Well-placed labels can be the difference between a sloppy map and a beautiful one. Labels need to clearly identify features without obscuring the map.

好的标注位置可以作为潦草的地图和漂亮的地图之间的区别。标签需要清晰地识别要素而不模糊地图。

The normal requirements for map labelling are to place labels as clearly as possible without any overlap. Regular maps just need to avoid label overlap for a single, fixed zoom level and rotation.

地图标注的正常要求是尽可能清晰地放置标签,而不需要重叠。正常地图只需要对一个单一的固定缩放级别和旋转来避免标签重叠。

Good label placement is a hard problem that we solve for Mapbox GL. We need our label placements to work at any zoom and any rotation. We need labels placements to be continuous, so that labels don’t jump around when zooming or rotating. We need labels to be seamless across tiles. We need to support changing font sizes as you zoom. And it all needs to be fast.

好的标注安置是我们解决的一个难题。我们需要我们的标签放置在任何缩放和任何旋转中都能正常展示。我们需要标注安置是渐进型的,这样标签不至于在旋转、缩放时跳来跳去。我们需要标注在瓦片上上无缝地连接。当你缩放时,我们需要支持更改字体大小。而且一切都需要快速。

Placement needs to support both horizontal labels, as well as curved labels which follow a line. Both types of labels need to behave smoothly when zooming and rotating. Labels can never overlap, even when rotating. Horizontal labels stay horizontal and curved labels rotate with the map. Labels are flipped to avoid being drawn upside down and curved labels smoothly slide along roads.

安置需要同时支持水平文字标注和沿着一条曲线弯曲的标注。两种类型的标签都需要在缩放和旋转时表现得很平滑。标签永远不能重叠,即使旋转时也不能重叠。水平标签保持水平且曲线标签随着地图旋转。文本标注会被翻转以避免被渲染成字头向下(文字倒置)的情况,弯曲的标签沿着道路平滑滑动。

There is plenty of academic research on label placement, but most of this applies to maps with fixed rotation and with separate zoom levels. Dynamic maps with continuous zooming, panning, and rotation need a completely different approach. Our implementation expands on a paper by Been and Yap that establishes four ideal requirements for continuous and interactive labelling:

标签安置方面的学术研究很多,但大部分都适用于固定旋转和分立的缩放级别的地图。具有连续缩放、平移和旋转的动态地图需要完全不同的安置方法。我们的实现扩展了由Been 和 Yap编写的论文,该论文为连续和交互式标签确立了四个理想要求:

  1. Labels should not disappear when zooming in or appear when zooming out.
  2. Labels should not disappear or appear when panning except when sliding out of view.
  3. Labels should not jump around, but instead should be anchored.
  4. Label placement should be deterministic, no matter how you got to the current view.
  1. 标签不应该在放大时消失,在缩小时出现。
  2. 标签不应该在平移时消失或出现,除非滑出视图。
  3. 标签不应该跳来跳去,而是应该被锚定。
  4. 标签的位置应该是确定的,无论你怎么到当前视图。

The paper provides guidance on implementing this for horizontal labels, but we go further by supporting rotation and curved labels.

该论文为水平标注的实现提供了指导,但是我们通过支持旋转和弯曲标签来更进一步完善文本安置。

  1. Our implementation has two steps:
  2. Preprocessing
  3. Rendering
  1. 我们的实现有两个步骤:
  2. 预处理
  3. 渲染

The rendering step needs to be fast so that Mapbox GL can rerender the entire map every frame for smooth interaction. Most of the placement work happens in the preprocessing step:

  1. Generate anchor points for each label.
  2. Calculate the positions of individual glyphs relative to the anchors.
  3. Calculate the zoom levels at which the labels and glyphs can be shown without overlap.
  4. Calculate the rotation range in which the label can be shown.

渲染步骤需要足够快以便为了mapbox gl 能够在每一帧中都能重新渲染整个地图以达到顺滑的交互效果。大多数的安置个工作发生在预处理的步骤中:

  1. 为每个标签生成锚点。
  2. 计算各个字形相对于锚点的位置。
  3. 计算该标签和符号可以没有重叠显示的缩放级别。
  4. 计算可以显示标签的旋转范围。

Generating anchor points

Each label has an anchor. An anchor is the point at which a label is positioned when zooming or rotating.

每一个标签都有一个锚点,锚点是指缩放活旋转时被定位位置的点。

Labels for point features have a single anchor, the point.

对于点要素的标签只有一个锚点,就是这个点本身。

For lines, we want to show multiple labels so we interpolate along the line adding an anchor every x pixels. Distance between labels changes when zooming, so we add a minimum zoom level for each anchor to maintain appropriate spacing. Fewer labels are shown at lower zoom levels and more appear as you zoom in.

对于线,我们想显示多个标签,所以我们沿着这条线对个x像素的都插入一个锚点。缩放时标签之间的距离发生变化,因此我们为每个锚添加最小缩放级别以保持适当的间距。较少的标签显示在较低缩放级别,并且随着您缩放的时候出现更多。

Generating positioned glyphs for each anchor

For each piece of text we already have a list of glyphs and their positions, but these positions need to be adjusted for curved labels.

对于每一段文本,我们已经有了一个字形和它们位置的列表,但是这些位置对于弯曲标签来说需要调整。

During the render step we can only shift glyphs along a straight line. To draw curved text we need to add multiple copies of glyphs — one for each line segment a glyph appears on. Each of these glyphs have minimum and maximum zoom levels that hide the glyph when it slides off the end of a segment so that only one instance of each original glyph is shown at the same time.

在渲染步骤中,我们只能沿着直线移动字形。要绘制曲面文本,我们需要添加多个字形副本每——一个线段上只出现一个字形。每个字形都有最小和最大缩放级别,当它滑动到段末端时隐藏字形符号,以便每一个原始字形的实例在同一时间只有一个能显示。

Usually these glyphs are completely hidden when out of range, but here they are shown with a reduced opacity:

通常这些符号在超出范围时完全隐藏起来,但是在这里它们显示出了一个减少的透明度:

Restricting the zoom range

To avoid label collisions, we need to restrict the zoom level at which a label is first shown. As you zoom in, labels get spaced further apart, opening room for new labels. Once a label is shown, it will not be hidden as you zoom in.

为了避免文本标注碰撞,我们需要在文本标注第一次显示时限制它的缩放级别。当你放大时,标签间距会进一步增大,为新的标签出现打开空间。一旦标签显示出来,它在放大时就不会被隐藏。

We use an R-tree that contains already-placed labels to narrow down which labels might collide. We then calculate the zoom level at which the two labels will fit side-by-side. It is safe to show the label for any zoom level higher than this one.

我们使用一个r树,它包含已经放置的标签来减少可能会碰撞的标签。然后计算两个标签将并排安装的缩放级别。对于任何缩放级别高于此的级别下显示这个标签是安全的。

Horizontal-horizontal collision

There are eight possible angles at which a pair of horizontal labels could collide. Each of these possible collisions is checked with some trigonometry.

有八个可能的角度会使得一对水平标签发生碰撞。这些可能碰撞的每一个都用一些三角学检验来检验。

弯曲-水平旋转碰撞

A curved-horizontal collision occurs when a corner of one label’s bounding box intersects an edge of the other label’s bounding box. For each of the eight bounding box corners, we calculate the angles at which a circle (formed by that point being rotated around the label’s anchor) intersects the edges of the other box. These are the angles at which a collision would begin and end.

当一个标签的边框的角与另一个标签的边框的边缘相交时,出现了弯曲水平碰撞。对于八个包围盒角的每个角落,我们计算了一个圆(由该点旋转围绕标签的锚)相交于另一个盒子的边缘的一些角度。这些就是碰撞开始和结束的角度。

Seamlessness

Mapbox GL downloads vector tiles with data for the area and zoom level it is currently displaying. When new tiles are downloaded and their labels have been placed, an old tile’s label may need to be hidden to make way for a more important label. This will be handled in a resolution step that has not yet been implemented.

Mapbox GL下载当前显示范围和缩放级别的矢量瓦片。当新的瓦片下载完成,且它们的标签位置已经计算完成,一个旧的瓦片的标注可能需要隐藏让位给一个更重要的标签。这将在尚未实现的步骤由解析处理。

mapbox.gl文字标注算法基本介绍的更多相关文章

  1. golang实现文字云算法

    golang实现文字云算法 项目链接 https://github.com/bangbaoshi/wordcloud 效果图 测试步骤如下 git clone https://github.com/b ...

  2. mapbox.gl源码解析——基本架构与数据渲染流程

    加载地图 Mapbox GL JS是一个JavaScript库,使用WebGL渲染交互式矢量瓦片地图和栅格瓦片地图.WebGL渲染意味着高性能,MapboxGL能够渲染大量的地图要素,拥有流畅的交互以 ...

  3. 3D GIS 应用开发 —— 基于 Mapbox GL 的实践总结

    最近在折腾的 web 端的可视化项目,由于相关业务的需要,用到了 Mapbox 这一地图开发的神器.在此先奉上一个基于mapbox-gl实现的demo(来源:uber的deck.gl项目): 下面我们 ...

  4. openlayers学习笔记(十三)— 异步调用JSON数据画点、文字标注与连线

    使用Openlayers 3实现调用本地json数据在地图上添加点.文字标注以及连线. 生成底图地图 首先得有一个地图作为底图,代码如下: let vectorSource = new ol.sour ...

  5. 【学】常用hash算法的介绍

    基本知识 Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值.这种转换是一种压缩映 ...

  6. leaflet渲染mapbox gl的矢量数据

    准备条件 1.mapbox-gl.js mapbox-gl.css 2.leaflet-mapbox-gl.js https://github.com/mapbox/mapbox-gl-leaflet ...

  7. DBoW2算法原理介绍

    本篇介绍DBoW2算法原理介绍,下篇介绍DBoW2的应用. DBow2算法 DBow2是一种高效的回环检测算法,DBOW2算法的全称为Bags of binary words for fast pla ...

  8. 算法笔记_071:SPFA算法简单介绍(Java)

    目录 1 问题描述 2 解决方案 2.1 具体编码   1 问题描述 何为spfa(Shortest Path Faster Algorithm)算法? spfa算法功能:给定一个加权连通图,选取一个 ...

  9. Zbar算法流程介绍

    博客转载自:https://blog.csdn.net/sunflower_boy/article/details/50783179 zbar算法是现在网上开源的条形码,二维码检测算法,算法可识别大部 ...

随机推荐

  1. 使用XAMPP和DVWA在Windows7上搭建渗透测试环境

    前言: XAMPP是一个Web应用程序运行环境集成软件包,包括MySQL.PHP.PerI和Apache的环境及Apache.MySQL.FilleZilla.Mercury和Tomecat等组件.D ...

  2. jmeter简单的使用

    jmeter简单的使用 一般步骤是:在测试计划下面新建一个线程组,线程组下面添加请求,请求中添加结果和断言 1.打开页面: 2.添加线程组: 3.线程组中设置参数: 很重要的几个参数:线程数.ramp ...

  3. redis 中如何切换db

    一台服务器上都快开启200个redis实例了,看着就崩溃了.这么做无非就是想让不同类型的数据属于不同的应用程序而彼此分开. 那么,redis有没有什么方法使不同的应用程序数据彼此分开同时又存储在相同的 ...

  4. 学会这15点,让你分分钟拿下Redis数据库

    1.Redis简介 REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统.Redis是一个开源的使用ANSI ...

  5. Python web简约表白网页源码分享,时光不老,我们不散!

    演示站:c.lmz8.cn打开js/4.js,复制到工具箱的js代码整理那,先解密,方便查看.工具箱:tool.lmz8.cnjs代码整理.在线解码 这个便是文字,只不过呗转码了,所以要用到解码工具. ...

  6. 学习Javascript数据结构与算法(第2版)笔记(1)

    第 1 章 JavaScript简介 使用 Node.js 搭建 Web 服务器 npm install http-server -g http-server JavaScript 的类型有数字.字符 ...

  7. 如何在当前目录下快速打开cmd(或者以管理员的身份打开)

    1.在当前目录下,按住shift键+点击右键,选择在此处打开命令窗口 很多时候我们需要打开命令行然后进入到相应目录进行一些操作. 常规的做法是: D:\foo\bar", 然后输入cd 再把 ...

  8. bzoj 2588 树上主席树

    主席树上树,对于每个节点,继承其父亲的,最后跑f[x]+f[y]-f[lca]-f[fa[lca]] 去重竟然要减一,我竟然不知道?? #include<cstdio> #include& ...

  9. BZOJ_2588_Spoj 10628. Count on a tree_树剖+主席树

    BZOJ_2588_Spoj 10628. Count on a tree_树剖+主席树 题意: 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastan ...

  10. K短路 (A*算法) [Usaco2008 Mar]牛跑步&[Sdoi2010]魔法猪学院

    A*属于搜索的一种,启发式搜索,即:每次搜索时加一个估价函数 这个算法可以用来解决K短路问题,常用的估价函数是:已经走过的距离+期望上最短的距离 通常和Dijkstra一起解决K短路 BZOJ1598 ...