Fork me on GitHub

从0开始撸一个支持单轴轮播的雷达图之中篇

如果你还不了解canvas,还不知道要讲啥,建议从首篇看起:从0开始写一个支持单轴轮播的雷达图
在首篇我们已经讲了怎么实现轮播,在这里我们将要用这一篇文章来说一下雷达图的单轴hover效果的实现,也是我写这篇文章的原因,因为echarts只支持单个series的hover。而我想要的是支持下面的效果:单轴hover。如果你只想知道怎么解决Echarts单轴轮播问题,并且你足够机智,你可以直接看最后一节。
clipboard.png

理清思路

如果你用过Echarts的radar图,如果你去看过生成雷达图形成的dom结构,你hover后会发现如下图所示
clipboard.png
有没有一种恍然大悟的感觉,其实就是在这画布的容器(我们称其为target)里里,添加了一个dom元素,来显示提示词。而这个dom元素的定位是绝对定位,定位点是根据hover捕获点在画布上的left和top计算值,然后显示生成的tooltip值;所以我们可以思考,要达到前面这几句话,我们需要提前做以下几步:
1、绑定一个鼠标移动事件,并试图捕捉画布上的拐点;
2、根据捕捉的点,获取相应的数据(标签,数值);
3:生成一个div元素(也可以是label这些元素),并设定位置,样式,及显示值,并添加到容器中,大功告成;

step by step

原谅我用了个英文单词,我确实不知道该用个什么标题。
如果你细心看过首篇的每一个实现步骤,并且理解整体思路,那接下来,事情会简单很多。因为无论哪个js插件画雷达图,前面的几步都是必须的,其核心除了canvas,其实就是计算和坐标转换,即将一块高为width,宽为height的dom元素变成一张拥有直角坐标系的画布,就像下面这个简图:
clipboard.png

绑定事件,并获取相对位置坐标点

我们为这个target元素绑定一个click事件,然后



  const draw = document.getElementById('canvas');
  const ctx = draw.getContext("2d");
/*获取鼠标在canvas画布上的位置(**不是浏览器窗口的鼠标位置)
 * clientX获取的相对浏览器窗口左上角的位置,适用于所有浏览器
 * 在chrome浏览器中,有一个zrX属性,是相对于元素本身的相对位置
 * getBoundingClientRect()函数是获取元素边框相对于浏览器窗口的位置
 * */
 function getMousePos(canvas, event) {
     var rect = canvas.getBoundingClientRect();
     return {
         x: event.clientX - rect.left ,
         y: event.clientY - rect.top
     }
 }
 draw.addEventListener('click',function(event){
    console.log(getMousePos(draw,event)); //打印得到的,就是鼠标点击位置相对于canvas容器元素左上角的坐标值,而不是相对于浏览器窗口。
 });

如果你还不明白,你可以试着拷贝代码,建立一个html页面尝试一下

根据获取的坐标点,判断是不是需要捕捉的点

你有可能会疑问,就算捕捉了这个点,那怎么才能判断这个点是不是需要捕捉的拐点呢?答案是,前面绘制这个拐点的时候,我们已经记录下了这个拐点在坐标位置,所以我们只需要将点击获取到的像素(px)值,转化为建立的坐标系坐标,我们就能轻易判断是不是拐点了,当然为了实现的灵敏度,我们需要给其配一个误差值,保证在拐点某个面积内都能触发这个hover。代码中有较多注释,具体看代码实现:
function addListener(dom,canvas,pointData){
//获取鼠标在canvas画布上的位置(*不是浏览器窗口的鼠标位置)
function getMousePos(canvas, evt) { //canvas就是dom中的canvas元素
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left
(canvas.width / rect.width),
y: evt.clientY - rect.top * (canvas.height / rect.height)
}
}
dom.addEventListener(‘click’,function (evt) { //开始测试建议用点击,后面弄清楚了改成mousemove事件就ok
const mouse = getMousePos(canvas, evt);
let point={};
let text = ‘’;
let index =-1;
const r =5; //这个r就是那个允许的误差值,值越大,越容易触发hover
point.x=mouse.x-offset.x/2; //offset的值就是画布的长和宽值,利用他们的中心点,可以计算鼠标点击位置在坐标系中的坐标值;
point.y=mouse.y-offset.y/2;//同上
for(let i=0;i (item[0] - r) && point.x < (item[0] + r) && point.y > (item1 - r) && point.y < (item1 + r)) {
index = i; //满足条件,就记录下这个值,用于后面单轴显示
break;
}
}
if(index!==-1){
hoverLabel(dom,mouse,index); //在下一步,我们将实现这个方法
}else{
removeLabel(dom);//当然,我们也将顺便实现这个方法
}
})

生成一个div元素,显示相应展示的轮播值

当我们生成一个div,并试图定位将其添加到画布容器中显示出来时,你需要明白下面两点:
1:这个div需要绝对定位,装他的容器需要一个非static定位;
2:装这个div的元素是装canvas容器的元素,而不是canvas,添加到canvas中 ,你将什么也看不到;
这个实现较简单,就直接看源码吧
/dom 即要添加div的容器,point即触发hover事件的位置,是位置,不是变换后的坐标,text即要显示的值/
function hoverLabel(dom,point,text){
removeLabel(dom);//生成前先判断有无,有就移除这个显示标签
let label =document.createElement(‘div’);
label.style.position=’absolute’;
label.style.top=point.y+’px’;
label.style.left=point.x+’px’;
label.style.border=’1px solid yellowgreen’;
label.style.background = ‘gray’;
label.style.zIndex = 999;

    label.innerHTML ='show:0999'+text;
    dom.appendChild(label);
}
function removeLabel(dom) {  //移除这个显示标签
  (dom.querySelectorAll('label').length)&&(dom.removeChild(dom.querySelector('label')));  //有就删除,没有就不动作
}

提示,我们也可以提前生成一个标签元素,将其添加到画布容器中,并不显示它,后面我们只需动态改变它的位置和内容。
至此,我们已经完成了单轴的hover,也就是下面这种效果图

clipboard.png
到这里,似乎该告一段落了,但好戏才要真正开始,我们的标题是解决Echarts单轴轮播,在末篇,我们将要真正写一个js插件来一步解决Echarts雷达图的轮播问题。

-------------本文结束感谢您的阅读-------------