zl程序教程

您现在的位置是:首页 >  前端

当前栏目

纯HTML5 Canvas实现的饼图详解编程语言

html5编程语言 实现 详解 Canvas
2023-06-13 09:20:28 时间

基本思路:

主要是利用HTML5 Canvas实现饼图绘制,绘制弧度的API主要是使用

context.arc与lineto两个API。

实现的功能有:

1. 支持标签Legend显示或者隐藏

2. 首次载入动画效果

3. 鼠标tooltip效果

4. 自定义饼图大小与是否添加文字

效果如下:

纯HTML5 Canvas实现的饼图详解编程语言

调用代码:

 html 

 head 

 meta http-equiv="X-UA-Compatible" content="chrome=IE8" 

 script src="js/fishcomponent.js" /script 

 script src="js/pie.js" /script 

 title My Demo 1 /title 

 script 

 window.onload = function() { 

 var canvas = document.getElementById("pie_canvas"); 

 var seriesData = [{name:"apples", value:150, color:"RGBA(255,0,0,1)"}, 

 {name:"orange", value:100, color:"RGBA(255,255,0,1)"}, 

 {name:"banana", value:80, color:"RGBA(255,0,255,1)"}, 

 {name:"peaches", value:60, color:"RGBA(0,255,255,1)"}, 

 {name:"strawberries", value:40, color:"RGBA(0,127,255,1)"}] 

 var config = { 

 width : 600, 

 height: 400, 

 series: seriesData, 

 canvas: canvas, 

 unit: "kg", 

 title:"Fruit Sales", 

 tooltips : { 

 enable : true 

 animation :{ 

 enable: true 

 legend : { 

 enable : true 

 text : { 

 enable: true 

 pieChart.initSettings(config); 

 pieChart.render(); 

 /script 

 /head 

 body 

 h1 Pie Chart Demo /h1 

 div id="my_container" 

 canvas id="pie_canvas" /canvas 

 /div 

 div id="btn-group" 

 button type="button" id="clear-button" Clear Plot /button 

 button type="button" id="refresh-button" Draw Plot /button 

 /div 

 /body 

 /html 

饼图JS的代码:

var pieChart = { 

 width: 600, 

 height: 400, 

 series: [], 

 unit: "kg", 

 chartCanvas: null, 

 selectable : true, 

 title: "Pie Chart", 

 legend : { 

 enable : true 

 edge : { 

 width: 50, 

 height: 50 

 animation: { 

 enable: true, 

 animCanvas : null, 

 hh: 1, // trick is here!! for animation play 

 pctx: null 

 tooltips: { 

 enable: true, 

 tooltipCanvas : null, 

 ttContext: null, 

 index: -1 

 circle : { 

 cx: 0, 

 cy: 0, 

 radius: 0 

 text : { 

 enable: false, 

 content:[] 

 initSettings: function (config) { 

 this.chartCanvas = config.canvas; 

 this.chartCanvas.width = config.width; 

 this.chartCanvas.height = config.height; 

 this.width = config.width; 

 this.height = config.height; 

 this.series = config.series; 

 this.title = config.title; 

 this.unit = config.unit; 

 if(config.tooltips != undefined) { 

 this.tooltips.enable = config.tooltips.enable; 

 if(config.animation != undefined) { 

 this.animation.enable = config.animation.enable; 

 if(config.legend != undefined) { 

 this.legend.enable = config.legend.enable; 

 if(config.text != undefined) { 

 this.text.enable = config.text.enable; 

 render : function() { 

 // initialization circle 

 this.circle.cx = this.width/2; 

 this.circle.cy = this.height/2; 

 this.circle.radius = Math.min(this.width/2, this.height/2) - Math.max(this.edge.width, this.edge.height); 

 var ctx = null; 

 if(this.animation.enable) { 

 this.animation.animCanvas = document.createElement("canvas"); 

 this.animation.animCanvas.width = this.width; 

 this.animation.animCanvas.height = this.height; 

 ctx = this.animation.animCanvas.getContext("2d"); 

 } else { 

 ctx = this.chartCanvas.getContext("2d"); 

 this.renderBorder(ctx); 

 if(this.circle.radius = 0) { 

 ctx.strokeText("Can not reader the chart, Circle is too small."); 

 return; 

 // draw each arc according to data series 

 var sum = 0; 

 var nums = this.series.length; 

 for(var i=0; i nums; i++) { 

 sum += this.series[i].value; 

 // draw title 

 ctx.font = 18pt Calibri; 

 ctx.fillText(this.title, this.width/2 - this.edge.width, 30); 

 ctx.save(); 

 var deltaArc = 0; 

 for(var i=0; i nums; i++) { 

 var precent = this.series[i].value/sum; 

 this.renderPie(ctx, i, precent, deltaArc); 

 deltaArc += 2*Math.PI * precent; 

 ctx.restore(); 

 // add blur shadow 

 ctx.save(); 

 ctx.shadowColor = "black"; 

 ctx.shadowOffsetX = 0; 

 ctx.shadowOffsetY = 0; 

 ctx.shadowBlur = 10; 

 ctx.beginPath(); 

 ctx.arc(this.circle.cx, this.circle.cy, this.circle.radius, 0, Math.PI * 2, false); 

 ctx.closePath(); 

 ctx.lineWidth = 1; 

 ctx.strokeStyle = "RGBA(127,127,127,1)"; 

 ctx.stroke(); 

 ctx.restore(); 

 // render legend 

 ctx.save(); 

 this.renderLegend(ctx, sum); 

 ctx.restore(); 

 // play animation 

 if(this.animation.enable) { 

 var parent = this; 

 this.animation.pctx = this.chartCanvas.getContext("2d"); 

 this.renderBorder(this.animation.pctx); 

 setTimeout(function() {parent.playAnimation(parent);}, 1000/20); 

 showTooltips : function(loc, ctx) { 

 if(!this.tooltips.enable) { 

 return; 

 var dx = loc.x - this.width/2; 

 var dy = loc.y - this.height/2; 

 var dis = Math.floor(Math.sqrt(dx * dx + dy * dy)); 

 if(dis = this.circle.radius) { 

 // draw tool tip text 

 var angle = Math.atan2(dy,dx); 

 if(angle = 0) { 

 // if[-Math.PI, 0], make it[Math.PI, 2*Math.PI] 

 angle = angle + 2*Math.PI; 

 var sum = 0; 

 var nums = this.series.length; 

 for(var s=0; s nums; s++) { 

 sum += this.series[s].value; 

 var deltaArc = 0; 

 var index = 0; 

 for(var i=0; i nums; i++) { 

 var precent = this.series[i].value/sum; 

 deltaArc += 2*Math.PI * precent; 

 if(angle =deltaArc) { 

 index = i; 

 break; 

 if(this.tooltips.tooltipCanvas == null) { 

 this.tooltips.tooltipCanvas = document.createElement("canvas"); 

 this.tooltips.ttContext = this.tooltips.tooltipCanvas.getContext("2d"); 

 this.tooltips.tooltipCanvas.width = 150; 

 this.tooltips.tooltipCanvas.height = 100; 

 // only draw once 

 // if(index == this.tooltips.index){ 

 // return; 

 // } 

 this.clearTooltips(ctx); 

 this.tooltips.index = index; 

 var m_context = this.tooltips.ttContext; 

 m_context.save(); 

 m_context.clearRect(0, 0, this.tooltips.tooltipCanvas.width, this.tooltips.tooltipCanvas.height); 

 m_context.lineWidth = 2; 

 m_context.strokeStyle = this.series[index].color; 

 m_context.fill ; 

 // m_context.strokeRect(2, 2, this.tooltips.tooltipCanvas.width-4, this.tooltips.tooltipCanvas.height-4); 

 // m_context.fillRect(2,2,this.tooltips.tooltipCanvas.width-4, this.tooltips.tooltipCanvas.height-4); 

 m_context.roundRect(2,2,this.tooltips.tooltipCanvas.width-4, this.tooltips.tooltipCanvas.height-4, 5, true, true); 

 m_context.font="14px Arial"; 

 m_context.fill ; 

 m_context.fillText("Index: " + (index + 1), 5, 20); 

 m_context.fillText(this.series[index].name + ": " + this.series[index].value + this.unit, 5, 40); 

 m_context.fillText(this.series[index].precent, 5, 60); 

 m_context.restore(); 

 // make tool-tip rectangle is always visible 

 if((loc.x + this.tooltips.tooltipCanvas.width) this.width) { 

 loc.x = loc.x - this.tooltips.tooltipCanvas.width; 

 if((loc.y - this.tooltips.tooltipCanvas.height) = 0) { 

 loc.y = loc.y + this.tooltips.tooltipCanvas.height; 

 ctx.drawImage(this.tooltips.tooltipCanvas, 0, 0, this.tooltips.tooltipCanvas.width, this.tooltips.tooltipCanvas.height, 

 loc.x, loc.y-this.tooltips.tooltipCanvas.height, this.tooltips.tooltipCanvas.width, this.tooltips.tooltipCanvas.height); 

 } else { 

 this.tooltips.index = -1; 

 this.clearTooltips(ctx); 

 clearTooltips : function(ctx) { 

 ctx.clearRect(0,0,this.width, this.height); 

 this.renderBorder(ctx); 

 ctx.drawImage(this.animation.animCanvas, 0, 0, this.width, this.height, 0, 0, this.width, this.height); 

 renderBorder : function(ctx) { 

 ctx.save(); 

 ctx.fill ; 

 ctx.stroke ; 

 ctx.fillRect(0, 0, this.width, this.height); 

 ctx.strokeRect(0, 0, this.width, this.height); 

 ctx.restore(); 

 renderPie : function(ctx, index, precent, deltaArc) { 

 var endAngle = deltaArc + 2*Math.PI*precent; 

 ctx.beginPath(); 

 ctx.arc(this.circle.cx, this.circle.cy, this.circle.radius, deltaArc, endAngle, false); 

 ctx.moveTo(this.circle.cx, this.circle.cy); 

 ctx.lineTo(this.circle.cx + this.circle.radius * Math.cos(deltaArc), this.circle.cy + this.circle.radius * Math.sin(deltaArc)); 

 ctx.lineTo(this.circle.cx + this.circle.radius * Math.cos(endAngle), this.circle.cy + this.circle.radius * Math.sin(endAngle)); 

 ctx.lineTo(this.circle.cx, this.circle.cy); 

 ctx.closePath(); 

 ctx.fillStyle = this.series[index].color; 

 ctx.fill(); 

 // render text content 

 if(this.text.enable) { 

 var halfEndAngle = deltaArc + Math.PI*precent; 

 var hx = this.circle.cx + this.circle.radius * Math.cos(halfEndAngle); 

 var hy = this.circle.cy + this.circle.radius * Math.sin(halfEndAngle); 

 ctx.beginPath(); 

 ctx.moveTo(hx, hy); 

 var linePos = (hx this.circle.cx) ? (hx - this.edge.width) : (hx + this.edge.width); 

 ctx.lineTo(linePos, hy); 

 ctx.closePath(); 

 ctx.stroke ; 

 ctx.stroke(); 

 var textPos = (hx this.circle.cx) ? (hx - this.edge.width*2) : (hx + this.edge.width); 

 precent = Math.round (precent*100) / 100; 

 var size = this.text.content.length; 

 var tipStr = (size index) ? this.text.content[index] : this.series[index].name + ": " + (precent * 100).toFixed(0) + "%"; 

 ctx.font = 10pt Calibri; 

 ctx.fill ; 

 ctx.fillText(tipStr, textPos, hy); 

 renderLegend : function(ctx, sum) { 

 if(!this.legend.enable) return; 

 var nums = this.series.length; 

 ctx.font = 10pt Calibri; 

 var pos = (this.width/2 (this.circle.radius+50)) ? 50 : (this.circle.cx - this.circle.radius); 

 for(var i=0; i nums; i++) { 

 var x = this.series[i].value/sum; 

 x = Math.round (x*100) / 100; 

 var tipStr = this.series[i].name + ": " + (x * 100).toFixed(0) + "%"; 

 this.series[i].precent = tipStr; 

 ctx.fillStyle = this.series[i].color; 

 ctx.fillRect(pos - 40, 20*i+10, 10, 10); 

 ctx.fillStyle = "black"; 

 ctx.fillText(tipStr, pos - 25, 20*i+20); 

 playAnimation : function(parent) { 

 if(parent.animation.hh parent.height) { 

 parent.animation.pctx.save(); 

 parent.animation.pctx.globalAlpha=0.5; 

 parent.animation.pctx.clearRect(0,0,parent.width, parent.height); 

 parent.renderBorder(parent.animation.pctx); 

 parent.animation.pctx.drawImage(parent.animation.animCanvas, 0, 0, parent.width, this.animation.hh, 0, 0, parent.width, this.animation.hh); 

 parent.animation.hh = parent.animation.hh + 10; 

 parent.animation.pctx.restore(); 

 setTimeout(function() {parent.playAnimation(parent);}, 1000/20); 

 } else { 

 parent.animation.pctx.clearRect(0,0,parent.width, parent.height); 

 parent.renderBorder(parent.animation.pctx); 

 parent.animation.pctx.drawImage(parent.animation.animCanvas, 0, 0, parent.width, parent.height, 0, 0, parent.width, parent.height); 

 // enable tool-tip functionality 

 if(parent.animation.enable parent.legend.enable) { 

 parent.chartCanvas.addEventListener(mousemove, function(event) { 

 var x = event.pageX; 

 var y = event.pageY; 

 var canvas = event.target; 

 var bbox = canvas.getBoundingClientRect(); 

 var loc = { x: x - bbox.left * (canvas.width / bbox.width), 

 y: y - bbox.top * (canvas.height / bbox.height)}; 

 parent.showTooltips(loc, (parent.animation.enable ? parent.animation.pctx : ctx)); 

 }, false); 

};

源代码可以直接使用

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/10089.html

cjava