ReactNative 手绘环形统计图
一、效果图

二、绘图使用了RN中的ART ,
对于每段的计算需要注意
1.角度计算应该转换为弧度,转换公式如下:
/*** 角度转弧度* @param angle* @returns {number}*/degress2Radians(angle){return angle / 180.0 * 3.1415926;};
2.当前段的起始角度应该等于上一段的终端角度,对于第一段通常用0作为起始角度
这里直接给出起始角度的计算公式,假设数据是用数组传进来的
var stratAngle = 0;var endAngle = 0;if (i === 0) {stratAngle = 0;} else {for (let j = 0; j < i; j++) {stratAngle += itemArray[j].degress; //前面的角度累加}}for (let j = 0; j <= i; j++) { //前面的角度累加endAngle += itemArray[j].degress;}return ( );})}
三、全部源码:
import React, {Component,
} from 'react';
import {View,ART,} from 'react-native';import Wedge from './Wedge';
import PropTypes from 'prop-types';const {Surface, Shape, Path} = ART;/*** Created by 刘胡来* Date on 2019.04.26* Copyright 2013 - 2019 QianTuo Inc. All Rights Reserved* Desc:环形统计图*/
export default class CircularChart extends Component {static propTypes = {itemArray: PropTypes.array,chartWidth: PropTypes.number,chartHeight: PropTypes.number,outerRadius: PropTypes.number,innerRadius: PropTypes.number,}constructor(props) {super(props);};render() {let {chartWidth, chartHeight, outerRadius,innerRadius,itemArray}=this.props;return ({flex: 1, backgroundColor: '#F5F5F9'}}>{backgroundColor: 'yellow', marginTop: 10}}>{itemArray.map((name, i) => {var stratAngle = 0;var endAngle = 0;if (i === 0) {stratAngle = 0;} else {for (let j = 0; j < i; j++) {stratAngle += itemArray[j].degress;}}for (let j = 0; j <= i; j++) {endAngle += itemArray[j].degress;}return ( );})} )};/*** 角度转弧度* @param angle* @returns {number}*/degress2Radians(angle){return angle / 180.0 * 3.1415926;};}
四、Wedge的源码,是来源于网络,找不到网址了,大兄弟这里暂时借用你的,
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 .*/
export default class Wedge extends Component {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 radiansconst sa = this._degreesToRadians(startAngle);const ea = this._degreesToRadians(endAngle);// central arc angle in radiansconst ca = sa > ea ? (this:any).circleRadians - sa + ea : ea - sa;// cached sine and cosine valuesconst ss = Math.sin(sa);const es = Math.sin(ea);const sc = Math.cos(sa);const ec = Math.cos(ea);// cached differencesconst 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 wedgeif (ir) {path.counterArc(ir * -ds, ir * dc, ir, ir, large); // inner arc}return path;}render() : any {// angles are provided in degreesconst startAngle = this.props.startAngle;const endAngle = this.props.endAngle;// if (startAngle - endAngle === 0) {// return null;// }// radii are provided in pixelsconst innerRadius = this.props.innerRadius || 0;const outerRadius = this.props.outerRadius;const { originX, originY } = this.props;// sorted radiiconst 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 ;}
}
Wedge.propTypes = {outerRadius: PropTypes.number.isRequired, // 圆弧半径startAngle: PropTypes.number.isRequired, // 开始角度endAngle: PropTypes.number.isRequired, // 结束角度originX: PropTypes.number, // 左边的距离 不是圆心的XoriginY: PropTypes.number, // 上部的距离 不是圆心的YinnerRadius: PropTypes.number, //内部半径 用户画弧
}
Wedge.defaultProps = {originX: 0,originY: 0,
}
五、使用方式:
import React from "react";
import {Button, View, Text, StyleSheet,Dimensions,Image,TextInput,ListView,Alert,Animated,ART,Easing,StatusBar,NativeModules,TouchableOpacity} from 'react-native';
import BaseComponent from "../BaseComponent";
import Wedge from '../../uikit/art/Wedge';
import CircularChart from '../../uikit/art/CircularChart';const {Surface, Shape, Path} = ART;/*** Created by 刘胡来* Date on 2019.04.25* Copyright 2013 - 2019 QianTuo Inc. All Rights Reserved* Desc: 交易查询*/
export default class TradeQuery extends BaseComponent{constructor(props){super(props);this.testArray = [];this.colors = ["yellow",'gray','green'];this.total = 0;// for(let i = 1; i <= 3; i ++){// var item = new CircleItem();// item.ratio = i * 100;// this.total += i * 100;// item.color = this.colors[i];// this.testArray.push(item);// }////// for(let i = 0; i < this.testArray.length; i ++){// var item = this.testArray[i];// let ratio = item.ratio;// item.ratio = ratio / this.total;// item.degress = item.ratio * 360.0;//// }var item1 = new CircleItem();item1.ratio = 100;item1.degress = 100.0 / 600.0 * 360.0;item1.color = 'purple';this.testArray.push(item1);var item2 = new CircleItem();item2.ratio = 200;item2.degress = 200.0 / 600.0 * 360.0;item2.color = 'green';this.testArray.push(item2);var item3 = new CircleItem();item3.ratio = 200;item3.degress = 200.0 / 600.0 * 360.0;item3.color = 'gray';this.testArray.push(item3);var item4 = new CircleItem();item4.ratio = 100;item4.degress = 100.0 / 600.0 * 360.0;item4.color = 'white';this.testArray.push(item4);};render(){return({flex:1,backgroundColor:'#F5F5F9'}}>{this.setStatusBar('#1373EC')}{this.buildTopNavigationBar('交易查询','#1373EC')}{this.buildCircleChart()}{/*{backgroundColor: 'yellow', marginTop: 10}}>*/}{/* */}{/*/!* *!/*/}{/* */}{/* */}{/*{ this.testArray.map((name, i) => {*/}{/*var posx = 0;*/}{/*var endAngle = 0;*/}{/*if(i === 0){*/}{/*posx = 0;*/}{/*}else{*/}{/*for(let j = 0 ; j */}{/*);*/}{/*})}*/}{/* */} )}buildCircleChart(){let tabParams = {itemArray:this.testArray,chartWidth: 300,chartHeight: 300,outerRadius: 100,innerRadius: 80,};return ( );};/*** 角度转弧度* @param angle* @returns {number}*/degress2Radians(angle){return angle / 180.0 * 3.1415926;};/*** 值转角度* @param value* @returns {number}*/value2Degress(value){return value / 360.0;};}class CircleItem {constructor(){this.ratio = 0;this.color = '#339900';this.degress = 0;}}
``
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
