@react-x11/components 0.7.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +295 -51
- package/dist/charts/node.d.ts +1 -1
- package/dist/charts/node.d.ts.map +1 -1
- package/dist/charts/node.js +6 -2
- package/dist/charts/node.js.map +1 -1
- package/dist/color-picker/ColorPicker.d.ts.map +1 -1
- package/dist/color-picker/ColorPicker.js +43 -33
- package/dist/color-picker/ColorPicker.js.map +1 -1
- package/dist/embed/client.d.ts +48 -3
- package/dist/embed/client.d.ts.map +1 -1
- package/dist/embed/client.js +79 -5
- package/dist/embed/client.js.map +1 -1
- package/dist/embed/index.d.ts +1 -1
- package/dist/embed/index.d.ts.map +1 -1
- package/dist/embed/index.js +1 -1
- package/dist/embed/index.js.map +1 -1
- package/dist/html/node.d.ts +3 -1
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +7 -5
- package/dist/html/node.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/{markdown → internal/markdown}/ast.d.ts +12 -0
- package/dist/internal/markdown/ast.d.ts.map +1 -0
- package/dist/internal/markdown/ast.js +22 -0
- package/dist/internal/markdown/ast.js.map +1 -0
- package/dist/internal/markdown/parse.d.ts.map +1 -0
- package/dist/{markdown → internal/markdown}/parse.js +112 -22
- package/dist/internal/markdown/parse.js.map +1 -0
- package/dist/internal/markdown/stringify.d.ts +4 -0
- package/dist/internal/markdown/stringify.d.ts.map +1 -0
- package/dist/internal/markdown/stringify.js +684 -0
- package/dist/internal/markdown/stringify.js.map +1 -0
- package/dist/internal/markdown/tags.d.ts.map +1 -0
- package/dist/internal/markdown/tags.js.map +1 -0
- package/dist/internal/scroll.d.ts +3 -2
- package/dist/internal/scroll.d.ts.map +1 -1
- package/dist/internal/scroll.js +33 -15
- package/dist/internal/scroll.js.map +1 -1
- package/dist/internal/units.d.ts +2 -0
- package/dist/internal/units.d.ts.map +1 -0
- package/dist/internal/units.js +35 -0
- package/dist/internal/units.js.map +1 -0
- package/dist/internal/window.d.ts.map +1 -1
- package/dist/internal/window.js +4 -2
- package/dist/internal/window.js.map +1 -1
- package/dist/maps/anchors.d.ts +98 -0
- package/dist/maps/anchors.d.ts.map +1 -0
- package/dist/maps/anchors.js +531 -0
- package/dist/maps/anchors.js.map +1 -0
- package/dist/maps/controller.d.ts +283 -0
- package/dist/maps/controller.d.ts.map +1 -0
- package/dist/maps/controller.js +743 -0
- package/dist/maps/controller.js.map +1 -0
- package/dist/maps/gl/buckets.d.ts +95 -0
- package/dist/maps/gl/buckets.d.ts.map +1 -0
- package/dist/maps/gl/buckets.js +362 -0
- package/dist/maps/gl/buckets.js.map +1 -0
- package/dist/maps/gl/build-worker.d.ts +13 -0
- package/dist/maps/gl/build-worker.d.ts.map +1 -0
- package/dist/maps/gl/build-worker.js +44 -0
- package/dist/maps/gl/build-worker.js.map +1 -0
- package/dist/maps/gl/color.d.ts +8 -0
- package/dist/maps/gl/color.d.ts.map +1 -0
- package/dist/maps/gl/color.js +57 -0
- package/dist/maps/gl/color.js.map +1 -0
- package/dist/maps/gl/cover.d.ts +51 -0
- package/dist/maps/gl/cover.d.ts.map +1 -0
- package/dist/maps/gl/cover.js +124 -0
- package/dist/maps/gl/cover.js.map +1 -0
- package/dist/maps/gl/index.d.ts +3 -0
- package/dist/maps/gl/index.d.ts.map +1 -0
- package/dist/maps/gl/index.js +20 -0
- package/dist/maps/gl/index.js.map +1 -0
- package/dist/maps/gl/markers.d.ts +28 -0
- package/dist/maps/gl/markers.d.ts.map +1 -0
- package/dist/maps/gl/markers.js +60 -0
- package/dist/maps/gl/markers.js.map +1 -0
- package/dist/maps/gl/overlays.d.ts +68 -0
- package/dist/maps/gl/overlays.d.ts.map +1 -0
- package/dist/maps/gl/overlays.js +300 -0
- package/dist/maps/gl/overlays.js.map +1 -0
- package/dist/maps/gl/pane.d.ts +12 -0
- package/dist/maps/gl/pane.d.ts.map +1 -0
- package/dist/maps/gl/pane.js +37 -0
- package/dist/maps/gl/pane.js.map +1 -0
- package/dist/maps/gl/placement.d.ts +111 -0
- package/dist/maps/gl/placement.d.ts.map +1 -0
- package/dist/maps/gl/placement.js +567 -0
- package/dist/maps/gl/placement.js.map +1 -0
- package/dist/maps/gl/renderer.d.ts +352 -0
- package/dist/maps/gl/renderer.d.ts.map +1 -0
- package/dist/maps/gl/renderer.js +1127 -0
- package/dist/maps/gl/renderer.js.map +1 -0
- package/dist/maps/gl/shaders.d.ts +120 -0
- package/dist/maps/gl/shaders.d.ts.map +1 -0
- package/dist/maps/gl/shaders.js +451 -0
- package/dist/maps/gl/shaders.js.map +1 -0
- package/dist/maps/gl/store.d.ts +115 -0
- package/dist/maps/gl/store.d.ts.map +1 -0
- package/dist/maps/gl/store.js +469 -0
- package/dist/maps/gl/store.js.map +1 -0
- package/dist/maps/gl/text.d.ts +154 -0
- package/dist/maps/gl/text.d.ts.map +1 -0
- package/dist/maps/gl/text.js +382 -0
- package/dist/maps/gl/text.js.map +1 -0
- package/dist/maps/gl/view.d.ts +54 -0
- package/dist/maps/gl/view.d.ts.map +1 -0
- package/dist/maps/gl/view.js +974 -0
- package/dist/maps/gl/view.js.map +1 -0
- package/dist/maps/index.d.ts +1 -1
- package/dist/maps/index.d.ts.map +1 -1
- package/dist/maps/index.js +216 -52
- package/dist/maps/index.js.map +1 -1
- package/dist/maps/labels.d.ts +37 -16
- package/dist/maps/labels.d.ts.map +1 -1
- package/dist/maps/labels.js +188 -119
- package/dist/maps/labels.js.map +1 -1
- package/dist/maps/node.d.ts +162 -56
- package/dist/maps/node.d.ts.map +1 -1
- package/dist/maps/node.js +607 -515
- package/dist/maps/node.js.map +1 -1
- package/dist/maps/overlay.d.ts +72 -9
- package/dist/maps/overlay.d.ts.map +1 -1
- package/dist/maps/overlay.js +108 -28
- package/dist/maps/overlay.js.map +1 -1
- package/dist/maps/paint.d.ts +3 -0
- package/dist/maps/paint.d.ts.map +1 -1
- package/dist/maps/paint.js.map +1 -1
- package/dist/maps/proj.d.ts +14 -0
- package/dist/maps/proj.d.ts.map +1 -1
- package/dist/maps/proj.js +28 -0
- package/dist/maps/proj.js.map +1 -1
- package/dist/maps/renderer.d.ts +69 -0
- package/dist/maps/renderer.d.ts.map +1 -0
- package/dist/maps/renderer.js +66 -0
- package/dist/maps/renderer.js.map +1 -0
- package/dist/maps/sources.d.ts +25 -3
- package/dist/maps/sources.d.ts.map +1 -1
- package/dist/maps/sources.js +17 -0
- package/dist/maps/sources.js.map +1 -1
- package/dist/maps/theme.d.ts +19 -0
- package/dist/maps/theme.d.ts.map +1 -0
- package/dist/maps/theme.js +44 -0
- package/dist/maps/theme.js.map +1 -0
- package/dist/maps/tiles.d.ts +117 -17
- package/dist/maps/tiles.d.ts.map +1 -1
- package/dist/maps/tiles.js +163 -30
- package/dist/maps/tiles.js.map +1 -1
- package/dist/maps/types.d.ts +188 -20
- package/dist/maps/types.d.ts.map +1 -1
- package/dist/markdown/expressions.d.ts +1 -1
- package/dist/markdown/expressions.d.ts.map +1 -1
- package/dist/markdown/expressions.js.map +1 -1
- package/dist/markdown/index.d.ts +7 -6
- package/dist/markdown/index.d.ts.map +1 -1
- package/dist/markdown/index.js +9 -7
- package/dist/markdown/index.js.map +1 -1
- package/dist/markdown/spans.d.ts +1 -1
- package/dist/markdown/spans.d.ts.map +1 -1
- package/dist/media-player/index.d.ts +11 -3
- package/dist/media-player/index.d.ts.map +1 -1
- package/dist/media-player/index.js +13 -2
- package/dist/media-player/index.js.map +1 -1
- package/dist/rich-text-editor/clipboard.d.ts +23 -0
- package/dist/rich-text-editor/clipboard.d.ts.map +1 -0
- package/dist/rich-text-editor/clipboard.js +307 -0
- package/dist/rich-text-editor/clipboard.js.map +1 -0
- package/dist/rich-text-editor/collab.d.ts +32 -0
- package/dist/rich-text-editor/collab.d.ts.map +1 -0
- package/dist/rich-text-editor/collab.js +55 -0
- package/dist/rich-text-editor/collab.js.map +1 -0
- package/dist/rich-text-editor/commands.d.ts +50 -0
- package/dist/rich-text-editor/commands.d.ts.map +1 -0
- package/dist/rich-text-editor/commands.js +376 -0
- package/dist/rich-text-editor/commands.js.map +1 -0
- package/dist/rich-text-editor/drag.d.ts +68 -0
- package/dist/rich-text-editor/drag.d.ts.map +1 -0
- package/dist/rich-text-editor/drag.js +148 -0
- package/dist/rich-text-editor/drag.js.map +1 -0
- package/dist/rich-text-editor/html.d.ts +145 -0
- package/dist/rich-text-editor/html.d.ts.map +1 -0
- package/dist/rich-text-editor/html.js +516 -0
- package/dist/rich-text-editor/html.js.map +1 -0
- package/dist/rich-text-editor/index.d.ts +263 -0
- package/dist/rich-text-editor/index.d.ts.map +1 -0
- package/dist/rich-text-editor/index.js +822 -0
- package/dist/rich-text-editor/index.js.map +1 -0
- package/dist/rich-text-editor/inline.d.ts +94 -0
- package/dist/rich-text-editor/inline.d.ts.map +1 -0
- package/dist/rich-text-editor/inline.js +252 -0
- package/dist/rich-text-editor/inline.js.map +1 -0
- package/dist/rich-text-editor/keymap.d.ts +71 -0
- package/dist/rich-text-editor/keymap.d.ts.map +1 -0
- package/dist/rich-text-editor/keymap.js +393 -0
- package/dist/rich-text-editor/keymap.js.map +1 -0
- package/dist/rich-text-editor/keys.d.ts +29 -0
- package/dist/rich-text-editor/keys.d.ts.map +1 -0
- package/dist/rich-text-editor/keys.js +93 -0
- package/dist/rich-text-editor/keys.js.map +1 -0
- package/dist/rich-text-editor/look.d.ts +71 -0
- package/dist/rich-text-editor/look.d.ts.map +1 -0
- package/dist/rich-text-editor/look.js +342 -0
- package/dist/rich-text-editor/look.js.map +1 -0
- package/dist/rich-text-editor/markdown.d.ts +18 -0
- package/dist/rich-text-editor/markdown.d.ts.map +1 -0
- package/dist/rich-text-editor/markdown.js +496 -0
- package/dist/rich-text-editor/markdown.js.map +1 -0
- package/dist/rich-text-editor/nodes.d.ts +135 -0
- package/dist/rich-text-editor/nodes.d.ts.map +1 -0
- package/dist/rich-text-editor/nodes.js +397 -0
- package/dist/rich-text-editor/nodes.js.map +1 -0
- package/dist/rich-text-editor/render.d.ts +68 -0
- package/dist/rich-text-editor/render.d.ts.map +1 -0
- package/dist/rich-text-editor/render.js +500 -0
- package/dist/rich-text-editor/render.js.map +1 -0
- package/dist/rich-text-editor/schema.d.ts +16 -0
- package/dist/rich-text-editor/schema.d.ts.map +1 -0
- package/dist/rich-text-editor/schema.js +386 -0
- package/dist/rich-text-editor/schema.js.map +1 -0
- package/dist/rich-text-editor/store.d.ts +11 -0
- package/dist/rich-text-editor/store.d.ts.map +1 -0
- package/dist/rich-text-editor/store.js +43 -0
- package/dist/rich-text-editor/store.js.map +1 -0
- package/dist/rich-text-editor/suggest.d.ts +127 -0
- package/dist/rich-text-editor/suggest.d.ts.map +1 -0
- package/dist/rich-text-editor/suggest.js +0 -0
- package/dist/rich-text-editor/suggest.js.map +1 -0
- package/dist/rich-text-editor/tables.d.ts +41 -0
- package/dist/rich-text-editor/tables.d.ts.map +1 -0
- package/dist/rich-text-editor/tables.js +204 -0
- package/dist/rich-text-editor/tables.js.map +1 -0
- package/dist/rich-text-editor/toolbar.d.ts +58 -0
- package/dist/rich-text-editor/toolbar.d.ts.map +1 -0
- package/dist/rich-text-editor/toolbar.js +548 -0
- package/dist/rich-text-editor/toolbar.js.map +1 -0
- package/dist/rich-text-editor/view.d.ts +368 -0
- package/dist/rich-text-editor/view.d.ts.map +1 -0
- package/dist/rich-text-editor/view.js +1968 -0
- package/dist/rich-text-editor/view.js.map +1 -0
- package/dist/rich-text-editor/virtual.d.ts +54 -0
- package/dist/rich-text-editor/virtual.d.ts.map +1 -0
- package/dist/rich-text-editor/virtual.js +262 -0
- package/dist/rich-text-editor/virtual.js.map +1 -0
- package/dist/richtext/node.d.ts +25 -2
- package/dist/richtext/node.d.ts.map +1 -1
- package/dist/richtext/node.js +46 -24
- package/dist/richtext/node.js.map +1 -1
- package/dist/table/index.d.ts.map +1 -1
- package/dist/table/index.js +14 -5
- package/dist/table/index.js.map +1 -1
- package/dist/terminal/backends.d.ts +4 -1
- package/dist/terminal/backends.d.ts.map +1 -1
- package/dist/terminal/backends.js.map +1 -1
- package/dist/terminal/index.d.ts +18 -7
- package/dist/terminal/index.d.ts.map +1 -1
- package/dist/terminal/index.js +28 -11
- package/dist/terminal/index.js.map +1 -1
- package/dist/terminal/vt/node.d.ts +56 -3
- package/dist/terminal/vt/node.d.ts.map +1 -1
- package/dist/terminal/vt/node.js +106 -26
- package/dist/terminal/vt/node.js.map +1 -1
- package/dist/terminal/vt/renderer.d.ts +4 -0
- package/dist/terminal/vt/renderer.d.ts.map +1 -1
- package/dist/terminal/vt/renderer.js +14 -5
- package/dist/terminal/vt/renderer.js.map +1 -1
- package/dist/tree/index.d.ts.map +1 -1
- package/dist/tree/index.js +6 -4
- package/dist/tree/index.js.map +1 -1
- package/package.json +23 -4
- package/src/charts/node.ts +6 -2
- package/src/color-picker/ColorPicker.ts +107 -81
- package/src/embed/client.ts +102 -8
- package/src/embed/index.ts +2 -0
- package/src/html/node.ts +7 -5
- package/src/index.ts +2 -0
- package/src/{markdown → internal/markdown}/ast.ts +24 -7
- package/src/{markdown → internal/markdown}/parse.ts +134 -24
- package/src/internal/markdown/stringify.ts +772 -0
- package/src/internal/scroll.ts +39 -18
- package/src/internal/units.ts +34 -0
- package/src/internal/window.ts +4 -2
- package/src/maps/anchors.ts +607 -0
- package/src/maps/controller.ts +999 -0
- package/src/maps/gl/buckets.ts +457 -0
- package/src/maps/gl/build-worker.ts +55 -0
- package/src/maps/gl/color.ts +62 -0
- package/src/maps/gl/cover.ts +170 -0
- package/src/maps/gl/index.ts +23 -0
- package/src/maps/gl/markers.ts +83 -0
- package/src/maps/gl/overlays.ts +379 -0
- package/src/maps/gl/pane.ts +42 -0
- package/src/maps/gl/placement.ts +816 -0
- package/src/maps/gl/renderer.ts +1576 -0
- package/src/maps/gl/shaders.ts +486 -0
- package/src/maps/gl/store.ts +566 -0
- package/src/maps/gl/text.ts +495 -0
- package/src/maps/gl/view.ts +1224 -0
- package/src/maps/index.ts +270 -81
- package/src/maps/labels.ts +214 -121
- package/src/maps/node.ts +763 -629
- package/src/maps/overlay.ts +148 -43
- package/src/maps/paint.ts +3 -0
- package/src/maps/proj.ts +31 -0
- package/src/maps/renderer.ts +155 -0
- package/src/maps/sources.ts +38 -3
- package/src/maps/theme.ts +51 -0
- package/src/maps/tiles.ts +191 -33
- package/src/maps/types.ts +188 -20
- package/src/markdown/expressions.ts +5 -1
- package/src/markdown/index.ts +14 -11
- package/src/markdown/spans.ts +1 -1
- package/src/media-player/index.ts +18 -4
- package/src/rich-text-editor/clipboard.ts +439 -0
- package/src/rich-text-editor/collab.ts +91 -0
- package/src/rich-text-editor/commands.ts +448 -0
- package/src/rich-text-editor/dom-globals.d.ts +23 -0
- package/src/rich-text-editor/drag.ts +211 -0
- package/src/rich-text-editor/html.ts +619 -0
- package/src/rich-text-editor/index.ts +1331 -0
- package/src/rich-text-editor/inline.ts +345 -0
- package/src/rich-text-editor/keymap.ts +510 -0
- package/src/rich-text-editor/keys.ts +119 -0
- package/src/rich-text-editor/look.ts +427 -0
- package/src/rich-text-editor/markdown.ts +653 -0
- package/src/rich-text-editor/nodes.ts +497 -0
- package/src/rich-text-editor/render.ts +800 -0
- package/src/rich-text-editor/schema.ts +431 -0
- package/src/rich-text-editor/store.ts +39 -0
- package/src/rich-text-editor/suggest.ts +597 -0
- package/src/rich-text-editor/tables.ts +272 -0
- package/src/rich-text-editor/toolbar.ts +724 -0
- package/src/rich-text-editor/view.ts +2287 -0
- package/src/rich-text-editor/virtual.ts +347 -0
- package/src/richtext/node.ts +59 -30
- package/src/table/index.ts +14 -5
- package/src/terminal/backends.ts +4 -1
- package/src/terminal/index.ts +43 -15
- package/src/terminal/vt/node.ts +128 -29
- package/src/terminal/vt/renderer.ts +27 -5
- package/src/tree/index.ts +6 -4
- package/dist/markdown/ast.d.ts.map +0 -1
- package/dist/markdown/ast.js +0 -17
- package/dist/markdown/ast.js.map +0 -1
- package/dist/markdown/parse.d.ts.map +0 -1
- package/dist/markdown/parse.js.map +0 -1
- package/dist/markdown/tags.d.ts.map +0 -1
- package/dist/markdown/tags.js.map +0 -1
- /package/dist/{markdown → internal/markdown}/parse.d.ts +0 -0
- /package/dist/{markdown → internal/markdown}/tags.d.ts +0 -0
- /package/dist/{markdown → internal/markdown}/tags.js +0 -0
- /package/src/{markdown → internal/markdown}/tags.ts +0 -0
package/src/maps/labels.ts
CHANGED
|
@@ -9,6 +9,12 @@
|
|
|
9
9
|
// is the one thing on a map nobody accepts blurred. And a tile's labels
|
|
10
10
|
// would be **clipped at its edge**, which is where half of them sit.
|
|
11
11
|
//
|
|
12
|
+
// **Where a label can go is the GL renderer's answer too**: both renderers
|
|
13
|
+
// take their anchors from `./anchors.ts` — a place name at its point, a
|
|
14
|
+
// street's name on a straight stretch of the street, its pieces merged
|
|
15
|
+
// first — so a map switched from one renderer to the other names the same
|
|
16
|
+
// streets in the same places, at the same angles.
|
|
17
|
+
//
|
|
12
18
|
// The placement itself is done in **world pixels** rather than screen
|
|
13
19
|
// pixels, and that is the load-bearing decision in this file. A placement
|
|
14
20
|
// computed against the viewport changes whenever the viewport does, so a
|
|
@@ -17,12 +23,21 @@
|
|
|
17
23
|
// scrolled away. Placed in world pixels, whether a label wins depends only
|
|
18
24
|
// on the labels near it and the zoom, so a pan is a translation of a
|
|
19
25
|
// placement that is already correct, and the blit stands.
|
|
26
|
+
import {
|
|
27
|
+
LABEL_STRIDE,
|
|
28
|
+
LEVEL_SNAP,
|
|
29
|
+
LINE_MARGIN,
|
|
30
|
+
LabelField,
|
|
31
|
+
STRAIGHT_FRACTION,
|
|
32
|
+
buildTileLabels,
|
|
33
|
+
estimateWidth,
|
|
34
|
+
} from './anchors.js';
|
|
35
|
+
import type { GlLabelData } from './anchors.js';
|
|
20
36
|
import type { MapCanvas } from './paint.js';
|
|
21
|
-
import { GeomType, GeometryBuffer } from './mvt.js';
|
|
22
37
|
import type { VectorTile } from './mvt.js';
|
|
23
38
|
import type { PreparedStyle, PreparedLayer } from './paint.js';
|
|
24
39
|
import { resolveZoomed } from './style.js';
|
|
25
|
-
import type { SymbolLayer, Zoomed } from './style.js';
|
|
40
|
+
import type { MapStyleLayer, SymbolLayer, Zoomed } from './style.js';
|
|
26
41
|
import type { TileId, Transform } from './proj.js';
|
|
27
42
|
import { tileCountAt, tileKey } from './proj.js';
|
|
28
43
|
|
|
@@ -53,7 +68,7 @@ export interface ShapedLabel {
|
|
|
53
68
|
*
|
|
54
69
|
* `mx`/`my` are normalized mercator, so a candidate outlives every camera
|
|
55
70
|
* move — it is a property of the data, and collected once per tile per
|
|
56
|
-
* zoom.
|
|
71
|
+
* zoom. So are the lengths a name along a street is fitted with.
|
|
57
72
|
*/
|
|
58
73
|
export interface LabelCandidate {
|
|
59
74
|
/** Stable for the life of the tile, which is what lets a placement be
|
|
@@ -66,8 +81,23 @@ export interface LabelCandidate {
|
|
|
66
81
|
text: string;
|
|
67
82
|
mx: number;
|
|
68
83
|
my: number;
|
|
84
|
+
/** The baseline's direction, radians, y down: `0` for a point label, and
|
|
85
|
+
* along its street — always upright — for a street name. */
|
|
86
|
+
angle: number;
|
|
87
|
+
/** A street name's room: the straight run either side of the anchor, the
|
|
88
|
+
* distance to the nearest junction, the run's length and how far it
|
|
89
|
+
* bends from straight — normalized mercator, so a placement at any zoom
|
|
90
|
+
* reads them in its own pixels. `Infinity`, `Infinity`, `0`, `0` for a
|
|
91
|
+
* point label, which fits anywhere. */
|
|
92
|
+
avail: number;
|
|
93
|
+
clear: number;
|
|
94
|
+
length: number;
|
|
95
|
+
dev: number;
|
|
69
96
|
/** Layer-wide priority; higher wins a collision. */
|
|
70
97
|
rank: number;
|
|
98
|
+
/** Importance within the layer — a road's class, a place's population —
|
|
99
|
+
* which breaks a tie in rank. */
|
|
100
|
+
priority: number;
|
|
71
101
|
/** Logical pixels. */
|
|
72
102
|
size: number;
|
|
73
103
|
color: string;
|
|
@@ -78,7 +108,7 @@ export interface LabelCandidate {
|
|
|
78
108
|
}
|
|
79
109
|
|
|
80
110
|
/** A candidate that won its place, with the box it occupies in world
|
|
81
|
-
* pixels at the zoom it was placed for. */
|
|
111
|
+
* pixels at the zoom it was placed for — its turned text's bounding box. */
|
|
82
112
|
export interface PlacedLabel extends LabelCandidate {
|
|
83
113
|
/** World pixels: `mercator × worldSize`. */
|
|
84
114
|
wx: number;
|
|
@@ -96,115 +126,120 @@ function num<T extends number>(
|
|
|
96
126
|
return value === undefined ? fallback : resolveZoomed(value, zoom);
|
|
97
127
|
}
|
|
98
128
|
|
|
129
|
+
/** The tile units anchors are worked out in: the GL buckets', so the two
|
|
130
|
+
* renderers' anchors are the same numbers. */
|
|
131
|
+
const EXTENT = 4096;
|
|
132
|
+
|
|
99
133
|
/**
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
134
|
+
* Anchors, per tile and style. They depend on neither the zoom nor the
|
|
135
|
+
* camera, and merging a tile's street pieces is the one costly step, so a
|
|
136
|
+
* zoom that collects a tile's candidates again does not work them out
|
|
137
|
+
* again.
|
|
138
|
+
*/
|
|
139
|
+
const anchorCache = new WeakMap<
|
|
140
|
+
VectorTile,
|
|
141
|
+
{ prepared: PreparedStyle; data: GlLabelData }
|
|
142
|
+
>();
|
|
143
|
+
|
|
144
|
+
function anchorsOf(tile: VectorTile, prepared: PreparedStyle): GlLabelData {
|
|
145
|
+
const hit = anchorCache.get(tile);
|
|
146
|
+
if (hit && hit.prepared === prepared) return hit.data;
|
|
147
|
+
const data = buildTileLabels(tile, prepared, EXTENT);
|
|
148
|
+
anchorCache.set(tile, { prepared, data });
|
|
149
|
+
return data;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** A symbol layer's labelling at a zoom, or null where it does not label. */
|
|
153
|
+
interface LayerPaint {
|
|
154
|
+
id: string;
|
|
155
|
+
size: number;
|
|
156
|
+
color: string;
|
|
157
|
+
halo: string | undefined;
|
|
158
|
+
haloWidth: number;
|
|
159
|
+
rank: number;
|
|
160
|
+
repeat: number;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function paintAt(
|
|
164
|
+
layer: MapStyleLayer | undefined,
|
|
165
|
+
zoom: number,
|
|
166
|
+
): LayerPaint | null {
|
|
167
|
+
if (!layer || layer.type !== 'symbol' || layer.visible === false) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
if (layer.minZoom !== undefined && zoom < layer.minZoom) return null;
|
|
171
|
+
if (layer.maxZoom !== undefined && zoom >= layer.maxZoom) return null;
|
|
172
|
+
const symbol = layer as SymbolLayer;
|
|
173
|
+
return {
|
|
174
|
+
id: layer.id,
|
|
175
|
+
size: num(symbol.textSize, zoom, 12),
|
|
176
|
+
color: symbol.textColor ? resolveZoomed(symbol.textColor, zoom) : '#000000',
|
|
177
|
+
halo: symbol.textHaloColor
|
|
178
|
+
? resolveZoomed(symbol.textHaloColor, zoom)
|
|
179
|
+
: undefined,
|
|
180
|
+
haloWidth: num(symbol.textHaloWidth, zoom, 1),
|
|
181
|
+
rank: symbol.rank ?? 0,
|
|
182
|
+
repeat: symbol.repeatDistance ?? 250,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* The label candidates one tile contributes: its anchors (`./anchors.ts`),
|
|
188
|
+
* with this zoom's size and colours. A point label anchors at its point,
|
|
189
|
+
* an area's at the middle of its largest ring, and a street's name at the
|
|
190
|
+
* middle of a straight stretch of the street — or of a block of it —
|
|
191
|
+
* turned to lie along it.
|
|
108
192
|
*/
|
|
109
193
|
export function collectLabels(
|
|
110
194
|
tile: VectorTile,
|
|
111
195
|
id: TileId,
|
|
112
196
|
prepared: PreparedStyle,
|
|
113
197
|
zoom: number,
|
|
114
|
-
buffer: GeometryBuffer,
|
|
115
198
|
): LabelCandidate[] {
|
|
116
199
|
const out: LabelCandidate[] = [];
|
|
200
|
+
const data = anchorsOf(tile, prepared);
|
|
117
201
|
const n = tileCountAt(id.z);
|
|
118
202
|
const key = tileKey(id);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
: '#000000';
|
|
131
|
-
const halo = symbol.textHaloColor
|
|
132
|
-
? resolveZoomed(symbol.textHaloColor, zoom)
|
|
133
|
-
: undefined;
|
|
134
|
-
const haloWidth = num(symbol.textHaloWidth, zoom, 1);
|
|
135
|
-
const rank = symbol.rank ?? 0;
|
|
136
|
-
const repeat = symbol.repeatDistance ?? 250;
|
|
137
|
-
const extent = source.extent;
|
|
138
|
-
const cursor = source.feature(0);
|
|
139
|
-
for (let f = 0; f < source.length; f++) {
|
|
140
|
-
source.seek(f, cursor);
|
|
141
|
-
if (!filter(cursor)) continue;
|
|
142
|
-
const raw = cursor.get(symbol.textField);
|
|
143
|
-
// The schema's fallback: a translated name field is absent for most
|
|
144
|
-
// features, and the local `name` is what a map without a translation
|
|
145
|
-
// shows rather than nothing.
|
|
146
|
-
const text =
|
|
147
|
-
typeof raw === 'string' && raw.length > 0
|
|
148
|
-
? raw
|
|
149
|
-
: symbol.textField !== 'name'
|
|
150
|
-
? typeof cursor.get('name') === 'string'
|
|
151
|
-
? String(cursor.get('name'))
|
|
152
|
-
: ''
|
|
153
|
-
: '';
|
|
154
|
-
if (text.length === 0) continue;
|
|
155
|
-
cursor.readGeometry(buffer);
|
|
156
|
-
const anchor = anchorOf(buffer, cursor.type);
|
|
157
|
-
if (!anchor) continue;
|
|
158
|
-
out.push({
|
|
159
|
-
id: `${key}:${layer.id}:${f}`,
|
|
160
|
-
key: `${layer.id}|${text}`,
|
|
161
|
-
text,
|
|
162
|
-
// Tile-local to normalized mercator, the same arithmetic the
|
|
163
|
-
// rasterizer's transform does and for the same precision reason.
|
|
164
|
-
mx: (id.x + anchor.x / extent) / n,
|
|
165
|
-
my: (id.y + anchor.y / extent) / n,
|
|
166
|
-
rank,
|
|
167
|
-
size,
|
|
168
|
-
color,
|
|
169
|
-
halo,
|
|
170
|
-
haloWidth,
|
|
171
|
-
repeat,
|
|
172
|
-
});
|
|
203
|
+
// Tile units to normalized mercator.
|
|
204
|
+
const unit = 1 / (EXTENT * n);
|
|
205
|
+
const paints = new Map<number, LayerPaint | null>();
|
|
206
|
+
const a = data.anchors;
|
|
207
|
+
for (let r = 0; r < data.count; r++) {
|
|
208
|
+
const at = r * LABEL_STRIDE;
|
|
209
|
+
const index = a[at + LabelField.layer];
|
|
210
|
+
let paint = paints.get(index);
|
|
211
|
+
if (paint === undefined) {
|
|
212
|
+
paint = paintAt(prepared.layers[index]?.layer, zoom);
|
|
213
|
+
paints.set(index, paint);
|
|
173
214
|
}
|
|
215
|
+
if (!paint) continue;
|
|
216
|
+
const text = data.texts[a[at + LabelField.text]];
|
|
217
|
+
const point = a[at + LabelField.avail] < 0;
|
|
218
|
+
out.push({
|
|
219
|
+
id: `${key}:${paint.id}:${r}`,
|
|
220
|
+
key: `${paint.id}|${text}`,
|
|
221
|
+
text,
|
|
222
|
+
// Tile-local to normalized mercator, the same arithmetic the
|
|
223
|
+
// rasterizer's transform does and for the same precision reason.
|
|
224
|
+
mx: (id.x + a[at + LabelField.x] / EXTENT) / n,
|
|
225
|
+
my: (id.y + a[at + LabelField.y] / EXTENT) / n,
|
|
226
|
+
angle: point ? 0 : a[at + LabelField.angle],
|
|
227
|
+
avail: point ? Infinity : a[at + LabelField.avail] * unit,
|
|
228
|
+
clear: point ? Infinity : a[at + LabelField.clear] * unit,
|
|
229
|
+
length: a[at + LabelField.length] * unit,
|
|
230
|
+
dev: a[at + LabelField.dev] * unit,
|
|
231
|
+
rank: paint.rank,
|
|
232
|
+
priority: a[at + LabelField.priority],
|
|
233
|
+
size: paint.size,
|
|
234
|
+
color: paint.color,
|
|
235
|
+
halo: paint.halo,
|
|
236
|
+
haloWidth: paint.haloWidth,
|
|
237
|
+
repeat: paint.repeat,
|
|
238
|
+
});
|
|
174
239
|
}
|
|
175
240
|
return out;
|
|
176
241
|
}
|
|
177
242
|
|
|
178
|
-
function anchorOf(
|
|
179
|
-
buffer: GeometryBuffer,
|
|
180
|
-
type: GeomType,
|
|
181
|
-
): { x: number; y: number } | null {
|
|
182
|
-
if (buffer.points === 0) return null;
|
|
183
|
-
if (type === GeomType.Point) {
|
|
184
|
-
return { x: buffer.coords[0], y: buffer.coords[1] };
|
|
185
|
-
}
|
|
186
|
-
// The longest part, by its box — a cheap stand-in for arc length that
|
|
187
|
-
// does not need a second pass over the vertices.
|
|
188
|
-
let best = 0;
|
|
189
|
-
let bestSpan = -1;
|
|
190
|
-
for (let part = 0; part < buffer.parts; part++) {
|
|
191
|
-
const at = part * 4;
|
|
192
|
-
const span =
|
|
193
|
-
buffer.partBounds[at + 2] -
|
|
194
|
-
buffer.partBounds[at] +
|
|
195
|
-
(buffer.partBounds[at + 3] - buffer.partBounds[at + 1]);
|
|
196
|
-
if (span > bestSpan) {
|
|
197
|
-
bestSpan = span;
|
|
198
|
-
best = part;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
const from = buffer.starts[best];
|
|
202
|
-
const to = buffer.starts[best + 1];
|
|
203
|
-
if (to <= from) return null;
|
|
204
|
-
const mid = from + ((to - from) >> 1);
|
|
205
|
-
return { x: buffer.coords[mid * 2], y: buffer.coords[mid * 2 + 1] };
|
|
206
|
-
}
|
|
207
|
-
|
|
208
243
|
/** Cache of shaped strings, owned by the element. */
|
|
209
244
|
export class LabelShaper {
|
|
210
245
|
private readonly _cache = new Map<string, ShapedLabel>();
|
|
@@ -267,13 +302,25 @@ export class LabelShaper {
|
|
|
267
302
|
}
|
|
268
303
|
}
|
|
269
304
|
|
|
305
|
+
/** A street name is set level — on whole pixels, which is sharper — when
|
|
306
|
+
* its street is this close to level. */
|
|
307
|
+
function levelled(angle: number): number {
|
|
308
|
+
return Math.abs(angle) < LEVEL_SNAP ? 0 : angle;
|
|
309
|
+
}
|
|
310
|
+
|
|
270
311
|
/**
|
|
271
312
|
* Place candidates against each other, in world pixels.
|
|
272
313
|
*
|
|
273
|
-
* Greedy
|
|
274
|
-
* nothing already taken overlaps it. The order
|
|
275
|
-
*
|
|
276
|
-
*
|
|
314
|
+
* Greedy, which is what every map does: sort, and take a label if it fits
|
|
315
|
+
* where it is and nothing already taken overlaps it. The order is the GL
|
|
316
|
+
* renderer's, less what depends on the view: rank, then importance within
|
|
317
|
+
* the layer, then a street name that clears its junctions over one that
|
|
318
|
+
* would cover a crossing street, then the longer straight run. It has to be
|
|
319
|
+
* **total and stable** — the candidate's id last — because a tie broken by
|
|
320
|
+
* array order would flicker as tiles arrived in a different order.
|
|
321
|
+
*
|
|
322
|
+
* A street name fits where the GL renderer says one does: on a stretch
|
|
323
|
+
* straight enough for its size, and long enough for all of it.
|
|
277
324
|
*/
|
|
278
325
|
export function placeLabels(
|
|
279
326
|
candidates: readonly LabelCandidate[],
|
|
@@ -282,9 +329,19 @@ export function placeLabels(
|
|
|
282
329
|
options?: { padding?: number },
|
|
283
330
|
): PlacedLabel[] {
|
|
284
331
|
const padding = options?.padding ?? 2;
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
332
|
+
const clean = (c: LabelCandidate): number =>
|
|
333
|
+
c.clear * worldSize >= estimateWidth(c.text, c.size) / 2 ? 1 : 0;
|
|
334
|
+
const sorted = [...candidates]
|
|
335
|
+
.map((c) => ({ c, clean: clean(c) }))
|
|
336
|
+
.sort(
|
|
337
|
+
(a, b) =>
|
|
338
|
+
b.c.rank - a.c.rank ||
|
|
339
|
+
b.c.priority - a.c.priority ||
|
|
340
|
+
b.clean - a.clean ||
|
|
341
|
+
b.c.length - a.c.length ||
|
|
342
|
+
(a.c.id < b.c.id ? -1 : a.c.id > b.c.id ? 1 : 0),
|
|
343
|
+
)
|
|
344
|
+
.map((entry) => entry.c);
|
|
288
345
|
const placed: PlacedLabel[] = [];
|
|
289
346
|
// A sparse grid over world pixels. The cell is sized for the labels
|
|
290
347
|
// themselves, so a box touches one or two cells and a collision test is a
|
|
@@ -297,18 +354,26 @@ export function placeLabels(
|
|
|
297
354
|
const byText = new Map<string, { wx: number; wy: number }[]>();
|
|
298
355
|
|
|
299
356
|
for (const candidate of sorted) {
|
|
357
|
+
// Bent under its size at this zoom: not a stretch to set a name on.
|
|
358
|
+
if (candidate.dev * worldSize > candidate.size * STRAIGHT_FRACTION) {
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
300
361
|
const shaped = shaper.shape(
|
|
301
362
|
candidate.text,
|
|
302
363
|
candidate.size,
|
|
303
364
|
candidate.color,
|
|
304
365
|
);
|
|
305
366
|
if (!shaped) return placed; // no font manager: nothing can be measured
|
|
367
|
+
// Longer than the straight stretch it would sit on, with a margin past
|
|
368
|
+
// each end: it would hang off the street, over whatever the street
|
|
369
|
+
// turns into.
|
|
370
|
+
const need = shaped.width / 2 + shaped.height * LINE_MARGIN;
|
|
371
|
+
if (candidate.avail * worldSize < need) continue;
|
|
306
372
|
const wx = candidate.mx * worldSize;
|
|
307
373
|
const wy = candidate.my * worldSize;
|
|
308
374
|
// The repeat test before the overlap test, because it is the cheaper
|
|
309
|
-
// one and because it is what rejects most of a street layer: a
|
|
310
|
-
//
|
|
311
|
-
// strung out along the road, none of them overlapping any other.
|
|
375
|
+
// one and because it is what rejects most of a street layer: a long
|
|
376
|
+
// street offers its name every block, none of them overlapping.
|
|
312
377
|
if (candidate.repeat > 0) {
|
|
313
378
|
const already = byText.get(candidate.key);
|
|
314
379
|
if (already) {
|
|
@@ -325,8 +390,15 @@ export function placeLabels(
|
|
|
325
390
|
if (tooClose) continue;
|
|
326
391
|
}
|
|
327
392
|
}
|
|
328
|
-
|
|
329
|
-
|
|
393
|
+
// The turned text's bounding box: what it covers, as far as another
|
|
394
|
+
// label can tell.
|
|
395
|
+
const angle = levelled(candidate.angle);
|
|
396
|
+
const w = shaped.width + padding * 2;
|
|
397
|
+
const h = shaped.height + padding * 2;
|
|
398
|
+
const cos = Math.abs(Math.cos(angle));
|
|
399
|
+
const sin = Math.abs(Math.sin(angle));
|
|
400
|
+
const width = w * cos + h * sin;
|
|
401
|
+
const height = w * sin + h * cos;
|
|
330
402
|
const left = wx - width / 2;
|
|
331
403
|
const top = wy - height / 2;
|
|
332
404
|
const x0 = Math.floor(left / CELL);
|
|
@@ -354,6 +426,7 @@ export function placeLabels(
|
|
|
354
426
|
if (!free) continue;
|
|
355
427
|
const entry: PlacedLabel = {
|
|
356
428
|
...candidate,
|
|
429
|
+
angle,
|
|
357
430
|
wx,
|
|
358
431
|
wy,
|
|
359
432
|
width,
|
|
@@ -387,6 +460,10 @@ export function placeLabels(
|
|
|
387
460
|
* composites of two shaped runs. That is cheap for the few dozen labels a
|
|
388
461
|
* pane holds and it is the difference between a place name that is
|
|
389
462
|
* readable over a motorway and one that is not.
|
|
463
|
+
*
|
|
464
|
+
* A level label is drawn on whole device pixels. A street name along its
|
|
465
|
+
* street is drawn turned about its centre, where the context can turn —
|
|
466
|
+
* and level where it cannot, on a context with no transform.
|
|
390
467
|
*/
|
|
391
468
|
export function drawLabels(
|
|
392
469
|
ctx: MapCanvas,
|
|
@@ -401,28 +478,43 @@ export function drawLabels(
|
|
|
401
478
|
const world = transform.world;
|
|
402
479
|
const originX = pane.x + transform.paneX - transform.centerX * world;
|
|
403
480
|
const originY = pane.y + transform.paneY - transform.centerY * world;
|
|
481
|
+
const turns = typeof ctx.rotate === 'function' && !!ctx.translate;
|
|
404
482
|
for (const label of placed) {
|
|
405
|
-
const
|
|
406
|
-
const
|
|
483
|
+
const cx = originX + label.wx;
|
|
484
|
+
const cy = originY + label.wy;
|
|
485
|
+
const halfW = label.width / 2;
|
|
486
|
+
const halfH = label.height / 2;
|
|
407
487
|
if (
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
488
|
+
cx + halfW < pane.x ||
|
|
489
|
+
cy + halfH < pane.y ||
|
|
490
|
+
cx - halfW > pane.x + pane.width ||
|
|
491
|
+
cy - halfH > pane.y + pane.height
|
|
412
492
|
) {
|
|
413
493
|
continue;
|
|
414
494
|
}
|
|
415
495
|
if (
|
|
416
496
|
clip &&
|
|
417
|
-
(
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
497
|
+
(cx + halfW < clip.x ||
|
|
498
|
+
cy + halfH < clip.y ||
|
|
499
|
+
cx - halfW > clip.x + clip.width ||
|
|
500
|
+
cy - halfH > clip.y + clip.height)
|
|
421
501
|
) {
|
|
422
502
|
continue;
|
|
423
503
|
}
|
|
424
|
-
const
|
|
425
|
-
const
|
|
504
|
+
const { width, height } = label.shaped;
|
|
505
|
+
const turned = label.angle !== 0 && turns;
|
|
506
|
+
let dx: number;
|
|
507
|
+
let dy: number;
|
|
508
|
+
if (turned) {
|
|
509
|
+
ctx.save();
|
|
510
|
+
ctx.translate!(cx * scale, cy * scale);
|
|
511
|
+
ctx.rotate!(label.angle);
|
|
512
|
+
dx = (-width * scale) / 2;
|
|
513
|
+
dy = (-height * scale) / 2;
|
|
514
|
+
} else {
|
|
515
|
+
dx = Math.round((cx - width / 2) * scale);
|
|
516
|
+
dy = Math.round((cy - height / 2) * scale);
|
|
517
|
+
}
|
|
426
518
|
if (label.halo !== undefined && label.haloWidth > 0) {
|
|
427
519
|
const halo = shaper.shape(label.text, label.size, label.halo);
|
|
428
520
|
if (halo) {
|
|
@@ -434,6 +526,7 @@ export function drawLabels(
|
|
|
434
526
|
}
|
|
435
527
|
}
|
|
436
528
|
label.shaped.layout.draw(ctx, dx, dy);
|
|
529
|
+
if (turned) ctx.restore();
|
|
437
530
|
drawn++;
|
|
438
531
|
}
|
|
439
532
|
return drawn;
|