【摘要】 用原生canvasAPI实现百度Echarts图表

示例代码托管在:http://www.github.com/dashnowords/blogs

一. 任务说明

使用原生canvasAPI绘制散点图。(截图以及数据来自于百度Echarts官方示例库【查看示例链接】)。

二. 重点提示

学习过折线图的绘制后,如果数据点只有坐标数据,则通过基本的坐标转换在对应的点上绘制出散点并不难实现。而在气泡图中,当我们直接将百度Echarts示例中的数据拿来经过一定的线性缩小后作为半径直接绘制散点时,就会出现一些问题,数据集的范围跨度较大,导致大部分点呈现后都非常小,这个时候就需要使用某种方法从真实数据值映射到散点圆半径进行映射,来缩小它们之间的差异,否则一旦数据集中有一个偏离度较大的点,就会造成其他点所对应的散点半径都很大或者都很小,对数据呈现来说是不可取的。例如在下面的示例中,当使用几种不同的映射方法来处理数据后,可以看到绘制的散点图是不一样的。

//求散点半径时所使用的公式
//1.直接数值
r = value * 5 / 100000000;
//2.求对数
r = Math.log(value);
//3.求指数
r = Math.pow(value,0.4) / 100;

所绘制出的散点图如下所示:

坐标映射的实现思路其实并不算复杂,它的概念可以参考算法的时间复杂度来进行理解,挑选一个增长更快的映射函数来区分相近的点,或者挑选一个增长更慢的映射函数来减小大跨度数据之间的差异,在数据可视化中是非常实用的技巧。本文示例中的效果是笔者自己手动调的,如果要实现根据数据集自动挑选适当的映射函数,还需要设计一些计算方法,感兴趣的读者可以自行研究。

三. 示例代码

气泡散点图绘制示例代码(坐标轴的绘制过程在前述博文中已经出现过很多次,故不再赘述,有需要的小伙伴可以直接翻看这个系列之前的博文或者查看本篇的demo):

/*数据点来自于百度Echarts官方示例库,每个数值分别表示[横坐标,纵坐标,数值,国家,年份]
*[28604,77,17096869,'Australia',1990]
*/ /**
* 绘制数据
*/
function drawData(options) {
let data = options.data;//获取数据集
let xLength = (options.chartZone[2] - options.chartZone[0]);
let yLength = (options.chartZone[3] - options.chartZone[1]);
let gap = xLength / options.xAxisLabel.length; //遍历两个年份
for(let i = 0; i < data.length ;i++){
let x,y,r,c;
context.fillStyle = options.colorPool[i];//从颜色池中选取颜色
context.globalAlpha = 0.8;//为避免点覆盖,采取半透明绘制
//遍历各个数据点
for(let j = 0; j < data[i].length ; j++){
//计算坐标
x = options.chartZone[0] + xLength * data[i][j][0] / 70000;
y = options.chartZone[3] - yLength * (data[i][j][1] - 55) / (85 - 55); //直接数值
r = data[i][j][2] * 5 / 100000000;
//求对数
r = Math.log(data[i][j][2]);
//开根号
r = Math.pow(data[i][j][2],0.4) / 100;
//绘制散点
context.beginPath();
context.arc(x, y , r , 0 , 2*Math.PI,false);
context.fill();
context.closePath();
}
}
}

浏览器中可查看效果:

四.散点hover交互效果的实现

4.1 基本算法

在散点图上实现hover交互效果的基本算法如下:

  1. canvas元素上监听鼠标移动事件,将鼠标坐标转换为canvas坐标系的坐标值。

  2. 遍历数据点查看是否存在当前鼠标点距离某个数据中心点的距离小于其散点的绘制半径,如果有则认为鼠标在该点之上。

  3. 利用之前缓存的该点绘图数据,调整绘图样式,增大数据点的绘图半径覆盖式绘图即可。

  4. 当鼠标距离任何数据点的距离都大于该点的绘图半径,或鼠标从一个hover数据点移动到另一个hover点时,均需要调用一次resetHover( )方法清除之前的hover状态。

  5. 为了恢复hover前的状态,可以使用【离屏canvas技术】缓存首次绘图后的结果,然后使用drawImage( )方法将对应区域恢复到hover前的状态。

4.2 参考代码

hover效果的关键代码如下,完整示例代码请在demo中获取,或访问【我的github仓库】

4.3 Demo中的小问题

  1. 为了简化代码,demo中的一些绘图数据并没有参数化,而是采取直接写死的形式放在代码里,尤其是逐帧绘图的代码,一般开发中此处都会配合动画来进行实现。

  2. 为了重置某个数据点的hover状态,笔者最初的实现思路是在每一帧中,使用context.clip( )方法裁切出绘图区域,先用全局背景绘制出背景图,缩小数据点半径,然后再绘制数据点,直到半径缩小至hover前的值。但在实现后发现这种方式存在一个问题,那就是数据点之间出现重叠时,如果只是简单地背景重绘,就会将部分重叠区域清除掉,造成其他数据点无法复原,如下图所示:

    所以最终采用离屏canvas的方法,将初次绘制后的数据点先暂存下来,然后在清除hover状态时,使用context.drawImage( )方法将有关区域的数据复制粘贴过来,以替代原来的使用背景图填充该区域的做法,这样就可以在数据点之间有重叠时重现hover前的状态。

demo.rar

作者:大史不说话

带着canvas去流浪系列之四 绘制散点图的更多相关文章

  1. 带着canvas去流浪系列之五 绘制K线图

    [摘要] 用canvas原生API实现百度Echarts 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...

  2. 带着canvas去流浪系列之七 绘制水球图

    [摘要] 用原生canvasAPI实现百度echarts 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...

  3. 带着canvas去流浪系列之三 绘制饼图

    [摘要] 用canvas原生API绘制Echarts图表 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...

  4. 带着canvas去流浪系列之六 绘制雷达图

    [摘要] 用canvas原生API实现百度Echarts基本图表. 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvas ...

  5. 带着canvas去流浪系列之二 绘制折线图

    [摘要] 用canvasAPI实现echarts简易图表 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...

  6. 带着canvas去流浪系列之八 碰撞

    [摘要] canvas动画-碰撞仿真 示例代码托管在:http://www.github.com/dashnowords/blogs 经过前面章节相对枯燥的练习,相信你已经能够上手canvas的原生A ...

  7. 带着canvas去流浪系列之八 碰撞【华为云技术分享】

    [摘要] canvas动画-碰撞仿真 示例代码托管在:http://www.github.com/dashnowords/blogs 经过前面章节相对枯燥的练习,相信你已经能够上手canvas的原生A ...

  8. 带着canvas去流浪系列之一:绘制柱状图

    [摘要] 学习使用canvasAPI来实现数据可视化. 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制柱 ...

  9. 带着canvas去流浪系列之九 粒子动画【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

随机推荐

  1. Linux下基本操作

    强行转Linux,开始以为会很不适应,其实还好,换汤不换药 本文只讲基本操作,足够让你愉快的打代码,想飞上天的自行百度,或找其他大神(友链) Update 6/20:由于写得太烂被学长爆踩了一顿 直接 ...

  2. Can't connect to MySQL server on 'localhost' (10061),连接Navicat报错问题解决

    今天,装了Mysql 1.1.7后,连接Navicat 时报错,后来找了一阵,发现问题所在. 原因是我在安装时把默认端口号3306修改成了3303, 连接时,把默认端口也修改下就好啦.

  3. JVM 中你不得不知的一些参数

    有的同学虽然写了一段时间 Java 了,但是对于 JVM 却不太关注.有的同学说,参数都是团队规定好的,部署的时候也不用我动手,关注它有什么用,而且,JVM 这东西,听上去就感觉很神秘很高深的样子,还 ...

  4. PHP实现开发者模式出现该公众号提供的服务出现故障 请稍后再试解决方法

    PHP实现开发者模式出现该公众号提供的服务出现故障 请稍后再试解决方法 仔细检查下有没有echo等输出的代码  echo没有输出东西 就是报这个信息  所以调试信息都必须写入日记

  5. AI的真实感

    目录 1.让AI"不完美"--估算和假设 2 AI感知 全能感知 特定感觉无知 3 AI的个性 4 AI的预判 5 AI的智能等级 ​ AI的真实感一直是游戏AI程序员追求的目标, ...

  6. C++中对C的扩展学习新增语法——函数重载

    函数重载 1.函数重载语法 1.同一个作用域(全局作用域.命名空间作用域.类作用域) 2.参数个数不同 3.参数类型不同 4.参数顺序不同 代码实现: 当函数名字一样的时候,通过参数类型.参数个数.参 ...

  7. 关于 “'sqlite3' 不是内部或外部命令.....”问题

    学习django 按书上的  执行 manage.py dbshell 时, 报“'sqlite3' 不是内部或外部命令,也不是可运行的程序 或批处理文件.” 也就是指,环境变量中没有“sqlite3 ...

  8. [转发]CSR8670的DFU功能

    本文源自:https://blog.csdn.net/wzz4420381/article/details/52371409 作者:RyomaWang 申明:为了保持原作者内容,这里不进行任何修改,后 ...

  9. devicemapper存储驱动下镜像的存储

    docker配置devicemapper存储驱动 #查看当前使用的存储驱动,默认为overlay docker info | grep -i storage #停止dockersystemctl st ...

  10. 【Linux系列】Centos7安装Samba并将工作区挂载到win(八)

    目的 本文主要介绍以下两点: 一. 安装Samba 二. 挂载到window 演示 一. 安装Samba Samba是基于smb协议的,主要作用是实现跨平台文件传输. 安装 yum install - ...