一、前言

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

详解基于 Canvas 手撸一个六边形能力图-1.jpg (17.59 KB, 下载次数: 0)

2020-7-13 15:29 上传

二、六边形绘制基础

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

详解基于 Canvas 手撸一个六边形能力图-2.jpg (9.84 KB, 下载次数: 0)

2020-7-13 15:29 上传

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

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

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

详解基于 Canvas 手撸一个六边形能力图-3.png (2.27 KB, 下载次数: 0)

2020-7-13 15:29 上传

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

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

详解基于 Canvas 手撸一个六边形能力图-4.png (2 KB, 下载次数: 0)

2020-7-13 15:29 上传

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

详解基于 Canvas 手撸一个六边形能力图-5.png (3.38 KB, 下载次数: 0)

2020-7-13 15:29 上传

详解基于 Canvas 手撸一个六边形能力图-6.png (3.24 KB, 下载次数: 0)

2020-7-13 15:29 上传

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

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= computeHexagonPoints(_width, _height, edge - i * edge / 5);

_context.beginPath();

_context.moveTo(_allPoints[5][0],_allPoints[5][1]);

for (var j = 0; j < 6; j++) {

_context.lineTo(_allPoints[j][0],_allPoints[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][0],_allPoints[0][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 手撸一个六边形能力图-7.png (3.2 KB, 下载次数: 0)

2020-7-13 15:29 上传

代码如下

/**

* 画覆盖物

*/

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[0] - centerX) * (_data.score / 100.0),

centerX + (tmpCoverPoints[1] - centerY) * (_data.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[0],_coverPoints[1],pointRadius,0,Math.PI*2);

_context.closePath();

_context.fill();

}

}3.4 最后来绘制文本

绘制文本也是用的最外围的 6 个顶点的坐标。而用的 API 是 fillText(text,x,y),其中 x,y 代码文字绘制起点,但注意,不是文字所在矩形框的左上角,应该在左下角的大概位置。准确来说是文字的基线位置,这个在其他的GUI系统中也是一样,当然这里不追求那么细节了,就认为是左下角位置吧。

因此,对于不同侧的文字,其起点坐标也是不一样。如左侧的文字至少应该是左侧的顶点 x 减去文字的宽度。再比如,上下两侧的文字与顶点中相对居中对齐的,因此计算方法是 x 减去文字宽度的一半。代码的实现分为了上下左右来进行不同的绘制。

代码如下,看着有点长,但其实是很简单的。

/**

* 绘制上侧的文字

* @param text

* @param pos

*/

function drawUpText(item, pos) {

let nameMeasure = _context.measureText(item.name);

let scoreMeasure = _context.measureText(item.score);

_context.fillStyle = '#8E8E8E';

_context.fillText(item.name, pos[0] - nameMeasure.width / 2,pos[1] - 26);

_context.fillStyle = '#212121';

_context.fillText(item.score, pos[0] - scoreMeasure.width / 2,pos[1] - 10);

}

/**

* 绘制下侧的文字

* @param text

* @param pos

*/

function drawDownText(item, pos) {

let nameMeasure = _context.measureText(item.name);

let scoreMeasure = _context.measureText(item.score);

_context.fillStyle = '#8E8E8E';

_context.fillText(item.name, pos[0] - nameMeasure.width / 2,pos[1] + 16);

_context.fillStyle = '#212121';

_context.fillText(item.score, pos[0] - scoreMeasure.width / 2,pos[1] + 32);

}

/**

* 绘制左侧的文字

* @param text

* @param pos

*/

function drawLeftText(item, pos) {

let nameMeasure = _context.measureText(item.name);

let scoreMeasure = _context.measureText(item.score);

_context.fillStyle = '#8E8E8E';

_context.fillText(item.name, pos[0] - nameMeasure.width - 10,pos[1]);

_context.fillStyle = '#212121';

_context.fillText(item.score, pos[0] - 10 - (nameMeasure.width + scoreMeasure.width) / 2,pos[1] + 16);

}

/**

* 绘制右侧的文字

* @param text

* @param pos

*/

function drawRightText(item, pos) {

let nameMeasure = _context.measureText(item.name);

let scoreMeasure = _context.measureText(item.score);

_context.fillStyle = '#8E8E8E';

_context.fillText(item.name, pos[0] - nameMeasure.width + 26,pos[1]);

_context.fillStyle = '#212121';

_context.fillText(item.score, pos[0] + 26 - (nameMeasure.width + scoreMeasure.width) / 2,pos[1] + 16);

}

/**

* 绘制所有文本

*/

function drawText() {

_context.fillStyle = '#8E8E8E';

_context.strokeStyle = _color;

let textPos = _allPoints[0];

for (let i = 0; i < textPos.length; i++) {

let item = _data;

let pos = textPos;

if(i == 0) {

drawUpText(item, pos);

} else if(i == 1 || i == 2) {

drawRightText(item, pos);

} else if(i == 3) {

drawDownText(item, pos);

} else if(i == 4 || i == 5) {

drawLeftText(item, pos);

}

}

}四、总结

文章主要是基于 canvas 自定义一个六边形能力图,而这个能力的图的关键部分是对于六边形的绘制,而六边形的绘制又在于计算出 6 个顶点。有了 6 个顶点,再绘制其他的边,文本,覆盖区域等都基于这个 6 个顶点进行相应的绘制即可。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持咔叽论坛。

php 六边形 属性图 能力数值图,详解基于 Canvas 手撸一个六边形能力图相关推荐

  1. html5如何编写六角形,详解基于 Canvas 手撸一个六边形能力图

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

  2. php 六边形 属性图 能力数值图,css怎样做出六边形图片

    这次给大家带来css怎样做出六边形图片,css做出六边形图片的注意事项有哪些,下面就是实战案例,一起来看一下. 本文主要介绍了css实现六边形图片的示例代码,分享给大家,具体如下: 不说别的,先上效果 ...

  3. html怎么给视频加遮罩,详解基于canvas的视频遮罩插件

    为一个视频添加一个覆盖物,从而挡住视频某区域,在视频的某一时间段,比如第10到第20分钟不显示划定的这块区域.应用场景包括 遮挡卫视图标 . 遮挡视频右下角广告 . 充当马赛克 等. 一个长视频可能包 ...

  4. k8s、ServiceAccount权限详解、RBAC 详解(基于角色的访问控制),常用操作指令

    文章目录 Service Account应用示例 RBAC 详解(基于角色的访问控制) 创建一个角色(role)---权限 实验二 常用操作指令 Service Account应用示例 概念图权限关系 ...

  5. python 折线图 尾部_Matplotlib 折线图plot()所有用法详解

    散点图和折线图是数据分析中最常用的两种图形.其中,折线图用于分析自变量和因变量之间的趋势关系,最适合用于显示随着时间而变化的连续数据,同时还可以看出数量的差异,增长情况. Matplotlib 中绘制 ...

  6. 详解基于图卷积的半监督学习

    Kipf和Welling最近发表的一篇论文提出,使用谱传播规则(spectral propagation)快速近似spectral Graph Convolution. 和之前讨论的求和规则和平均规则 ...

  7. 图之邻接表详解(C语言版)

    文章目录 一.定义 二.结构 三.常用操作 四.测试 结语 附录 一.定义 图的邻接表是一种顺序与链式存储相结合的存储方式.下面给出一个示例,以便大家能够理解邻接表这种存储方式:         无向 ...

  8. 呆呆带你手撸一个思维导图-基础篇

    希沃ENOW大前端 公司官网:CVTE(广州视源股份) 团队:CVTE旗下未来教育希沃软件平台中心enow团队 「本文作者:」 前言 你盼世界,我盼望你无bug.Hello 大家好,我是霖呆呆! 哈哈 ...

  9. javascript实现图片轮播_手撸一个简易版轮播图(上)

    手撸一个简易版轮播图 实现原理,通过控制 swiper-warpper 容器的定位来达到切换图片的效果. 页面布局 简易版轮播图 < > 页面样式 .container{width: 60 ...

最新文章

  1. QTP时间格式的转换(YYYYMMDDHHMMSS)
  2. ggplot01:R语言坐标轴离散、连续与图例离散连续的区分
  3. 数据转数字类型的方法总结
  4. matlab中predictor怎么填,在MATLAB中求解非線性有限元
  5. Python 生成器 迭代器
  6. ASP.Net Core 3.1 中使用JWT认证
  7. [vue-cli]vue-cli默认是单页面的,那要弄成多页面该怎么办呢
  8. 正确断开计算机和网络的方法是,网络管理与维护-题库
  9. 做梦都在想的游戏设备
  10. JAVA学习day07 1
  11. 浅谈ES6中的rest参数
  12. 内网通过计算机名查询IP地址
  13. 大龄程序员的一些出路
  14. matlab 怎么求直线斜率,matlab中如何求近似(不平滑)直线的斜率
  15. MySQL语句-查看当前数据库有哪些表(SHOW TABLES)
  16. win7计算机无法连接投影仪,联想笔记本win7系统连接投影仪的方法【图文详解】...
  17. 根据六边形边长求六边形面积
  18. Gate 用户手册(一)总体概念
  19. ReactNative的SDK打包后给到其他项目集成
  20. springboot项目本地运行无问题,Linux系统报错org.thymeleaf.exceptions.TemplateInputException

热门文章

  1. CH0502 七夕祭
  2. 模拟QQ自动隐藏窗体
  3. #前端开发我们应该具备的硬核技能
  4. 图像合成:Multi-scale Image Harmonization
  5. ubuntu 20.04安装各类软件
  6. 平台+插件源代码最新地址
  7. 浅析Android中build.gradle的实用技巧
  8. 写 Python 爬虫的助手
  9. HMM(隐马尔可夫)笔记
  10. 成长计划校园极客秀|基于OpenHarmony的智能阳台