1 | import browser from '../util/browser';
|
2 |
|
3 | import {Placement} from '../symbol/placement';
|
4 |
|
5 | import type Transform from '../geo/transform';
|
6 | import type StyleLayer from './style_layer';
|
7 | import type SymbolStyleLayer from './style_layer/symbol_style_layer';
|
8 | import type Tile from '../source/tile';
|
9 | import type {BucketPart} from '../symbol/placement';
|
10 |
|
11 | class LayerPlacement {
|
12 | _sortAcrossTiles: boolean;
|
13 | _currentTileIndex: number;
|
14 | _currentPartIndex: number;
|
15 | _seenCrossTileIDs: {
|
16 | [k in string | number]: boolean;
|
17 | };
|
18 | _bucketParts: Array<BucketPart>;
|
19 |
|
20 | constructor(styleLayer: SymbolStyleLayer) {
|
21 | this._sortAcrossTiles = styleLayer.layout.get('symbol-z-order') !== 'viewport-y' &&
|
22 | !styleLayer.layout.get('symbol-sort-key').isConstant();
|
23 |
|
24 | this._currentTileIndex = 0;
|
25 | this._currentPartIndex = 0;
|
26 | this._seenCrossTileIDs = {};
|
27 | this._bucketParts = [];
|
28 | }
|
29 |
|
30 | continuePlacement(tiles: Array<Tile>, placement: Placement, showCollisionBoxes: boolean, styleLayer: StyleLayer, shouldPausePlacement: () => boolean) {
|
31 |
|
32 | const bucketParts = this._bucketParts;
|
33 |
|
34 | while (this._currentTileIndex < tiles.length) {
|
35 | const tile = tiles[this._currentTileIndex];
|
36 | placement.getBucketParts(bucketParts, styleLayer, tile, this._sortAcrossTiles);
|
37 |
|
38 | this._currentTileIndex++;
|
39 | if (shouldPausePlacement()) {
|
40 | return true;
|
41 | }
|
42 | }
|
43 |
|
44 | if (this._sortAcrossTiles) {
|
45 | this._sortAcrossTiles = false;
|
46 | bucketParts.sort((a, b) => (a.sortKey as any as number) - (b.sortKey as any as number));
|
47 | }
|
48 |
|
49 | while (this._currentPartIndex < bucketParts.length) {
|
50 | const bucketPart = bucketParts[this._currentPartIndex];
|
51 | placement.placeLayerBucketPart(bucketPart, this._seenCrossTileIDs, showCollisionBoxes);
|
52 |
|
53 | this._currentPartIndex++;
|
54 | if (shouldPausePlacement()) {
|
55 | return true;
|
56 | }
|
57 | }
|
58 | return false;
|
59 | }
|
60 | }
|
61 |
|
62 | class PauseablePlacement {
|
63 | placement: Placement;
|
64 | _done: boolean;
|
65 | _currentPlacementIndex: number;
|
66 | _forceFullPlacement: boolean;
|
67 | _showCollisionBoxes: boolean;
|
68 | _inProgressLayer: LayerPlacement;
|
69 |
|
70 | constructor(
|
71 | transform: Transform,
|
72 | order: Array<string>,
|
73 | forceFullPlacement: boolean,
|
74 | showCollisionBoxes: boolean,
|
75 | fadeDuration: number,
|
76 | crossSourceCollisions: boolean,
|
77 | prevPlacement?: Placement
|
78 | ) {
|
79 | this.placement = new Placement(transform, fadeDuration, crossSourceCollisions, prevPlacement);
|
80 | this._currentPlacementIndex = order.length - 1;
|
81 | this._forceFullPlacement = forceFullPlacement;
|
82 | this._showCollisionBoxes = showCollisionBoxes;
|
83 | this._done = false;
|
84 | }
|
85 |
|
86 | isDone() {
|
87 | return this._done;
|
88 | }
|
89 |
|
90 | continuePlacement(
|
91 | order: Array<string>,
|
92 | layers: {[_: string]: StyleLayer},
|
93 | layerTiles: {[_: string]: Array<Tile>}
|
94 | ) {
|
95 | const startTime = browser.now();
|
96 |
|
97 | const shouldPausePlacement = () => {
|
98 | const elapsedTime = browser.now() - startTime;
|
99 | return this._forceFullPlacement ? false : elapsedTime > 2;
|
100 | };
|
101 |
|
102 | while (this._currentPlacementIndex >= 0) {
|
103 | const layerId = order[this._currentPlacementIndex];
|
104 | const layer = layers[layerId];
|
105 | const placementZoom = this.placement.collisionIndex.transform.zoom;
|
106 | if (layer.type === 'symbol' &&
|
107 | (!layer.minzoom || layer.minzoom <= placementZoom) &&
|
108 | (!layer.maxzoom || layer.maxzoom > placementZoom)) {
|
109 |
|
110 | if (!this._inProgressLayer) {
|
111 | this._inProgressLayer = new LayerPlacement(layer as any as SymbolStyleLayer);
|
112 | }
|
113 |
|
114 | const pausePlacement = this._inProgressLayer.continuePlacement(layerTiles[layer.source], this.placement, this._showCollisionBoxes, layer, shouldPausePlacement);
|
115 |
|
116 | if (pausePlacement) {
|
117 |
|
118 |
|
119 |
|
120 | return;
|
121 | }
|
122 |
|
123 | delete this._inProgressLayer;
|
124 | }
|
125 |
|
126 | this._currentPlacementIndex--;
|
127 | }
|
128 |
|
129 | this._done = true;
|
130 | }
|
131 |
|
132 | commit(now: number) {
|
133 | this.placement.commit(now);
|
134 | return this.placement;
|
135 | }
|
136 | }
|
137 |
|
138 | export default PauseablePlacement;
|