* ## **为何要改造uCharts?**
* 并不是所有图表插件直接拿来就可以满足客户需求,如果您的UI设计师设计一个图表,如下图:
:-: 
* 您会发现这个图表即使在echarts里也不是很好实现,那么就需要我们自己动手去实现。下面就让我们一起来完成,本文旨在抛砖引玉,希望各位朋友能够更好的应用uCharts来完成您的项目。
* ## **题外篇:学习canvas画布的教程**
> [学习HTML5 Canvas这一篇文章就够了](https://blog.csdn.net/u012468376/article/details/73350998)
* 此教程仅针对HTML的canvas,仅供入门参考。uCharts中使用的canvas的API是遵循小程序中的API,个别方法与此不一样,例如uCharts中要用context.setLineWidth(1)来指定线宽,而HTML中是用context.lineWidth=1,uCharts为兼容H5做了如下方法的兼容:
```
this.context = document.getElementById(opts.canvasId).getContext("2d");
this.context.setStrokeStyle = function(e){ return this.strokeStyle=e; }
this.context.setLineWidth = function(e){ return this.lineWidth=e; }
this.context.setLineCap = function(e){ return this.lineCap=e; }
this.context.setFontSize = function(e){ return this.font=e+"px sans-serif"; }
this.context.setFillStyle = function(e){ return this.fillStyle=e; }
this.context.draw = function(){ }
```
* uCharts的画布API参考uniapp的画布API:
> [uniapp的画布API](https://uniapp.dcloud.io/api/canvas/CanvasContext)
* ## **uCharts程序结构介绍**
* 很多朋友刚接触uCharts的时候,对于文档API部分不是很理解,先说一下入口函数:
> var Charts = function Charts(opts)
* 当我们在vue页面调用uCharts的时候,也就是 let xxx = new uCharts({});的时候,我们传入uCharts的参数,就是opts这个对象。所以文档里都是以opts.开头的API参数。
* 这个入口函数主要对一些默认配置进行了初始化,改造过程中不涉及改造这里,仅需了解opts是代表您传入的参数即可,另外后续opts这个对象也会起很大作用,一些计算好的数据也会挂载到这里。
> function drawCharts(type, opts, config, context)
* `drawCharts`这个函数是主执行函数,所有的交互例如点击后出现toolTip、图例点击、拖拽滚动条等,都会调用此方法重新渲染图表。
* `type`是图表类型,`opts`是API参数,`config`是默认配置,`context`是画布的上下文。
> function draw...(xx,xx,xx)
* 凡是涉及到function draw...开头的函数,都是绘制图表的主方法,如果E文好的话,根据方法名就可以看出来是做什么用的,这里不一一介绍了。其他get...(),find...(),cal...()开头的函数,都是辅助计算类函数。
=================================================
* 说了一堆没用的,下面说正题:
* ## **图形分析**
* 首先,我们会发现这个图形包含两部分:
- 1外部的刻度与`仪表盘`的刻度类似,可以参考仪表盘的做法来改。
- 2外侧的进度条与`圆弧进度条`类似,把进度条部分复制过来,加到仪表盘里,剩下的就好办了。
* 这样,我们就需要把这两种图表进行一个结合,再绘制出其他辅助类的文字即可。
> function drawGaugeDataPoints(categories, series, opts, config, context)
> function drawArcbarDataPoints(series, opts, config, context)
* ## **仪表盘变量定义说明**
* 我们先来看drawGaugeDataPoints这个方法里头部的几个变量,简单介绍一下用途:
- var process:代表指针或者动画的进度,值的范围为[0-1],1为动画结束。
- var gaugeOption:这个继承了opts.extra.gauge的配置,便于后续读取opts中的扩展配置。
- categories:这个比较特殊,在仪表盘中用于定义刻度轴线的样式尺寸等配置。
- var centerPosition:顾名思义,这个是仪表盘的中心点。
- var radius:仪表盘半径,这里取了画布宽高的最小值作为基准依据。
- var innerRadius:仪表盘内部半径,根据外半径及刻度线宽度计算而来。
* ## **下面开始新增一个样式:**
- 我们通过opts.extra.gauge.type的值来传入一个新的样式,原来的样式为`default`,新样式定义为`progress`,这样,我们判断gaugeOption.type的字符串来确定绘制哪个图表样式。
- 我们把这个图分为五部分来画:
* ### 第一步画中心圆形背景和进度条背景:
```
//中心圆形背景
var pieRadius = radius - gaugeOption.width*3;
context.beginPath();
let gradient = context.createLinearGradient(centerPosition.x, centerPosition.y-pieRadius, centerPosition.x , centerPosition.y+pieRadius);
//配置渐变填充(起点:中心点向上减半径;结束点中心点向下加半径)
gradient.addColorStop('0', hexToRgb(series[0].color, 0.3));
gradient.addColorStop('1.0',hexToRgb("#FFFFFF", 0.1));
context.setFillStyle(gradient);
context.arc(centerPosition.x, centerPosition.y, pieRadius, 0, 2*Math.PI, false);
context.fill();
//画进度条背景
context.setLineWidth(gaugeOption.width);
context.setStrokeStyle(hexToRgb(series[0].color, 0.3));
context.setLineCap('round');
context.beginPath();
context.arc(centerPosition.x, centerPosition.y, innerRadius , gaugeOption.startAngle * Math.PI, gaugeOption.endAngle *Math.PI, false);
context.stroke();
```
* ### 第二步画刻度线:
```
totalAngle = gaugeOption.startAngle - gaugeOption.endAngle + 1;
let splitAngle = totalAngle / gaugeOption.splitLine.splitNumber;
let childAngle = totalAngle / gaugeOption.splitLine.splitNumber / gaugeOption.splitLine.childNumber;
let startX = -radius - gaugeOption.width * 0.5 - gaugeOption.splitLine.fixRadius;
let endX = -radius - gaugeOption.width - gaugeOption.splitLine.fixRadius + gaugeOption.splitLine.width;
context.save();
context.translate(centerPosition.x, centerPosition.y);
context.rotate((gaugeOption.startAngle - 1) * Math.PI);
let len = gaugeOption.splitLine.splitNumber * gaugeOption.splitLine.childNumber + 1;
let proc = series[0].data * process;
for (let i = 0; i < len; i++) {
context.beginPath();
//刻度线随进度变色
if(proc>(i/len)){
context.setStrokeStyle(hexToRgb(series[0].color, 1));
}else{
context.setStrokeStyle(hexToRgb(series[0].color, 0.3));
}
context.setLineWidth(3 * opts.pixelRatio);
context.moveTo(startX, 0);
context.lineTo(endX, 0);
context.stroke();
context.rotate(childAngle * Math.PI);
}
context.restore();
```
* ### 第三步画进度条:
```
series = getArcbarDataPoints(series, gaugeOption, process);
context.setLineWidth(gaugeOption.width);
context.setStrokeStyle(series[0].color);
context.setLineCap('round');
context.beginPath();
context.arc(centerPosition.x, centerPosition.y, innerRadius , gaugeOption.startAngle * Math.PI, series[0]._proportion_ *Math.PI, false);
context.stroke();
```
* ### 第四步画指针:
```
let pointerRadius = radius - gaugeOption.width*2.5;
context.save();
context.translate(centerPosition.x, centerPosition.y);
context.rotate((series[0]._proportion_ - 1) * Math.PI);
context.beginPath();
context.setLineWidth(gaugeOption.width/3);
let gradient3 = context.createLinearGradient(0, -pointerRadius*0.6, 0 , pointerRadius*0.6);
gradient3.addColorStop('0', hexToRgb('#FFFFFF', 0));
gradient3.addColorStop('0.5', hexToRgb(series[0].color, 1));
gradient3.addColorStop('1.0', hexToRgb('#FFFFFF', 0));
context.setStrokeStyle(gradient3);
context.arc(0, 0, pointerRadius , 0.85* Math.PI, 1.15 * Math.PI, false);
context.stroke();
context.beginPath();
context.setLineWidth(1);
context.setStrokeStyle(series[0].color);
context.setFillStyle(series[0].color);
context.moveTo(-pointerRadius-gaugeOption.width/3/2,-4);
context.lineTo(-pointerRadius-gaugeOption.width/3/2-4,0);
context.lineTo(-pointerRadius-gaugeOption.width/3/2,4);
context.lineTo(-pointerRadius-gaugeOption.width/3/2,-4);
context.stroke();
context.fill();
context.restore();
```
* ### 第五步画中间文字(调用圆环图的Title方法):
```
drawRingTitle(opts, config, context, centerPosition);
```
友情链接:[因卓诶-爱生活爱分享技术的博客](https://www.yinzhuoei.com)
- uCharts简介
- 图表预览
- 快速上手
- 常见问题
- API参数
- 通用基础配置项
- 数据列表配置项
- 标题配置项
- 坐标轴配置项
- 图例配置项
- 扩展配置项
- 圆弧进度图
- 仪表盘
- 雷达图
- 柱状图
- 饼图圆环图
- 玫瑰图
- 折线图
- 区域图
- K线图
- 词云图
- 漏斗图
- 地图
- 条状图
- 标记线
- ToolTip
- 其他配置
- 方法 & 事件
- 更新图表数据
- 图例点击交互
- 停止动画效果
- 添加事件监听
- 获取图表点击序列编号
- 获取图例点击序列编号
- ToolTip方法
- 图表拖拽事件
- 放大或缩小图表
- 图表渲染完成事件
- 入门配置示例
- 图表区域详解
- 绘制X坐标轴网格
- 绘制Y坐标轴网格
- 隐藏X轴(不含网格)
- 隐藏Y轴(不含网格)
- 启用X轴滚动条及拖拽
- 绘制Y轴标题
- 隐藏X轴下方图例
- 隐藏数据点标识
- 隐藏数据点标签
- 进阶配置示例
- ToolTip配置
- uni-app示例
- 饼图
- 饼图基本用法
- 饼图右侧图例
- 圆环图
- 圆环图基本用法
- 玫瑰图
- 玫瑰图基本用法
- 线图
- 线图基本用法
- 柱状图
- 基本柱状图
- 温度计式图表
- 堆叠柱状图
- 横屏模式
- 区域图
- 区域图基本用法
- 雷达图
- 雷达图基本用法
- 圆弧进度图
- 圆弧进度图基本用法
- 整圆进度图基本用法
- 仪表盘
- 仪表盘基本用法
- K线图
- K线图基本用法
- 条状图
- 条状图基本用法
- 混合图
- 混合图基本用法
- 词云图
- 词云图基本用法
- 漏斗图
- 漏斗图基本用法
- 地图
- 地图基本用法
- 更新记录
- 改造uCharts打造专属图表
- uni-app实战教程