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

  

  

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

  

GitHub地址:https://github.com/TalkingData/inmap(本地下载)

  

文档地址:http://inmap.talkingdata.com/

  

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

  

蹦憧赡懿恢赖那岸怂惴ㄖ淖直苋胕nMap
  

  

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

  

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

  

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

  

蹦憧赡懿恢赖那岸怂惴ㄖ淖直苋胕nMap

  

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

  

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

  


  

  

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

        (   {   “名称”:“海门”,//要显示的文字   “液化天然气”:121.15,   “纬度”:31.89,   “数”:7,   “像素”:{//像素坐标   “x”: 968年,   “y”: 736   }   },   {   “名称”:“鄂尔多斯”,   “液化天然气”:109.781327,   “纬度”:39.608266,   “数”:5   “像素”:{   “x”: 659年,   “y”: 478   }   },   …   )      

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

  

  

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

        让ctx=this.container.getContext (2 d);//画布上下文   让宽度=ctx.measureText(名字).width;      

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

  

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

  

所以代码如下:

        让字形大?方法(ctx.font);   让身高=字形大小* 1.1;      

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

  

  

蹦憧赡懿恢赖那岸怂惴ㄖ淖直苋胕nMap
  

  

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

  

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

  

蹦憧赡懿恢赖那岸怂惴ㄖ淖直苋胕nMap

  

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

  

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

  

代码如下:

        _getLeftAnchor () {   让x=this.center。x -。半径,this.textReact.width   y=this.center。y - this.textReact。高度/2,   直径=0刖? 2,   maxH=直径比;this.textReact。高度& # 63;直径:this.textReact.height;//矩形的高度   返回{   x,   y,   风骚女子:x,   maxX: this.center。x + this.radius,   如矿坑的:this.center。y - maxH/2,   maxY: this.center。y + maxH/2   };   }      

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

  


  

  

判断两个矩形是否覆盖相交,根据矩形的风骚女子,maxX、如矿坑的,maxY判断相,交原理比较简单,代码如下:

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