带着canvas去流浪系列之四 绘制散点图
【摘要】 用原生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交互效果的基本算法如下:
在
canvas元素上监听鼠标移动事件,将鼠标坐标转换为canvas坐标系的坐标值。遍历数据点查看是否存在当前鼠标点距离某个数据中心点的距离小于其散点的绘制半径,如果有则认为鼠标在该点之上。
利用之前缓存的该点绘图数据,调整绘图样式,增大数据点的绘图半径覆盖式绘图即可。
当鼠标距离任何数据点的距离都大于该点的绘图半径,或鼠标从一个hover数据点移动到另一个hover点时,均需要调用一次
resetHover( )方法清除之前的hover状态。为了恢复hover前的状态,可以使用【离屏canvas技术】缓存首次绘图后的结果,然后使用
drawImage( )方法将对应区域恢复到hover前的状态。
4.2 参考代码
hover效果的关键代码如下,完整示例代码请在demo中获取,或访问【我的github仓库】
4.3 Demo中的小问题
为了简化代码,demo中的一些绘图数据并没有参数化,而是采取直接写死的形式放在代码里,尤其是逐帧绘图的代码,一般开发中此处都会配合动画来进行实现。
为了重置某个数据点的hover状态,笔者最初的实现思路是在每一帧中,使用
context.clip( )方法裁切出绘图区域,先用全局背景绘制出背景图,缩小数据点半径,然后再绘制数据点,直到半径缩小至hover前的值。但在实现后发现这种方式存在一个问题,那就是数据点之间出现重叠时,如果只是简单地背景重绘,就会将部分重叠区域清除掉,造成其他数据点无法复原,如下图所示:所以最终采用离屏canvas的方法,将初次绘制后的数据点先暂存下来,然后在清除hover状态时,使用
context.drawImage( )方法将有关区域的数据复制粘贴过来,以替代原来的使用背景图填充该区域的做法,这样就可以在数据点之间有重叠时重现hover前的状态。
作者:大史不说话
带着canvas去流浪系列之四 绘制散点图的更多相关文章
- 带着canvas去流浪系列之五 绘制K线图
[摘要] 用canvas原生API实现百度Echarts 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...
- 带着canvas去流浪系列之七 绘制水球图
[摘要] 用原生canvasAPI实现百度echarts 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...
- 带着canvas去流浪系列之三 绘制饼图
[摘要] 用canvas原生API绘制Echarts图表 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...
- 带着canvas去流浪系列之六 绘制雷达图
[摘要] 用canvas原生API实现百度Echarts基本图表. 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvas ...
- 带着canvas去流浪系列之二 绘制折线图
[摘要] 用canvasAPI实现echarts简易图表 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...
- 带着canvas去流浪系列之八 碰撞
[摘要] canvas动画-碰撞仿真 示例代码托管在:http://www.github.com/dashnowords/blogs 经过前面章节相对枯燥的练习,相信你已经能够上手canvas的原生A ...
- 带着canvas去流浪系列之八 碰撞【华为云技术分享】
[摘要] canvas动画-碰撞仿真 示例代码托管在:http://www.github.com/dashnowords/blogs 经过前面章节相对枯燥的练习,相信你已经能够上手canvas的原生A ...
- 带着canvas去流浪系列之一:绘制柱状图
[摘要] 学习使用canvasAPI来实现数据可视化. 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制柱 ...
- 带着canvas去流浪系列之九 粒子动画【华为云技术分享】
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...
随机推荐
- 【转】python之property属性
1. 什么是property属性 一种用起来像是使用的实例属性一样的特殊属性,可以对应于某个方法 # ############### 定义 ############### class Foo: def ...
- VM虚拟机安装Windows Server 2008操作系统
镜像链接:https://pan.baidu.com/s/1_Hv6U3xulqkkKzCYXmNvNQ 提取码:uwph Windows 2008 版本 有标准版.有企业版 群集 双击热备 clus ...
- Centos 7.X 安装及常规设置
一.制作USBHDD+启动 需要工具: UltraISO(软碟通) U盘 centos7镜像: http://www.centos.org 二.安装(有坑) U盘启动电脑,进入安装界面: 选中第一项, ...
- 【前端知识体系-CSS相关】CSS工程化方案
1.如何解决CSS的模块化问题? 使用Less,Sass等CSS预处理器 使用PostCSS插件(postcss-import/precss) 使用webpack处理CSS(css-loader + ...
- 简单说说基于JWT的token认证方式
一.什么是认证 好多人不知道什么是认证,认证,其实就是服务端确认用户身份.Http协议是无状态的,客户端发送一条请求,服务端返回一条响应,二者就算做成一单买卖,一拍两散.在很久以前,互联网所能提供的服 ...
- vc在x64体系的一般传参数方式
前篇分析过在objc中函数调用传参的一般方式,本篇分析vc在x64体系中的一般传参方式.手头上因为没有64位的vc编译器,只好用windbg看ms自身的函数是怎么样调用的. 首先看两个再熟悉不过的ap ...
- vue路由传参刷新丢失
没有系统学习过vue,以前使用路由传参都是直接this.$router.push({name:'main',params:{'id': 123}})的,没有在路由定义中配置参数,如下: router: ...
- 找到了element, 但是用getText却得到空值,取不到文本的解决办法
最近代码中发现一些bug, 在Debug过程中发现,页面元素是被定位到了,但是用getText方法取到的却是空值.调查了一下发现,getText是否返回值和isDisplayed是否为true有关.当 ...
- mysql--时区问题(时间差8个小时?修改Mysql 时区)
发现评论时间比本地时间晚8小时,原因:mysql默认时区选择了CST 解决办法: Ubuntu系统环境下: 1.检查mysql系统时区 进入mysql:mysql -u root -p mysql&g ...
- 【集训Day1 测试】奇怪数
奇怪数(odometer) [题目描述] 一个正整数Z是奇怪数,当且仅当满足的条件是:Z的所有数字中,只有一个数字不同于其他数字.例如:33323.110 都是奇怪数,而 9779.5555 都不是奇 ...