详解基于 Canvas 手撸一个六边形能力图分享!

一、前言

六边形能力图如下,由 6 个 六边形组成,每一个顶点代表其在某一方面的能力。这篇文章我们就来看看如何基于 canvas 去绘制这么一个六边形能力图。当然,你也可以基于其他开源的 js 方案来实现,如 EChars.js 等。

详解基于 Canvas 手撸一个六边形能力图 

二、六边形绘制基础

六边形能力图有 6 个 六边形组成,那我们只要绘制出一个,另外 5 个则依次减小六边形的边长即可。那我们首先来分析一下,如何绘制出一个六边形。

详解基于 Canvas 手撸一个六边形能力图

如上图,绘制一个六边形有以下几个关键点:

1.紫色矩形区域我们可以看成是 canvas 的画布。其大小可以认为是 (width,height)。center(centerX,centerY) 是其中心点,即 (width / 2, height / 2)。

2.绘制六边形的关键是计算出它的 6 个顶点的坐标。而如上图所示,这里面最关键的又是计算出六边形所在矩形区域的左上角坐标(left,top)。对照上图,(left,top) 的计算公式如下。

详解基于 Canvas 手撸一个六边形能力图

要计算出 (left,top) 需要先计算出 x,y 。而 x,y 的值与六边形的边长有关。

3.如上的 x,y 的计算公式为

详解基于 Canvas 手撸一个六边形能力图

4.因此,X1(x1,y1),X2(x2,y2),X3(x3,y3),X4(x4,y4),X5(x5,y5),X6(x6,y6) 的坐标计算为

详解基于 Canvas 手撸一个六边形能力图 详解基于 Canvas 手撸一个六边形能力图

因此,得到绘制六边形的代码为:

  function computeHexagonPoints(width, height, edge) {      let centerX = width / 2;      let centerY = height / 2;      let x = edge * Math.sqrt(3) / 2;      let left = centerX - x;      let x1,x2,x3,x4,x5,x6;      let y1,y2,y3,y4,y5,y6;      x5 = x6 = left;      x2 = x3 = left + x * 2;      x1 = x4 = left + x;        let y = edge / 2;      let top = centerY - 2 * y;      y1 = top;      y2 = y6 = top + y;      y3 = y5 = top + 3 * y;      y4 = top + 4 * y;        let points = new Array();      points[0] = [x1, y1];      points[1] = [x2, y2];      points[2] = [x3, y3];      points[3] = [x4, y4];      points[4] = [x5, y5];      points[5] = [x6, y6];      return points;    }

三、绘制六维能力图

 3.1 绘制 6 个六边形

基于 canvas 绘制,首先就是需要获取 context。

  _context = canvas.getContext('2d');

而绘制的话,已经知道 6 个顶点了,那只需要将这 6 个点用连线的方式连接起来就可以了。主要用到 moveTo(x,y) 和 lineTo(x,y) 两个方法。这里总共需要绘制 6 个六边形,那只要按等比例减小 edge 的值就可以了。因此绘制六边形能力图的主要代码如下。

  function drawHexagonInner(edge) {      _context.strokeStyle = _color;      for (var i = 0; i < 6; i++) {        _allPoints[i] = computeHexagonPoints(_width, _height, edge - i * edge / 5);        _context.beginPath();        _context.moveTo(_allPoints[i][5][0],_allPoints[i][5][1]);        for (var j = 0; j < 6; j++) {          _context.lineTo(_allPoints[i][j][0],_allPoints[i][j][1]);        }        _context.closePath();        _context.stroke();      }    }

代码中还有 3 个相关的 API。beginPath() 和 closePath() 主要就是绘制得到一个封闭的路径。stroke() 主要是得到一个镂空的形状。当然,相应的就有 fill() 得到填充的形状。

3.2 绘制 3 条直线

绘制那 3 条直线也是比较简单的,只要将 X1和X4 连接,将X2 和 X5 相连,将 X3 和 X6 相连。代码如下:

  function drawLines() {      _context.beginPath();      _context.strokeStyle = _color;      for (let i = 0; i < 3; i++) {        _context.moveTo(_allPoints[0][i][0],_allPoints[0][i][1]); //1-4        _context.lineTo(_allPoints[0][i+3][0],_allPoints[0][i+3][1]); //1-4        _context.stroke();      }      _context.closePath();    }

3.3 绘制覆盖图

6 个顶点代表了六种能力,比如这里的各科成绩,把六种能力封闭成一个闭合路径并填充则称为覆盖图。要绘制出覆盖图,这里需要计算出六个顶点。6 个顶点可以通过最外围的六边形的 6 个顶点和中心点来计算。简单来说就是通过能力得分,在顶点到中心距离的占比来计算。计算公式如下。

详解基于 Canvas 手撸一个六边形能力图

代码如下

  /**     * 画覆盖物     */    function drawCover() {        let tmpCoverPoints = _allPoints[0];      _coverPoints = [];      console.log("coverPoints ",tmpCoverPoints)        let centerX = _width / 2;      let centerY = _height / 2;      for (let i = 0; i < tmpCoverPoints.length; i++) {        _coverPoints.push([          centerX + (tmpCoverPoints[i][0] - centerX) * (_data[i].score / 100.0),          centerX + (tmpCoverPoints[i][1] - centerY) * (_data[i].score / 100.0)        ]);      }      console.log("newCoverPoints ",_coverPoints)      _context.beginPath();      _context.fillStyle = 'rgba(90,200,250,0.4)';      _context.moveTo(_coverPoints[5][0],_coverPoints[5][1]); //5      for (var j = 0; j < 6; j++) {        _context.lineTo(_coverPoints[j][0],_coverPoints[j][1]);      }      _context.stroke();      _context.closePath();      _context.fill();    }
  /**     * 描点     * @param pointRadius     */      function drawPoints(pointRadius) {      _context.fillStyle = _color;      for (let i = 0; i < _coverPoints.length; i++) {        _context.beginPath();        _context.arc(_coverPoints[i][0],_coverPoints[i][1],pointRadius,0,Math.PI*2);        _context.closePath();        _context.fill();      }    }

3.4 最后来绘制文本

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请点击右边联系管理员删除。

如若转载,请注明出处:https://www.ctvol.com/htm5ctutorials/472348.html

(0)
上一篇 2020年10月26日
下一篇 2020年10月26日

精彩推荐