当前位置:   article > 正文

HTML5 + JavaScript绘制饼图+1_js画出饼状图

js画出饼状图

利用难得的假期继续改进“圳品”信息系统,在另一个模块中使用之前的Pie()代码编制饼图。

代码详见:改进“圳品”信息系统网页上的饼图:加标题+文字说明换行显示

却发现饼图标题没显示出来。

研究源代码后发现问题出在计算饼图标题输出位置的代码上,即:

		this.ctx.fillText(this.title, (tcCanvas.width - this.title.length*fontSize)/2, 25);

在这里我们使用了tcCanvas.width,由于tcCanvas是一个实例,在另一个实例中调用这段代码就会出现问题。

改进的代码是把Canvas的width作为一个属性传递进来,即分为两步。

第一步,增加width属性:

  1. var typeCountPie = new Pie({
  2. ctx: ctx,
  3. x: tcCanvas.width / 2,
  4. y: tcCanvas.height / 2,
  5. r: 150,
  6. width:tcCanvas.width,//增加width属性
  7. data:aTypeCount,
  8. title:'“圳品”产品类别分析'
  9. });

第2步,修改计算饼图标题输出位置的代码,改为:

		this.ctx.fillText(this.title, (this.width - this.title.length*fontSize)/2, 25);

也就是用this.width 替代 了 tcCanvas.width,增强了代码通用性。完整的代码如下:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="Author" content="PurpleEndurer">
  6. <meta name="Keywords" content="">
  7. <meta name="Description" content="">
  8. <title>“圳品”信息系统</title>
  9. </head>
  10. <body>
  11. <script>
  12. const aType = [
  13. "水果",//0
  14. "粮食",//1,谷类、豆类、薯类
  15. "食用油",//2
  16. "饮用水",//3
  17. "畜",//4
  18. "禽",//5
  19. "渔",//6
  20. "其它"//7
  21. ];
  22. //结构:
  23. //类别,数量,颜色
  24. var aTypeCount = [
  25. [0, 3, "purple"],
  26. [1, 5, "gray"],
  27. [2,3, 'yellow'],
  28. [3,4,"green"],
  29. [4,8,"red"]
  30. ];
  31. </script>
  32. <canvas id="typeCountCanvas" style="border:1px solid red"></canvas>
  33. <div>
  34. <textarea border="1" id="taDebug" cols="80" rows="15">debug:</textarea>
  35. </div>
  36. <script>
  37. var tcCanvas = document.getElementById("typeCountCanvas");
  38. //var w = window.innerWidth;
  39. //var h = window.innerHeight;
  40. tcCanvas.height = 480;
  41. tcCanvas.width = 640;
  42. var ctx = tcCanvas.getContext('2d');
  43. var taDbg = document.getElementById("taDebug");
  44. function Pie(obj)
  45. {
  46. for(var key in obj)
  47. {
  48. this[key] = obj[key];
  49. }
  50. this.init();
  51. this.render(this.slice);
  52. this.drawText();
  53. }
  54. Pie.prototype = {
  55. init: function () {
  56. this.start = 0;
  57. //1、累计数据求合
  58. var sum = 0;
  59. this.data.forEach(function (v) {
  60. sum += v[1];
  61. });
  62. //2、计算每一个数据所占的比重
  63. this.slice = this.data.map(function (v) {
  64. var obj = {};
  65. obj.number = v[1];
  66. obj.ratio = v[1] / sum;//每个数据占据的比重
  67. obj.radian = 2 * Math.PI * v[1] / sum;//该扇形所占据的弧度
  68. obj.start = this.start;
  69. obj.end = this.start + obj.radian;
  70. this.start = obj.end;
  71. obj.color = v[2];
  72. obj.text = aType[v[0]] + "类产品"+ v[1] + "个,占比" + Math.ceil(obj.ratio*100) + "%";
  73. return obj;
  74. },this);
  75. },
  76. //渲染页面(画饼图)
  77. render: function (obj) {
  78. //3、计算每一个扇形的起始弧度和结束弧度
  79. this.slice.forEach(function (v, i) {
  80. var obj = {};
  81. //第一个扇形的起始弧度:start 结束:start+第一个扇形占据的弧度差
  82. obj.start = this.start;
  83. obj.end = this.start + v.radian;
  84. this.start += v.radian;
  85. //绘制扇形
  86. this.ctx.beginPath();
  87. this.ctx.moveTo(this.x, this.y);
  88. this.ctx.arc(this.x, this.y, this.r, obj.start, obj.end);
  89. this.ctx.fillStyle = v.color;
  90. this.ctx.fill();
  91. }, this);
  92. },
  93. //输出文字说明
  94. drawText:function(){
  95. var fontSize = 20;//标题文字大小
  96. //如果标题属性已赋值且长度大于0,则输出标题文件
  97. if (typeof(this.title) != "undefined" && 0 < this.title.length)
  98. {
  99. this.ctx.font = "bolder "+ fontSize + "px 微软雅黑";
  100. this.ctx.fillStyle = 'black';
  101. this.ctx.fillText(this.title, (this.width - this.title.length*fontSize)/2, 25);
  102. }
  103. fontSize= 16;
  104. this.ctx.font = fontSize+"px 微软雅黑";
  105. var textWidth= 100;
  106. this.slice.forEach(function(obj){
  107. this.ctx.fillStyle = obj.color;// 'black';
  108. //计算文字所在的弧度
  109. r2 = obj.start + obj.radian/2;
  110. //计算相对于圆心文字偏移的位置
  111. b = this.r * Math.cos(r2) ;
  112. h = this.r * Math.sin(r2);
  113. //文字的x坐标位置
  114. var x2 = this.x + b;
  115. if (x2 <= this.x)
  116. {
  117. //在圆心的左侧
  118. x2 -= textWidth+10;
  119. }
  120. //文字的y坐标位置
  121. var y2 = this.y + h;
  122. if (y2 >= this.y)
  123. {
  124. y2 += fontSize;
  125. }
  126. else
  127. {
  128. //在圆心的上方
  129. y2 -= fontSize;
  130. }
  131. //this.ctx.fillText(obj.text, x2, y2);//在一行输出
  132. taDbg.value += "\nthis.r=" + this.r + " obj.text= " + obj.text + " x2=" + x2 + " y2=" + y2;
  133. //换行输出方法1
  134. var charNumPerLine = Math.ceil(textWidth / fontSize);
  135. var t = obj.text, i = 0;
  136. while (t.length > charNumPerLine)
  137. {
  138. this.ctx.fillText(t.substr(i,charNumPerLine), x2,y2);//绘制截取部分
  139. i += charNumPerLine;
  140. t = t.substring(i);
  141. y2 += fontSize;
  142. }
  143. if (i <= obj.text.length)
  144. {
  145. this.ctx.fillText(t, x2,y2);//绘制剩余部分
  146. }
  147. /*
  148. //换行输出方法2
  149. var i, lastSubStrIndex = lineWidth=0;
  150. for (i=0;i< obj.text.length; i++)
  151. {
  152. taDbg.value += '\nobj.text['+i +']=' + obj.text[i];
  153. lineWidth += ctx.measureText(obj.text[i]).width;
  154. if (lineWidth > textWidth)
  155. {
  156. this.ctx.fillText(obj.text.substring(lastSubStrIndex,i), x2,y2);//绘制截取部分
  157. y2 += fontSize;
  158. lineWidth = 0;
  159. lastSubStrIndex = i;
  160. }
  161. if(i==obj.text.length-1)
  162. { //绘制剩余部分
  163. this.ctx.fillText(obj.text.substring(lastSubStrIndex,i+1),x2,y2);
  164. break;
  165. }
  166. }//for*/
  167. },this);
  168. }
  169. };
  170. var typeCountPie = new Pie({
  171. ctx: ctx,
  172. x: tcCanvas.width / 2,
  173. y: tcCanvas.height / 2,
  174. r: 150,
  175. width:tcCanvas.width,//增加width属性
  176. data:aTypeCount,
  177. title:'“圳品”产品类别分析'
  178. });
  179. </script>
  180. </body>
  181. </html>

代码运行的效果如下:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/132626
推荐阅读
相关标签
  

闽ICP备14008679号