您的当前位置:首页React-Native ART绘图

React-Native ART绘图

2024-12-14 来源:哗拓教育
  • 绘制 直线
  • 绘制 虚线
  • 绘制 矩形
  • 绘制 三角形
  • 绘制 多边形
  • 绘制 多边线
  • 绘制 圆形
  • 绘制 半圆
  • 绘制 扇形
  • 绘制 圆环
  • 绘制 渐变色
  • 图片填充绘制的形状(Pattern)

props

Pattern
  • 使用图片填充
Surface
  • width : 渲染区域的宽
  • height : 定义渲染区域的高
Shape
  • d : 定义绘制路径 (Path对象)
  • stroke : 描边颜色
  • strokeWidth : 描边宽度
  • strokeDash : 定义虚线
  • fill : 填充颜色
Path
  • moveTo(x,y) : 移动到坐标(x,y),设置初始点

  • lineTo(x,y) : 连线到(x,y)
    Path().moveTo(20, 20).lineTo(10, 20) 得到的是一条(20, 20) 到(10, 20) 的线。

    image.png
  • line(x,y): 相对于原来的偏移
    Path().moveTo(20, 20).line(10, 20) 得到的是一条(20, 20) 到(30, 40) 的线。

    image.png
  • arc() : 绘制弧线
    Path().moveTo(150,50).arc(50, 100,50) 绘制一半圆弧(150,50)起点,(50, 100)偏移量(终点) 50 半径

    image.png

Path().arc(30, 50, 70, 90, true, false, 1) 画一段圆弧(30, 50)起点,(70, 90)控制点 (true, false, 1)不知/逆时针/不知,另个一圆弧的点在视图的边缘

image.png
  • close() : 封闭空间

使用

import {
    ART
} from 'react-native';
var {
    Surface, //  一个矩形可渲染的区域,是其他元素的容器
    Group, // 可容纳多个形状、文本和其他的分组
    Shape, // 形状定义,可填充
    Path, // 路径
    LinearGradient, // 渐变色
    Pattern, // 填充图片
    ClippingRectangle, // 剪辑
} = ART;
  • 直接使用SVG
    .svg 路径的文件用浏览器打开,一片空白是正常的,右键查看网页源代码,找到path字段
var HEART_SVG = "M130.4-0.8c25.4 0 46 20.6 46 46.1 0 13.1-5.5 24.9-14.2 33.3L88 153.6 12.5 77.3c-7.9-8.3-12.8-19.6-12.8-31.9 0-25.5 20.6-46.1 46-46.2 19.1 0 35.5 11.7 42.4 28.4C94.9 11 111.3-0.8 130.4-0.8"
<Surface width={300} height={300} style={{backgroundColor: 'yellow', marginTop: 10}}>
  <Shape d={HEART_SVG} stroke="#000000" strokeWidth={1} fill={'#892265'}/>
</Surface>
svg代码
  • 绘制 直线
{/*绘制 直线*/}
let zhixian_path = Path()
            .moveTo(0,5) // 改变起点为 0,5 。默认为0,0
            .lineTo(300,5) // 目标点

<Surface width={300} height={10} style={{backgroundColor: 'yellow', marginTop: 10}}>
    <Shape d={zhixian_path} stroke="#000000" strokeWidth={1} />
</Surface>
黄色中间的直线
  • 绘制 虚线
{/*绘制 虚线*/}
let xuxian_path = Path()
            .moveTo(0,5) // 改变起点为 0,5 。默认为0,0
            .lineTo(300,5) // 目标点

let xuxian_path1 = Path()
            .moveTo(0,15) // 改变起点为 0,15 。默认为0,0
            .lineTo(300,15) // 目标点
                
<Surface width={300} height={20} style={{backgroundColor: 'yellow', marginTop: 10}}>
 <Group>
    {/*strokeDash={[5,20]  先是5像素的实线,再是20像素的空白,再是5像素的实线... 循环*/}
    <Shape d={xuxian_path} stroke="#000000" strokeWidth={2} strokeDash={[5,20,]}/>

    {/*strokeDash={[10,5,20,5]  先是10像素的实线,再是5像素的空白,再是20像素的实线, 再是5像素的空白... 循环*/}
    <Shape d={xuxian_path1} stroke="#000000" strokeWidth={2} strokeDash={[10,5,20,5]}/>
  </Group>
</Surface>
黄色中间两条虚线
  • 绘制 矩形
let juxing_path = Path()
            .moveTo(5,5)
            .lineTo(295,5)
            .lineTo(295,25)
            .lineTo(5,25)
            .close() // close 封闭

{/*绘制 矩形*/}
<Surface width={300} height={30} style={{backgroundColor: 'yellow', marginTop: 10}}>
  <Shape d={juxing_path} stroke="#000000" strokeWidth={1} fill="#892265"/>
</Surface>
黄色中间矩形
  • 绘制 三角形
let sanjiaoxing_path = Path()
            .moveTo(100,5)
            .lineTo(200, 25)
            .lineTo(30,10)
            .close()

{/*绘制 三角形*/}
<Surface width={300} height={30} style={{backgroundColor: 'yellow', marginTop: 10}}>
  <Shape d={sanjiaoxing_path} stroke="#000000" strokeWidth={1} fill="#892265"/>
</Surface>
黄色中间三角形
  • 绘制 多边形
 let duobianxing_path = Path()
            .moveTo(50, 10)
            .lineTo(80, 0)
            .lineTo(120, 60)
            .lineTo(60, 90)
            .lineTo(10, 30)
            .lineTo(80, 70)
            .close()
{/*绘制 多边形*/}
<Surface width={300} height={200} style={{backgroundColor: 'yellow', marginTop: 10}}>
  <Shape d={duobianxing_path} stroke="#000000" strokeWidth={1} fill="#892265"/>
</Surface>

黄色内部
  • 绘制 多边线
 let duobianxian_path = Path()
            .moveTo(50, 10)
            .lineTo(80, 0)
            .lineTo(120, 60)
            .lineTo(60, 90)
            .lineTo(10, 30)
            .lineTo(80, 70)
            .close()
{/*绘制 多边线*/}
<Surface width={300} height={200} style={{backgroundColor: 'yellow', marginTop: 10}}>
  <Shape d={duobianxian_path} stroke="#000000" strokeWidth={1} />
</Surface>

黄色内部
  • 绘制 圆形、半圆
// 正常情况下  arc()只用来画圆,想要花圆弧使用...

// 实际是由两条 圆弧 构成了一个圆(左右两半拼成一个圆)
let yuanxing_path = Path()
    .moveTo(50, 0)// 起点位置
    .arc(0,100,50) // 将 (50,0) 看成新的坐标系(0,0),由此进行 顺时针(100正) 的画半弧。
    .arc(0,-100,50) // 将 (0,100) 看成新的坐标系(0,0),由此进行 逆时针(-100负) 的画半弧。
    .close() // arc第一个参数为 0 是因为 终点的x和原点在一条直线上,确保画的是半圆弧

 // arc 第一个参数不为0 的情况
let yuanxing_path2 = Path()
    .moveTo(150,50)
    .arc(50, 100,50) // 给定了终点的坐标,即可自动算出半径,第三个参数 的范围预估 不可大于 真正的半径 不可小于1
    .close()

let yuanxing_path3 = Path()
    .moveTo(100,120)
    .arc(-50, 100,50) // 给定了终点的坐标,即可自动算出半径,第三个参数 的范围预估 不可大于 真正的半径 不可小于1
    .close()

 let yuanxing_path4 = Path().moveTo(50, 5)// 起点位置
    .arc(0, 100, 50) // 将起点位置看成新的坐标系,(50, 5)为新的原点(0,0)。100为正值,顺时针方向画半圆,50 为半径,100为终点坐标
    .arc(0, 80, 40) // 将(0,100)看成新的坐标系(0,0),80为正值,顺时针方向画半圆,40 为半径,80为终点坐标
    .arc(0, 60, 30) // 将(0, 80)看成新的坐标系(0,0),60为正值,顺时针方向画半圆,30 为半径,60为终点坐标
    .arc(0, -20, 10) // 将(0, 60)看成新的坐标系(0,0),20为负值,逆时针方向画半圆,10 为半径,-20为终点坐标
    .close();

{/*绘制 圆形*/}
<Surface width={300} height={250} style={{backgroundColor: 'yellow', marginTop: 10}}>
  <Group>
    <Shape d={yuanxing_path} stroke="#000000" strokeWidth={1} fill="#892265"/>
    <Shape d={yuanxing_path2} stroke="#000000" strokeWidth={1} fill="#892265"/>
    <Shape d={yuanxing_path3} stroke="#000000" strokeWidth={1} fill="#892265"/>
  </Group>
</Surface>
<Surface width={300} height={300} style={{backgroundColor: 'yellow', marginTop: 10}}>
  <Shape d={yuanxing_path4} stroke="#000000" strokeWidth={1} fill="#892265"/>
</Surface>

黄色内部
  • 扇形、圆环

需要一个绘制类

import React, { Component } from 'react';
import { ART } from 'react-native';
const { Shape, Path } = ART;
import PropTypes from 'prop-types'
/**
 * Wedge is a React component for drawing circles, wedges and arcs. Like other
 * ReactART components, it must be used in a <Surface>.
 */
export default class Wedge extends Component<void, any, any> {

    constructor(props : any) {
        super(props);
        (this:any).circleRadians = Math.PI * 2;
        (this:any).radiansPerDegree = Math.PI / 180;
        (this:any)._degreesToRadians = this._degreesToRadians.bind(this);
    }

    /**
     * _degreesToRadians(degrees)
     *
     * Helper function to convert degrees to radians
     *
     * @param {number} degrees
     * @return {number}
     */
    _degreesToRadians(degrees : number) : number {
        if (degrees !== 0 && degrees % 360 === 0) { // 360, 720, etc.
            return (this:any).circleRadians;
        }
        return degrees * (this:any).radiansPerDegree % (this:any).circleRadians;
    }

    /**
     * _createCirclePath(or, ir)
     *
     * Creates the ReactART Path for a complete circle.
     *
     * @param {number} or The outer radius of the circle
     * @param {number} ir The inner radius, greater than zero for a ring
     * @return {object}
     */
    _createCirclePath(originX : number, originY : number, or : number, ir : number) : Path {
        const path = new Path();

        path.move(originX, or + originY)
            .arc(or * 2, 0, or)
            .arc(-or * 2, 0, or);

        if (ir) {
            path.move(or - ir, 0)
                .counterArc(ir * 2, 0, ir)
                .counterArc(-ir * 2, 0, ir);
        }

        path.close();

        return path;
    }

    /**
     * _createArcPath(sa, ea, ca, or, ir)
     *
     * Creates the ReactART Path for an arc or wedge.
     *
     * @param {number} startAngle The starting degrees relative to 12 o'clock
     * @param {number} endAngle The ending degrees relative to 12 o'clock
     * @param {number} or The outer radius in pixels
     * @param {number} ir The inner radius in pixels, greater than zero for an arc
     * @return {object}
     */
    _createArcPath(originX : number, originY : number, startAngle : number, endAngle : number, or : number, ir : number) : Path {
        const path = new Path();

        // angles in radians
        const sa = this._degreesToRadians(startAngle);
        const ea = this._degreesToRadians(endAngle);

        // central arc angle in radians
        const ca = sa > ea ? (this:any).circleRadians - sa + ea : ea - sa;

        // cached sine and cosine values
        const ss = Math.sin(sa);
        const es = Math.sin(ea);
        const sc = Math.cos(sa);
        const ec = Math.cos(ea);

        // cached differences
        const ds = es - ss;
        const dc = ec - sc;
        const dr = ir - or;

        // if the angle is over pi radians (180 degrees)
        // we will need to let the drawing method know.
        const large = ca > Math.PI;

        // TODO (sema) Please improve theses comments to make the math
        // more understandable.
        //
        // Formula for a point on a circle at a specific angle with a center
        // at (0, 0):
        // x = radius * Math.sin(radians)
        // y = radius * Math.cos(radians)
        //
        // For our starting point, we offset the formula using the outer
        // radius because our origin is at (top, left).
        // In typical web layout fashion, we are drawing in quadrant IV
        // (a.k.a. Southeast) where x is positive and y is negative.
        //
        // The arguments for path.arc and path.counterArc used below are:
        // (endX, endY, radiusX, radiusY, largeAngle)

        path.move(originX, originY) // move to starting point
            .arc(or * ds, or * -dc, or, or, large) // outer arc
            .line(dr * es, dr * -ec);  // width of arc or wedge

        if (ir) {
            path.counterArc(ir * -ds, ir * dc, ir, ir, large); // inner arc
        }

        return path;
    }

    render() : any {
        // angles are provided in degrees
        const startAngle = this.props.startAngle;
        const endAngle = this.props.endAngle;
        // if (startAngle - endAngle === 0) {
        // return null;
        // }

        // radii are provided in pixels
        const innerRadius = this.props.innerRadius || 0;
        const outerRadius = this.props.outerRadius;

        const { originX, originY } = this.props;

        // sorted radii
        const ir = Math.min(innerRadius, outerRadius);
        const or = Math.max(innerRadius, outerRadius);

        let path;
        if (endAngle >= startAngle + 360) {
            path = this._createCirclePath(originX, originY, or, ir);
        } else {
            path = this._createArcPath(originX, originY, startAngle, endAngle, or, ir);
        }

        return <Shape {...this.props} d={path} />;
    }
}
Wedge.propTypes = {
    outerRadius: PropTypes.number.isRequired, // 圆弧半径
    startAngle: PropTypes.number.isRequired, // 开始角度
    endAngle: PropTypes.number.isRequired, // 结束角度
    originX: PropTypes.number, // 左边的距离 不是圆心的X
    originY: PropTypes.number, // 上部的距离 不是圆心的Y
    innerRadius: PropTypes.number, //内部半径 用户画弧
}
Wedge.defaultProps = {
    originX: 0,
    originY: 0,
}

使用

 <Surface width={300} height={400} style={{backgroundColor: 'yellow', marginTop: 10}}>
  <Wedge
        outerRadius={100}
        startAngle={0}
        endAngle={160}
        originX={80}
        originY={50}
        fill="blue" />
</Surface>

<Surface width={300} height={300} style={{backgroundColor: 'yellow', marginTop: 10}}>
  <Wedge
        outerRadius={100}
        innerRadius={90}
        startAngle={0}
        endAngle={40}
        originX={80}
        originY={50}
        fill="purple" />
</Surface>
黄色内部
  • 渐变色
        // .5 颜色占比表示 50%,  那个颜色的占比大,在前;颜色比小,在后。不能大于1
        // 同样的占比,后面的会把前面的替换掉
        // 必须是 Int 类型, 不可以是float或其他

        // x1,y1,x2,y2   x1,y1颜色的起点;x2,y2颜色的终点
        // "0", "0", "300", "0"    300为组件的宽度、弧度的长度   此:表示 横向颜色渐变
        // "0", "0", "0", "40"     40为组件的高度、弧度的高度   此:表示 纵向颜色渐变
        // "0", "0", "300", "100"  300、100 渐变是横向 ///(渐变样式犹如斜杠) 渐变

        var linearGradient = new LinearGradient({
                '.4': 'green',
                '.6': 'blue',
            },
            "0", "0", "300", "100"
        );

<Surface width={300} height={300} style={{backgroundColor: 'yellow', marginTop: 10}}>
  <Wedge
        outerRadius={100}
        innerRadius={90}
        startAngle={0}
        endAngle={100}
        originX={80}
        originY={50}
        fill={linearGradient}/>
</Surface>

 <Surface width={300} height={100} style={{backgroundColor: 'yellow', marginTop: 10}}>
  <Shape d={juxing_jianbian_path} stroke="#000000" strokeWidth={1} fill={linearGradient}/>
</Surface>
image.png
  • 图片填充绘制的形状(Pattern)
    (resolveAssetSource(本地图片) 得到本地图片的url
let url = resolveAssetSource(require('./image.png'))
image.png
import resolveAssetSource from 'resolveAssetSource'
const pattern = new Pattern(resolveAssetSource(pengyouImage),90,90,5,5)
<Surface width={300} height={100} style={{backgroundColor: 'yellow', marginTop: 10}}>
  <Shape d={juxing_jianbian_path} stroke="#000000" strokeWidth={1} fill={pattern}/>
</Surface>
image.png
<Surface width={300} height={200} style={{backgroundColor: 'yellow', marginTop: 10}}>
  <ClippingRectangle
        width={ 100 } //要剪辑的宽
        height={ 50 } //要剪辑的高
        x={ 40 } //要剪辑的left
        y={ 0 }> //要剪辑的top
    <Shape d={ new Path().moveTo(20,20).lineTo(100,20) } stroke="black" strokeWidth={50}/>
  </ClippingRectangle>
  <Shape d={ new Path().moveTo(20, 100).lineTo(100,100) } stroke="black" strokeWidth={50}/>
</Surface>
image.png
显示全文