你可能不知道的前端算法之文字避让inMap

前言

inMap 是一款基于 canvas 的大数据可视化库,专注于大数据方向点线面的可视化效果展示。目前支持散点、围栏、热力、网格、聚合等方式;致力于让大数据可视化变得简单易用。

GitHub 地址:()

文档地址:

在地理信息可视化中,我们经常会遇到在地图上标记文字的需求,下面展示的是某流行 chart 图表框架的效果:

要显示的文字空间不够时,就会造成文字重叠显示混乱,用户体验很不友好。

怎么解决这个问题呢?我们采用文字避让算法,解决这种坑爹的问题。

下面展示的是 inMap 文字避让效果:

文字标注算法是 GIS 中最复杂的问题之一(属于 NP 复杂度问题,所以通常不能找到最优解,只能找到较优解)。

inMap 避让算法采用的是四分位模型算法,接下来手把手教你写避让算法,老司机带你装逼带你飞。

准备数据

inMap 接收的是经纬度数据,需要把它映射到 canvas 的像素坐标,这就用到了墨卡托转换,墨卡托算法很复杂,以后我们会有单独的一篇文章来讲讲他的原理。经过转换,你得到的数据应该是这样的:

好了,我们得到转换后的像素坐标数据(x、y),就可以做下面的事情了。

求出每段文字矩形的实际大小

measureText() 是 canvas 内置的方法,返回字体宽度的像素单位:

我们通过 measureText 得到每个文字的宽度,canvas 并没有直接获取文字的方法,那文字的高度如何的得到呢?

我们通过反复测试发现 canvas 的 font 等于 “13px Arial” 字体(别的字体不敢保证)的时候,文字的高度大概是 fontSize 的 1.1 倍。

所以代码如下:

文字的宽度和高度得到后,我们就可以创建文字矩形的坐标系了。

创建四分位模型

所谓四分位模型,每一个标记点都有上下左右四个放文字的位子,如果左边放不下,那就放右边试试,还不行就放到下面试试,以此类推,原理就这么简单,哈哈。

创建右侧虚拟矩形坐标描述:

右侧虚拟矩形坐标的描述把圆点也包含在内了,是为了防止文字和圆点重叠。

在计算虚拟矩形的高度时有些坑,圆点大小不是固定的,是根据用户动态配置的,圆点的直径可能大于文字的高度,我们就设定虚拟矩形的高度永远都是最大的那个,需要做一些特殊处理。

代码如下:

this.textReact.height ? diam : this.textReact.height; //矩形的高度 return { x,y,minX: x,maxX: this.center.x + this.radius,minY: this.center.y - maxH / 2,maxY: this.center.y + maxH / 2 }; }

以此类推,描述下面、左面、上面的虚拟矩形坐标。

判断碰撞

判断两个矩形是否覆盖相交,根据矩形的 minX,maxX,minY,maxY 判断相交,原理比较简单,代码如下:

创建虚拟文字集合对象

{ let radius = val.pixel.radius + this.style.normal.borderWidth; //圆点半径 return new Label(val.pixel.x,val.pixel.y,radius,fontSize,byteWidth,val.name); });

递归遍历虚拟文字集合、判断是否与其他相交,如果有相交就移动当前文字位子,直到不相交为止。当找不到合适位置时,就选择隐藏当前文字。

代码如下:

绘画文字

文字避让算法到目前介绍完了,对应的 inMap 文件地址为,接下来还会继续给大家分享干货。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对编程之家的支持。

相关文章

kindeditor4.x代码高亮功能默认使用的是prettify插件,prett...
这一篇我将介绍如何让kindeditor4.x整合SyntaxHighlighter代...
js如何实现弹出form提交表单?(图文+视频)
js怎么获取复选框选中的值
js如何实现倒计时跳转页面
如何用js控制图片放大缩小