热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

从0开始撸一个支持单轴轮播的雷达图(Ehcarts的单轴显示问题)之头篇

引子最近做公司的数据展示项目,用的核心插件是Echarts,但在雷达图的展示案列上,需求上出现了需要单轴轮播标签和数据,在看

引子

最近做公司的数据展示项目,用的核心插件是Echarts,但在雷达图的展示案列上,需求上出现了需要单轴轮播标签和数据,在看完github上的issue后,这个Echarts3不支持,看了一下源码,似乎有点复杂,改了改,只实现了多个series的轮播,和需求还是有差距,周末反正无聊,何不自己动手撸一个。

整理一下思路

clipboard.png

想实现如上图这样一个建议雷达图,需要几步?个人总结,需要:
初始化一个canvas对象;

  1. 以画布中心,绘制三个同心圆;

  2. 根据输入的点数,计算3根轴在外径圆上的6个坐标点,并以中心点,绘制6根轴线;

  3. 根据输入的标签,集合前面6个坐标点,完成6个标签在画布的绘制;

  4. 根据输入的数据,结合前面的6个坐标,计算得输入数据的坐标点,连线完成输入数据展示;

  5. 要实现轮播,主要解决的就是根据输入数据坐标点计算此点在Dom元素的位置,然后轮播显示;

  6. 如果想触发echarts那种hover tooltip的效果,你只需要添加一个mousemove事件,获取位置,并计算其相对应的坐标点。

好像要达到的效果就完成了,似乎不难,来吧,实现它。

分布实现

初始化一块画布

首先引入一个canvas函数,并为其制定长高,然后获取这个元素,并得到一块平面画布,代码如下:

const draw = document.getElementById('canvas');const ctx = draw.getContext("2d");

为了后面更方便的计算,我们需要把坐标原点从画布的右上角移到画布的中心,所以我们首先获取画布的长宽,接着使用translate方法,转移坐标原点

const offset = {x:draw.offsetWidth,y:draw.offsetHeight};ctx.translate(offset.x/2,offset.y/2);

这样我们就初始化了一块画布,并将其坐标原点移到了画布的中心.
这里提示两点:

  • 添加canvas为其指定宽高时,需要用width和height属性直接指定,而不能用style的宽高指定其宽高,如果是样式指定,画出来的线或圆是模糊且变形的;

  • 虽然上面变换了坐标原点,但是canvas坐标系默认是向下,向右为正,所以我们改变了坐标原点,但这个特点并未改变,所以像(0,120)这个点是位于坐标原点正下方的,而非通常我们认知的正上方;

画同心圆

在echarts中,圆的个数可通过splitNum配置,其实这个实现也不难,可通过下面的代码实现:

const m &#61; Math; const PI &#61; m.PI;//这两个参数后面经常会用&#xff0c;这里提前简单申明/*输入参数*ctx 画布* radius 要画的最外层圆的半径* spiltNum 要画的圆的个数* */function drawArc(ctx,radius,splitNum){ctx.beginPath(); //开始画路径/*这个可通过stokeColor与fillColor设置圆边的颜色和圆的填充色*/const splitStep &#61;radius/splitNum;for(let i&#61;1;i<&#61;splitNum;i&#43;&#43;){ //按splitNum个数&#xff0c;计算并画出相应的圆ctx.moveTo(i*splitStep,0); //这一句很重要&#xff0c;你需要手动移动你的画笔&#xff0c;而不是任其在画布上连续移动&#xff0c;画出不应该出现的线&#xff1b;ctx.arc(0,0,i*splitStep,0,2*PI,false);}ctx.stroke();}drawArc(ctx,raduis,3);

clipboard.png

这一步就提示一点&#xff1a;
ctx.beginPath()与ctx.stroke();总是成对成对出现&#xff0c;缺一个&#xff0c;这线必须出不来。

计算极坐标线与外侧圆的交点

首先回忆一个高中数学知识&#xff0c;已知一个圆的大小&#xff0c;其一条线与O度角直径成x度角&#xff0c;求其这条线沿Y轴正方向与圆的交点&#xff0c;好难&#xff0c;有没有&#xff0c;久了不摸&#xff0c;知识瞬间回到幼儿园&#xff0c;答案是&#xff1a;&#xff08;r*sin(x),r.cos(x)&#xff09;&#xff0c;答案怎么这么简单&#xff0c;不信&#xff0c;不信你可以用三个和四个点验证&#xff0c;我会说我就干过这事嘛。好了&#xff0c;进入正题&#xff0c;直接上函数&#xff0c;顺便说一句&#xff0c;我们在计算这个点的同时&#xff0c;也可以把标签的坐标点也一起算出来&#xff0c;直接上代码&#xff1a;

let l &#61; 6; //极坐标点的个数&#xff0c;也急速雷达的维度个数&#xff1b;const single &#61; 2*PI /l ;//计算偏转角度&#xff1b;let pointData&#61;[],labelData&#61;[];//声明两个数组&#xff0c;用于存储计算所得的坐标点&#xff1b;for(let i &#61; 0;i

点计算好了&#xff0c;接下来我们需要连接每个点到圆心得连线

/*输入画布&#xff0c;和要连接的点*/function drawLine(ctx,data){ctx.beginPath();ctx.strokeStyle &#61; &#39;blue&#39;;for(let i&#61; 0;i

clipboard.png

提示&#xff1a;其实绘制这几根极坐标也可以采用坐标变换rotate API来执行&#xff0c;比如这样

rotate(single);
ctx.lingeTo(0,r);

这样也很简单&#xff0c;但为了后面&#xff0c;我们需要知道这些极坐标也圆的交点&#xff0c;这在后面会很有用&#xff0c;但不得否认canvas的translate和retate是两个很好用的方法.

根据前面标签的计算点&#xff0c;绘制标签

canvas文字绘制&#xff0c;涉及到的属性和方法有font(设置字体样式),textAlign&#xff08;设置左右对齐&#xff09;,textBaseline&#xff08;设置基线&#xff0c;上下对齐&#xff09;,fillText&#xff08;文字绘制&#xff09;直接上代码&#xff1a;

let label&#61; [&#39;卫生&#39;,&#39;安全&#39;,&#39;交通&#39;,&#39;住宿&#39;,&#39;景点&#39;,&#39;吃88喝&#39;];
for(let i &#61; 0;ilabel[i] &#61; {label:label[i],position:labelData[i]}
}
function drawText(ctx,data,style) {const max &#61; data.length;ctx.font &#61; &#39;bold 14px Arial&#39;;ctx.textBaseline &#61;&#39;middle&#39;; //这个和textAlign都很重要&#xff0c;决定了整个图的美丑ctx.fillStyle &#61;&#39;red&#39;; //style.backgroundColorconsole.log(ctx);/*下面这些很重要&#xff0c;至于为什么&#xff0c;自己体会*/for(let i&#61;0;i&#61;-1)&&(x<&#61;1)){ //由于single值的问题&#xff0c;所以很多时候没有x&#61;0的出现&#xff0c;都是0.000001这种浮点数出现&#xff1b;ctx.textAlign &#61;&#39;center&#39;;}else if(x>1){ctx.textAlign &#61;&#39;left&#39;;}else{ctx.textAlign &#61;&#39;right&#39;;}ctx.fillText(data[i].label,...data[i].position);}
}
drawText(ctx,label);

clipboard.png

提示&#xff1a;strokeText与fillText都可以为文本描边&#xff0c;但strokeText使用效果更好&#xff1b;另外使用fillText时&#xff0c;是使用fillStyle为文字设置颜色属性&#xff0c;而strokeText是采用strokeStyle设置文字颜色属性&#xff0c;很重要

根据输入的点&#xff0c;绘制雷达闭合区域

其实这一步也相当简单&#xff0c;就是根据点计算在响应极坐标上的落点&#xff0c;然后一一连线&#xff0c;然后为封闭区域着色&#xff0c;直接上代码&#xff1a;

let data &#61; [120,50,150,80,100,140];for(let i &#61; 0;i

clipboard.png

也许拐点区域特殊处理&#xff0c;更有味道

Echarts怎么做的&#xff0c;Echarts可以配置拐点样式&#xff0c;那我们也为我们的雷达图加上拐点吧。
如果你想用绘制一个线&#xff0c;并根据拐点圆的大小和切入角度&#xff0c;然后计算出这条线的长度&#xff0c;再绘制这个拐点&#xff0c;然后再接着画线&#xff0c;这样真的很难&#xff0c;有没有简单点的&#xff0c;有&#xff0c;就是投机取巧&#xff0c;绘完线后再绘制拐点&#xff0c;并将这个拐点圆填充&#xff0c;这样看起来就像是我们连着画的啦&#xff0c;但这样也有bug&#xff0c;如果我们没有填充颜色&#xff0c;或者填充的颜色有透明度&#xff0c;那么拐点下两条线相交就可见了&#xff0c;我们的连续绘制假象也就被自己拆穿了。还是上代码把&#xff1a;

function drawPoint(ctx,data) {const max &#61; data.length;const r&#61; 3;ctx.fillStyle&#61;&#39;white&#39;; //rgba(10,50,200,0.5)ctx.beginPath();for(let i&#61;0;i

clipboard.png

至此&#xff0c;我们基础的图形就画完了&#xff0c;现在我们要做最重要的一步&#xff0c;也就是轮播了。

做一个简单的自动轮播

还是直接上代码吧&#xff0c;下一篇文章再详说&#xff1a;

let step &#61;-1;function removeLabel(dom) {(dom.querySelectorAll(&#39;label&#39;).length)&&(dom.removeChild(dom.querySelector(&#39;label&#39;)));}function autoLabel(point){removeLabel();let label &#61;document.createElement(&#39;label&#39;);label.innerHTML &#61;&#39;show:0999&#39;; //这里先写成定值&#xff0c;后面会详述怎样定制轮播值label.style.position&#61;&#39;absolute&#39;;label.style.top&#61;point[1]&#43;offset.y/2 &#43;&#39;px&#39;;label.style.left&#61;point[0]&#43;offset.x/2&#43;&#39;px&#39; ;label.style.border&#61;&#39;1px solid yellowgreen&#39;;label.style.background &#61; &#39;gray&#39;;label.style.opacity &#61; &#39;0.5&#39;label.style.zIndex &#61; 999;dom.appendChild(label);} setInterval(function(){step &#61; (step&#43;1)%6;autoLabel(draw,pointData[step]);},1000)

clipboard.png

好了&#xff0c;至此我们就简单的实现了一个暂时没法定制的雷达轮播图&#xff0c;在下一篇文章我们将会根据这里提到的思想&#xff0c;开发一个与简易版的echarts radar插件。
如果发现有任何叙述不正确之处或有更好的想法&#xff0c;还请指正。
源码地址

本文系列&#xff1a;
从0开始撸一个支持单轴轮播的雷达图&#xff08;Ehcarts的单轴显示问题&#xff09;之中篇
从0开始撸一个支持单轴轮播的雷达图&#xff08;Ehcarts的单轴显示问题&#xff09;之末篇
本文首发于&#xff1a;http://closertb.site &#xff0c;转载请注明



推荐阅读
  • [echarts] 同指标对比柱状图相关的知识介绍及应用示例
    本文由编程笔记小编为大家整理,主要介绍了echarts同指标对比柱状图相关的知识,包括对比课程通过率最高的8个课程和最低的8个课程以及全校的平均通过率。文章提供了一个应用示例,展示了如何使用echarts制作同指标对比柱状图,并对代码进行了详细解释和说明。该示例可以帮助读者更好地理解和应用echarts。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • 本文介绍了[从头学数学]中第101节关于比例的相关问题的研究和修炼过程。主要内容包括[机器小伟]和[工程师阿伟]一起研究比例的相关问题,并给出了一个求比例的函数scale的实现。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 本文介绍了机器学习手册中关于日期和时区操作的重要性以及其在实际应用中的作用。文章以一个故事为背景,描述了学童们面对老先生的教导时的反应,以及上官如在这个过程中的表现。同时,文章也提到了顾慎为对上官如的恨意以及他们之间的矛盾源于早年的结局。最后,文章强调了日期和时区操作在机器学习中的重要性,并指出了其在实际应用中的作用和意义。 ... [详细]
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
  • 本文介绍了在wepy中运用小顺序页面受权的计划,包含了用户点击作废后的从新受权计划。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • STL迭代器的种类及其功能介绍
    本文介绍了标准模板库(STL)定义的五种迭代器的种类和功能。通过图表展示了这几种迭代器之间的关系,并详细描述了各个迭代器的功能和使用方法。其中,输入迭代器用于从容器中读取元素,输出迭代器用于向容器中写入元素,正向迭代器是输入迭代器和输出迭代器的组合。本文的目的是帮助读者更好地理解STL迭代器的使用方法和特点。 ... [详细]
  • Ihaveaworkfolderdirectory.我有一个工作文件夹目录。holderDir.glob(*)>holder[ProjectOne, ... [详细]
  • 本文介绍了一个Python函数same_set,用于判断两个相等长度的数组是否包含相同的元素。函数会忽略元素的顺序和重复次数,如果两个数组包含相同的元素,则返回1,否则返回0。文章还提供了函数的具体实现代码和样例输入输出。 ... [详细]
  • 本文介绍了如何使用n3-charts绘制以日期为x轴的数据,并提供了相应的代码示例。通过设置x轴的类型为日期,可以实现对日期数据的正确显示和处理。同时,还介绍了如何设置y轴的类型和其他相关参数。通过本文的学习,读者可以掌握使用n3-charts绘制日期数据的方法。 ... [详细]
author-avatar
henrysong
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有