萨摩亚乔 發表於 2019-9-5 18:48:00

uni-app 之canvas绘制饼状图

<p style="text-align: center"><span style="font-size: 18pt">uni-app 之canvas绘制饼状图</span></p>
<p>一开始,对于canvas我是拒绝的,后来,我发现我爱上了它,像爱上小哥哥一样~~</p>
<p>  说起canvas,是css3新增的标签。而饼状图又是canvas经典,我们公司现在正在用uni-app框架去研发APP,平常我们使用canvas标签时,只需在HTML中增加一个canvas标签,然后再script中获取标签属性,<span class="hljs-keyword">var canvas = <span class="hljs-built_in">document.getElementById(<span class="hljs-string">'cavsElem') 就可以了!但是,咱们也说了,使用uni-app,有过了解的人也知道,咱们uni-app是不支持document和window对象的,所以呢uni-app官网给我们提供了一个API --uni<span class="token punctuation">.<span class="token function">createCanvasContext,他会创建一个画布,你要定义他的宽高,给这个画布一个id,然后你就可以随心多欲了~~~</span></span><br></span></span></span></p>
<p><span class="hljs-keyword"><span class="hljs-built_in"><span class="hljs-string"><span class="token punctuation"><span class="token function">我们想要的图是这样的:</span></span></span></span></span></p>
<p><span class="hljs-keyword"><span class="hljs-built_in"><span class="hljs-string"><span class="token punctuation"><span class="token function"> <img src="https://img2018.cnblogs.com/blog/1664944/201909/1664944-20190903205225176-1657794519.png"> </span></span></span></span></span></p>
<p><span class="hljs-keyword"><span class="hljs-built_in"><span class="hljs-string"><span class="token punctuation"><span class="token function">我之前在调研这个canvas的时候,发现大家都做了那个就是解释说明,我就在延展的地方给大家写出来了,emmmmm,假如我有这么多钱,买了这么多化妆品~~</span></span></span></span></span></p>
<p><span class="hljs-keyword"><span class="hljs-built_in"><span class="hljs-string"><span class="token punctuation"><span class="token function">这个canvas把,我结合一下我当初调研的时候的感觉,就感觉还是给大家直接上代码比较好,解说什么的当时我都看不懂,我就一步一步的跟大家解释一下,让大家拿下他!!!像拿下心仪的小哥哥一样!!!加油,我们是最棒的!!(什么鬼~)</span></span></span></span></span></p>
<p><span class="hljs-keyword"><span class="hljs-built_in"><span class="hljs-string"><span class="token punctuation"><span class="token function">我们是在vue项目中写的 , 首先我先在一个vue组件中使用了canvas标签:</span></span></span></span></span></p>
<p><span class="hljs-keyword"><span class="hljs-built_in"><span class="hljs-string"><span class="token punctuation"><span class="token function">  定义canvas的大小宽高,给canvas定义一个id,在获取的时候能用到,我给了一个class样式,就是想让他居中的&nbsp; ,,可忽略</span></span></span></span></span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">&lt;canvas style="width: 350px; height: 300px;" canvas-id="homeownerCanvas" class="homeowner-canvas_charts"&gt;&lt;/canvas&gt;               
</pre>
</div>
<p>  其次我在js中定义了所需要展示的数据,类型,所占比例的:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">          let data = [{
                        "money": 30 + '万',
                        "value": 0.3,
                        "color": "#afb4db",
                        "title": "口红"
                },
                {
                        "money": 20 + '万',
                        "value": 0.2,
                        "color": "#ffce7b",
                        "title": "眼影"
                },
                {
                        "money": 30 + '万',
                        "value": 0.3,
                        "color": "#f8aba6",
                        "title": "粉底"
                },
                {
                        "money": 20 + '万',
                        "value": 0.2,
                        "color": "#afdfe4",
                        "title": "眉笔"
                }
                ];
</pre>
</div>
<p>  这个东西我就不详细解释了 ,他这个的意思就是说定义要显示的数据,比如你看到的金钱,颜色(我看别人家的颜色有的是生成的,我就直接定义了颜色,毕竟咱们主题不是他),比值(比值这个问题就是说你自己当前的这个金钱在你所有的金钱中所占的比例,说白了就是1/10 = 0.1的事情),还有他的title?&nbsp; &nbsp;就是他这个块是什么东西啦~~·</p>
<p>  然后就是在vue组件中引用关于canvas的js文件,现在vue组件中调用 :</p>
<p>     字段说明~参数一: canvasID&nbsp; &nbsp; 参数二:定义好的data&nbsp; &nbsp; &nbsp;参数三:总数(自己可以计算啦~我直接写死了)这个是便于以后有别的组件也会使用canvas这个js文件,所以把会使用到的数据当做参数传送过去</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">  canvas.canvasGraph('homeownerCanvas',data,100)
</pre>
</div>
<p>  接下来就是重头戏 :canvas这个js文件了!!</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 图表封装</span>
export <span style="color: rgba(0, 0, 255, 1)">default</span><span style="color: rgba(0, 0, 0, 1)">{
    canvasGraph(canvasID,data,summation){
      function PieChart(ctx,radius){
             </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义起始角度</span>
            let tempAngle=<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定圆心位置</span>
            let x0=<span style="color: rgba(128, 0, 128, 1)">182</span>,y0=<span style="color: rgba(128, 0, 128, 1)">150</span><span style="color: rgba(0, 0, 0, 1)">;<br>       <span style="color: rgba(51, 153, 102, 1)">//伸出长度</span>
            let outLine </span>= <span style="color: rgba(128, 0, 128, 1)">18</span><span style="color: rgba(0, 0, 0, 1)">;
            PieChart.prototype.init </span>=<span style="color: rgba(0, 0, 0, 1)"> function(data){
                </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.drawPie(data);
            };   
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 绘画扇形 及中心圆</span>
            PieChart.prototype.drawPie =<span style="color: rgba(0, 0, 0, 1)"> function(data){
                </span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = <span style="color: rgba(128, 0, 128, 1)">0</span>; i &lt; data.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 开始一个新路径</span>
<span style="color: rgba(0, 0, 0, 1)">                  ctx.beginPath();
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 移动到中心点</span>
<span style="color: rgba(0, 0, 0, 1)">                  ctx.moveTo(x0,y0);
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">计算当前扇形角度   所占比例*360</span>
                  let angle = data.value*<span style="color: rgba(128, 0, 128, 1)">360</span><span style="color: rgba(0, 0, 0, 1)">;
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">当前扇形起始绘制弧度   360 = 2π等于6.28</span>
                  let startAngle = tempAngle*Math.PI/<span style="color: rgba(128, 0, 128, 1)">180</span><span style="color: rgba(0, 0, 0, 1)">;
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">当前扇形借结束绘制弧度</span>
                  let endAngle = (tempAngle + angle)*Math.PI/<span style="color: rgba(128, 0, 128, 1)">180</span><span style="color: rgba(0, 0, 0, 1)">;
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">绘制扇形x y中心半径开始弧度结束弧度</span>
<span style="color: rgba(0, 0, 0, 1)">                  ctx.arc(x0,y0,radius,startAngle,endAngle);
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">填充扇形</span>
                  ctx.fillStyle =<span style="color: rgba(0, 0, 0, 1)"> data.color;
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 填充</span>
<span style="color: rgba(0, 0, 0, 1)">                  ctx.fill();
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 调用添加标题解释方法</span>
                  <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.drawTitle(startAngle,angle,data.color, data.title + data.money)
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">当前扇形结束绘制角度,即下一个扇形开始绘制角度</span>
                  tempAngle +=<span style="color: rgba(0, 0, 0, 1)"> angle;
                }
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 开始一个新路径</span>
<span style="color: rgba(0, 0, 0, 1)">                ctx.beginPath();
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 开始画圆</span>
                ctx.arc(x0, y0, <span style="color: rgba(128, 0, 128, 1)">65</span>, <span style="color: rgba(128, 0, 128, 1)">0</span>, <span style="color: rgba(128, 0, 128, 1)">2</span> *<span style="color: rgba(0, 0, 0, 1)"> Math.PI)
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 填充颜色 白色</span>
                ctx.setFillStyle(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">white</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 调用绘制中心圆文字方法</span>
                <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.drawCenterTitle()
            }
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 伸出线条方法</span>
            PieChart.prototype.drawTitle =<span style="color: rgba(0, 0, 0, 1)"> function(startAngle,angle,color,title){
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 伸出去的长度 斜边长度 等于半径加上定义好的长度</span>
                let <span style="color: rgba(0, 0, 255, 1)">out</span> =<span style="color: rgba(0, 0, 0, 1)"> radius;
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 当前弧度的二分之一</span>
                let du = startAngle+(angle/<span style="color: rgba(128, 0, 128, 1)">2</span>)*Math.PI/<span style="color: rgba(128, 0, 128, 1)">180</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算伸出的点x坐标</span>
                let outX = x0+<span style="color: rgba(0, 0, 255, 1)">out</span>*<span style="color: rgba(0, 0, 0, 1)">Math.cos(du);
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算伸出的点y坐标</span>
                let outY = y0+<span style="color: rgba(0, 0, 255, 1)">out</span>*<span style="color: rgba(0, 0, 0, 1)">Math.sin(du);
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 开始一个新路径</span>
<span style="color: rgba(0, 0, 0, 1)">                ctx.beginPath();
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 移动到中心点</span>
<span style="color: rgba(0, 0, 0, 1)">                ctx.moveTo(x0,y0);
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 画出点到伸出点的一条线</span>
<span style="color: rgba(0, 0, 0, 1)">                ctx.lineTo(outX,outY);
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 线条颜色</span>
                ctx.strokeStyle =<span style="color: rgba(0, 0, 0, 1)"> color;
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置标题</span>
                ctx.font = <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">bold 14px Microsoft Yahei</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算出标题文字宽度</span>
                let textWidth =<span style="color: rgba(0, 0, 0, 1)"> ctx.measureText(title).width;
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算标题样式</span>
                ctx.textBaseline = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">bottom</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 刷新配置项象限判断 与 对应符号</span>
                let optionArr=<span style="color: rgba(0, 0, 0, 1)">[
                  {
                        quadrant:outX</span>&gt;x0 &amp;&amp; outY&lt;<span style="color: rgba(0, 0, 0, 1)">y0,
                        symbol:[</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">+</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">-</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">left</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">]
                  },
                  {
                        quadrant:outX</span>&lt;x0 &amp;&amp; outY&lt;<span style="color: rgba(0, 0, 0, 1)">y0,
                        symbol:[</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">-</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">-</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">right</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">]
                  },
                  {
                        quadrant:outX</span>&lt;x0 &amp;&amp; outY&gt;<span style="color: rgba(0, 0, 0, 1)">y0,
                        symbol:[</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">-</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">+</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">right</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">]
                  },
                  {
                        quadrant:outX</span>&gt;x0 &amp;&amp; outY&gt;<span style="color: rgba(0, 0, 0, 1)">y0,
                        symbol:[</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">+</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">+</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">left</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">]
                  }
                ]
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 渲染的配置项</span>
                let {symbol} = optionArr.find(el=&gt;el.quadrant&amp;&amp;<span style="color: rgba(0, 0, 0, 1)">el.symbol)
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 斜线起始点</span>
                let slashState = eval(outX+symbol[<span style="color: rgba(128, 0, 128, 1)">0</span>]+<span style="color: rgba(0, 0, 0, 1)">outLine)
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 横线起始点</span>
                let lineState = eval(outX+symbol[<span style="color: rgba(128, 0, 128, 1)">0</span>]+textWidth+symbol[<span style="color: rgba(128, 0, 128, 1)">0</span>]+<span style="color: rgba(0, 0, 0, 1)">outLine)
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 终点</span>
                let lineEnd = eval(outY+symbol[<span style="color: rgba(128, 0, 128, 1)">1</span>]+<span style="color: rgba(0, 0, 0, 1)">outLine)
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 标题文字样式</span>
                ctx.textAlign = symbol[<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">];
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 画出伸出的斜线</span>
<span style="color: rgba(0, 0, 0, 1)">                ctx.lineTo(slashState,lineEnd);
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 接上斜线画出标题下面的直线</span>
<span style="color: rgba(0, 0, 0, 1)">                ctx.lineTo(lineState,lineEnd);
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 填充标题</span>
<span style="color: rgba(0, 0, 0, 1)">                ctx.fillText(title,slashState,lineEnd);
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 填充</span>
<span style="color: rgba(0, 0, 0, 1)">                ctx.stroke();
            }
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 绘制中心文字</span>
            PieChart.prototype.drawCenterTitle =<span style="color: rgba(0, 0, 0, 1)"> function(){
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 填充</span>
<span style="color: rgba(0, 0, 0, 1)">                ctx.fill();
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 文字大小</span>
                ctx.setFontSize(<span style="color: rgba(128, 0, 128, 1)">24</span><span style="color: rgba(0, 0, 0, 1)">)
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 文字颜色</span>
                ctx.fillStyle = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">#333333</span><span style="color: rgba(128, 0, 0, 1)">"</span>
                <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 文字位置</span>
                ctx.setTextAlign(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">center</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 插入文字</span>
                ctx.fillText(`${summation}万`, x0, y0+<span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">)
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 文字大小</span>
                ctx.setFontSize(<span style="color: rgba(128, 0, 128, 1)">14</span><span style="color: rgba(0, 0, 0, 1)">)
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 合计字体样式</span>
                ctx.font = <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">14px Microsoft Yahei</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 文字颜色</span>
                ctx.fillStyle = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">#999999</span><span style="color: rgba(128, 0, 0, 1)">"</span>
                <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 插入文字</span>
                ctx.fillText(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">合计(元)</span><span style="color: rgba(128, 0, 0, 1)">'</span>, x0, y0+<span style="color: rgba(128, 0, 128, 1)">30</span><span style="color: rgba(0, 0, 0, 1)">)
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 开始画图</span>
<span style="color: rgba(0, 0, 0, 1)">                ctx.draw()
            }
      }
      </span><span style="color: rgba(0, 0, 255, 1)">var</span> ctx =<span style="color: rgba(0, 0, 0, 1)"> uni.createCanvasContext(canvasID)
      </span><span style="color: rgba(0, 0, 255, 1)">var</span> PieChart = <span style="color: rgba(0, 0, 255, 1)">new</span> PieChart(ctx,<span style="color: rgba(128, 0, 128, 1)">90</span><span style="color: rgba(0, 0, 0, 1)">)
      PieChart.init(data)
    }
   
}</span></pre>
</div>
<p><strong><span style="font-size: 14pt">详细解析:</span></strong></p>
<p>  我使用了构造函数的原型添加方式</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">  //根据canvasID 获取当前传参的canvas信息<br>  //定义起始角度(决定你是从哪里开始画)
  let tempAngle=0;
  //定圆心位置
  let x0=100,y0=150;<br>  //定义伸出长度(指的是解释说明伸出的长度)
  let outLine = 18;<br>  
</pre>
</div>
<p>  使用的原型的方法:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">  PieChart.prototype.init = function(data){}   ------集合调用初始化函数创建对象后   参数为传参的data
  PieChart.prototype.drawPie = function(data){}   ------画饼状图的扇形和画白色小圆的方法
  PieChart.prototype.drawTitle = function(startAngle,angle,color,title){}-----画伸出的线条和文字
  PieChart.prototype.drawCenterTitle = function(){}   ---画白色圆上的文字
</pre>
</div>
<p>  来张图详细解析</p>
<p> <img src="https://img2018.cnblogs.com/blog/1664944/201909/1664944-20190904211140409-1106928552.png"></p>
<p>这样的解释可还ok?&nbsp; &nbsp;哈哈哈哈哈~~~~</p>
<p>&nbsp;接下来就是这个方法的分析</p>
<p>  主要呢就是这几个方法,不过呢,建议大家先去看一下这个canvas基本的方法什么的,要不然就会像我最开始接触的时候一团懵,不知道都是干啥的,大家可以先去了解一下方法都是什么意思,这样在捋的时候及不会乱了</p>
<p>   <span style="font-size: 18px"><strong>PieChart.prototype.drawPie = function(data){}&nbsp; &nbsp;绘画扇形与白色圆</strong></span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">PieChart.prototype.drawPie = function(data){
                for (let i = 0; i &lt; data.length; i++) {
                  // 开始一个新路径
                  ctx.beginPath();
                  // 移动到中心点
                  ctx.moveTo(x0,y0);
                  //计算当前扇形角度   所占比例*360
                  let angle = data.value*360;
                  //当前扇形起始绘制弧度   360 = 2π等于6.28
                  let startAngle = tempAngle*Math.PI/180;
                  //当前扇形借结束绘制弧度
                  let endAngle = (tempAngle + angle)*Math.PI/180;
                  //绘制扇形x y中心半径开始弧度结束弧度
                  ctx.arc(x0,y0,radius,startAngle,endAngle);
                  //填充扇形
                  ctx.fillStyle = data.color;
                  // 填充
                  ctx.fill();
                  // 调用添加标题解释方法
                  <span style="color: rgba(255, 0, 0, 1)">this.drawTitle(startAngle,angle,data.color, data.title + data.money)</span>
                  //当前扇形结束绘制角度,即下一个扇形开始绘制角度
                  tempAngle += angle;
                }
                // 开始一个新路径
                ctx.beginPath();
                // 开始画圆
                ctx.arc(x0, y0, 65, 0, 2 * Math.PI)
                // 填充颜色 白色
                ctx.setFillStyle('white')
                // 调用绘制中心圆文字方法
                <span style="color: rgba(255, 0, 0, 1)">this.drawCenterTitle()</span>
            }
</pre>
</div>
<p>  这里的知识点就是咱们关于弧度与角度之间的换算&nbsp;&nbsp;1弧度=180/π&nbsp; &nbsp;1度=π/180&nbsp; &nbsp; &nbsp; 方法主要是写了 根据传入data中value所代表的百分比计算出各自所占有的角度,在通过换算计算出所占弧度,先计算出开始弧度,再计算结束弧度,画出扇形,然后遍历data,画出各自的扇形,一定切记,<span style="color: rgba(51, 102, 255, 1)">当你要画一个新的扇形或者别的形状的时候,一定要开启一个新路径</span>,白色的小圆同样是这样,开启一个新路径然后用画圆的方法画个圆,另外在方法里面还调用了绘制标题的drawTitle()和绘制中心圆文字drawCenterTitle()方法</p>
<p>   <span style="font-size: 18px"><strong>PieChart.prototype.drawTitle = function(startAngle,angle,color,title){}&nbsp; &nbsp; &nbsp;@param&nbsp; {<strong>startAngle,angle,color,title}&nbsp; &nbsp;开始弧度 当前角度 颜色 标题</strong></strong></span></p>
<p>  自我感觉这是个重点! 我当初在调研,在看别人写的时候入了一个不小的坑&nbsp; ,后来仔细一算 发现他们写错了&nbsp; 我在这里给大家指正一下, 来张图片解释一下~~&nbsp; &nbsp;要是有看不懂的,欢迎大家提出来,我会给大家解释的,嗯嗯嗯(若是看不清楚请见上面详细代码)</p>
<p><img src="https://img2018.cnblogs.com/blog/1664944/201909/1664944-20190905190012421-1869497156.png"></p>
<p><strong><span style="font-size: 18pt">PieChart.prototype.drawCenterTitle = function(){} 绘制中心文字</span></strong></p>
<p>&nbsp;</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">PieChart.prototype.drawCenterTitle = function(){
                                // 填充
                                ctx.fill();
                                // 文字大小
                                ctx.setFontSize(24)
                                // 文字颜色
                                ctx.fillStyle = "#333333"
                                // 文字位置
                                ctx.setTextAlign('center')
                                // 插入文字
                                ctx.fillText(`${summation}万`, x0, y0+5)
                                // 文字大小
                                ctx.setFontSize(14)
                                // 合计字体样式
                                ctx.font = '14px Microsoft Yahei';
                                // 文字颜色
                                ctx.fillStyle = "#999999"
                                // 插入文字
                                ctx.fillText('合计(元)', x0, y0+30)
                                // 开始画图
                                ctx.draw()
                        }
</pre>
</div>
<p>  具体方法就是这样了,如果你们有什么不会的或者还没有懂得,欢迎留言,或者你们想要什么效果的,都可以留言,大家一起交流,一起拿下“小哥哥”!!!</p>
<p><span style="font-size: 14pt"><strong>更正:</strong></span>由于当时的考虑不周的原因,发现当如果在你的data中有比例为零时,会不显示canvas图表,会报出一个'symbol is not defined' 的问题,后来寻找了一下错误点,发现了自己在象限的判断中考虑的并不周到,没有考虑到0的原因 ,故象限判断做出如下更改,其他不变:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// 象限判断
let optionArr=[
  {
        quadrant:outX&gt;=x0 &amp;&amp; outY&lt;=y0,
        symbol:['+','-','left']
    },
    {
        quadrant:outX&lt;x0 &amp;&amp; outY&lt;=y0,
        symbol:['-','-','right']
    },
    {
        quadrant:outX&lt;x0 &amp;&amp; outY&gt;y0,
        symbol:['-','+','right']
    },
    {
        quadrant:outX&gt;=x0 &amp;&amp; outY&gt;y0,
        symbol:['+','+','left']
    }
]
</pre>
</div>
<p> <span style="font-size: 14pt"><strong>注意:</strong></span>另外之前有人扣扣私聊我说他按照我这个代码写的,但是并没有显示图表,后来他把代码发给我,我发现他把canvas画图方法放在了onLoad上,后来给他放到onReady就显示了,在这里我讲一下为什么、</p>
<p>  &nbsp; &nbsp; &nbsp;onReady要比onLoad先执行,onLoad必须等到页面内包括图片的所有元素加载完毕之后才能执行,而onReady不需要,canvas说白了就是一张画布,所以在onLoad执行时不会显示的,因为当时的画布并没有加载完成</p>
<p>  </p><br><br>
来源:https://www.cnblogs.com/gongliying/p/11461508.html
頁: [1]
查看完整版本: uni-app 之canvas绘制饼状图