@sakuzu/maplibre-gl-draw 2.1.0 → 2.1.2
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/CHANGELOG.md +49 -0
- package/dist/dataset/retained.js +19 -18
- package/dist/dataset/selection.d.ts +3 -3
- package/dist/dataset/selection.js +3 -7
- package/dist/dataset/table-source.js +13 -11
- package/dist/modes/select/click-handler.d.ts +4 -1
- package/dist/modes/select/click-handler.js +17 -9
- package/dist/view/layer/custom-layer.js +2 -1
- package/dist/view/layer/drape-planner.d.ts +3 -0
- package/dist/view/layer/drape-planner.js +9 -7
- package/dist/view/layer/frame-render.js +2 -3
- package/dist/view/layer/frame-state.d.ts +3 -0
- package/dist/view/layer/frame-state.js +2 -1
- package/dist/view/layer/gl-state.d.ts +2 -3
- package/dist/view/layer/gl-state.js +2 -3
- package/dist/view/layer/renderers.js +2 -1
- package/dist/view/renderers/line/dash.d.ts +27 -0
- package/dist/view/renderers/line/dash.js +23 -12
- package/dist/view/shaders/initializer.d.ts +3 -0
- package/dist/view/shaders/initializer.js +4 -2
- package/dist/view/terrain/anchor.js +20 -1
- package/dist/view/terrain/drape/bin-store.d.ts +11 -2
- package/dist/view/terrain/drape/bin-store.js +26 -2
- package/dist/view/terrain/drape/binning.d.ts +32 -0
- package/dist/view/terrain/drape/binning.js +15 -7
- package/dist/view/terrain/drape/geometry.d.ts +27 -0
- package/dist/view/terrain/drape/geometry.js +57 -6
- package/dist/view/terrain/drape/pass.d.ts +8 -3
- package/dist/view/terrain/drape/pass.js +39 -28
- package/dist/view/terrain/drape/renderer.d.ts +13 -0
- package/dist/view/terrain/drape/renderer.js +157 -30
- package/dist/view/ui/selection-ui/renderer.d.ts +2 -1
- package/dist/view/ui/selection-ui/renderer.js +88 -25
- package/dist/view/ui/selection-ui-drawer.js +4 -8
- package/package.json +1 -1
|
@@ -11,21 +11,31 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
11
11
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
12
12
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
13
13
|
};
|
|
14
|
-
var _SelectionUIRenderer_instances, _SelectionUIRenderer_strokeRenderer, _SelectionUIRenderer_extensions, _SelectionUIRenderer_config, _SelectionUIRenderer_transform, _SelectionUIRenderer_projectionData, _SelectionUIRenderer_drawRotatingBoundingBox, _SelectionUIRenderer_drawIndividualBoundingBox, _SelectionUIRenderer_drawCombinedBoundingBox, _SelectionUIRenderer_drawBoundingBoxWithMargin, _SelectionUIRenderer_drawPointBoundingBox, _SelectionUIRenderer_applyMargin, _SelectionUIRenderer_strokeBoundingBox, _SelectionUIRenderer_strokePath;
|
|
15
|
-
import { applyMarginToBoundingBox } from '../../../shared/math/index.js';
|
|
14
|
+
var _SelectionUIRenderer_instances, _SelectionUIRenderer_strokeRenderer, _SelectionUIRenderer_extensions, _SelectionUIRenderer_terrain, _SelectionUIRenderer_config, _SelectionUIRenderer_transform, _SelectionUIRenderer_projectionData, _SelectionUIRenderer_drawRotatingBoundingBox, _SelectionUIRenderer_drawIndividualBoundingBox, _SelectionUIRenderer_drawCombinedBoundingBox, _SelectionUIRenderer_drawBoundingBoxWithMargin, _SelectionUIRenderer_drawPointBoundingBox, _SelectionUIRenderer_pointFrame, _SelectionUIRenderer_applyMargin, _SelectionUIRenderer_strokeBoundingBox, _SelectionUIRenderer_strokePath;
|
|
15
|
+
import { applyMarginToBoundingBox, } from '../../../shared/math/index.js';
|
|
16
|
+
import { anchorElevationMeters, isAnchorActive, projectAnchorAt } from '../../terrain/anchor.js';
|
|
17
|
+
import { TerrainContext } from '../../terrain/context.js';
|
|
16
18
|
import { computeBoundingBox, computeCombinedBoundingBox, hasZeroArea, rotateBoundingBox, } from './bounding-box.js';
|
|
19
|
+
/**
|
|
20
|
+
* How far the positions differ that the scale of the screen around a point is measured
|
|
21
|
+
* between, in pixels at the zoom of the frame
|
|
22
|
+
*/
|
|
23
|
+
const POINT_FRAME_PROBE_PX = 4;
|
|
17
24
|
export class SelectionUIRenderer {
|
|
18
|
-
constructor(strokeRenderer, config, extensions) {
|
|
25
|
+
constructor(strokeRenderer, config, extensions, terrain = new TerrainContext()) {
|
|
19
26
|
_SelectionUIRenderer_instances.add(this);
|
|
20
27
|
_SelectionUIRenderer_strokeRenderer.set(this, void 0);
|
|
21
28
|
/** The Selection UI extension points of the draw instance this renderer belongs to */
|
|
22
29
|
_SelectionUIRenderer_extensions.set(this, void 0);
|
|
30
|
+
/** The terrain state of the draw instance (an inactive one projects with the map) */
|
|
31
|
+
_SelectionUIRenderer_terrain.set(this, void 0);
|
|
23
32
|
_SelectionUIRenderer_config.set(this, void 0);
|
|
24
33
|
_SelectionUIRenderer_transform.set(this, null);
|
|
25
34
|
_SelectionUIRenderer_projectionData.set(this, null);
|
|
26
35
|
__classPrivateFieldSet(this, _SelectionUIRenderer_strokeRenderer, strokeRenderer, "f");
|
|
27
36
|
__classPrivateFieldSet(this, _SelectionUIRenderer_config, config, "f");
|
|
28
37
|
__classPrivateFieldSet(this, _SelectionUIRenderer_extensions, extensions, "f");
|
|
38
|
+
__classPrivateFieldSet(this, _SelectionUIRenderer_terrain, terrain, "f");
|
|
29
39
|
}
|
|
30
40
|
/** Compute the BoundingBox of a feature (also usable from outside) */
|
|
31
41
|
computeFeatureBoundingBox(feature) {
|
|
@@ -80,7 +90,7 @@ export class SelectionUIRenderer {
|
|
|
80
90
|
__classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_drawCombinedBoundingBox).call(this, features, zoom);
|
|
81
91
|
}
|
|
82
92
|
}
|
|
83
|
-
_SelectionUIRenderer_strokeRenderer = new WeakMap(), _SelectionUIRenderer_extensions = new WeakMap(), _SelectionUIRenderer_config = new WeakMap(), _SelectionUIRenderer_transform = new WeakMap(), _SelectionUIRenderer_projectionData = new WeakMap(), _SelectionUIRenderer_instances = new WeakSet(), _SelectionUIRenderer_drawRotatingBoundingBox = function _SelectionUIRenderer_drawRotatingBoundingBox(features, zoom, dragState) {
|
|
93
|
+
_SelectionUIRenderer_strokeRenderer = new WeakMap(), _SelectionUIRenderer_extensions = new WeakMap(), _SelectionUIRenderer_terrain = new WeakMap(), _SelectionUIRenderer_config = new WeakMap(), _SelectionUIRenderer_transform = new WeakMap(), _SelectionUIRenderer_projectionData = new WeakMap(), _SelectionUIRenderer_instances = new WeakSet(), _SelectionUIRenderer_drawRotatingBoundingBox = function _SelectionUIRenderer_drawRotatingBoundingBox(features, zoom, dragState) {
|
|
84
94
|
// When dragState.operation === 'rotate', rotateInfo always exists
|
|
85
95
|
const rotateInfo = dragState.rotateInfo;
|
|
86
96
|
if (!rotateInfo)
|
|
@@ -124,17 +134,16 @@ _SelectionUIRenderer_strokeRenderer = new WeakMap(), _SelectionUIRenderer_extens
|
|
|
124
134
|
if (!bbox)
|
|
125
135
|
continue;
|
|
126
136
|
// A single-coordinate feature (such as Point) is computed from the extent of the
|
|
127
|
-
// point frame + the margin
|
|
128
|
-
// other than Point can be zero-area too, e.g. a
|
|
129
|
-
// coordinates must not be treated as a Coordinate)
|
|
137
|
+
// point frame + the margin, as its own frame is (#pointFrame). The coordinate used is
|
|
138
|
+
// the center of the bbox (features other than Point can be zero-area too, e.g. a
|
|
139
|
+
// MultiPoint with a single point, so coordinates must not be treated as a Coordinate)
|
|
130
140
|
if (hasZeroArea(bbox)) {
|
|
131
|
-
const
|
|
132
|
-
for (const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
maxLat = Math.max(maxLat, at.lat);
|
|
141
|
+
const frame = __classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_pointFrame).call(this, feature, bbox.center, zoom);
|
|
142
|
+
for (const [lng, lat] of frame?.coords ?? []) {
|
|
143
|
+
minLng = Math.min(minLng, lng);
|
|
144
|
+
maxLng = Math.max(maxLng, lng);
|
|
145
|
+
minLat = Math.min(minLat, lat);
|
|
146
|
+
maxLat = Math.max(maxLat, lat);
|
|
138
147
|
}
|
|
139
148
|
continue;
|
|
140
149
|
}
|
|
@@ -168,19 +177,37 @@ _SelectionUIRenderer_strokeRenderer = new WeakMap(), _SelectionUIRenderer_extens
|
|
|
168
177
|
return;
|
|
169
178
|
__classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_strokeBoundingBox).call(this, __classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_applyMargin).call(this, bbox, zoom), zoom);
|
|
170
179
|
}, _SelectionUIRenderer_drawPointBoundingBox = function _SelectionUIRenderer_drawPointBoundingBox(feature, coord, zoom) {
|
|
171
|
-
|
|
180
|
+
const frame = __classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_pointFrame).call(this, feature, coord, zoom);
|
|
181
|
+
if (!frame)
|
|
172
182
|
return;
|
|
183
|
+
__classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_strokePath).call(this, frame.coords, zoom, {
|
|
184
|
+
elevationMeters: frame.elevationMeters,
|
|
185
|
+
followTerrain: false,
|
|
186
|
+
});
|
|
187
|
+
}, _SelectionUIRenderer_pointFrame = function _SelectionUIRenderer_pointFrame(feature, coord, zoom) {
|
|
173
188
|
const transform = __classPrivateFieldGet(this, _SelectionUIRenderer_transform, "f");
|
|
174
|
-
|
|
189
|
+
if (!transform)
|
|
190
|
+
return null;
|
|
191
|
+
const terrain = __classPrivateFieldGet(this, _SelectionUIRenderer_terrain, "f");
|
|
192
|
+
const elevationMeters = anchorElevationMeters(terrain, coord[0], coord[1]);
|
|
193
|
+
const anchored = isAnchorActive(terrain);
|
|
194
|
+
const project = (at) => anchored ? projectAnchorAt(terrain, at[0], at[1], elevationMeters) : transform.project(at);
|
|
195
|
+
const center = project(coord);
|
|
196
|
+
if (!center)
|
|
197
|
+
return null;
|
|
175
198
|
const margin = __classPrivateFieldGet(this, _SelectionUIRenderer_config, "f").boundingBox.margin;
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
199
|
+
const corners = __classPrivateFieldGet(this, _SelectionUIRenderer_extensions, "f").resolvePointFrameCorners(feature, center, margin);
|
|
200
|
+
const toPosition = anchored ? screenToPlane(project, coord, center, zoom) : null;
|
|
201
|
+
const coords = corners.map((corner) => {
|
|
202
|
+
const position = toPosition?.(corner);
|
|
203
|
+
if (position)
|
|
204
|
+
return position;
|
|
205
|
+
// No terrain, or the plane seen edge on: the corner is cast onto the map
|
|
179
206
|
const at = transform.unproject(corner);
|
|
180
207
|
return [at.lng, at.lat];
|
|
181
208
|
});
|
|
182
209
|
coords.push(coords[0]);
|
|
183
|
-
|
|
210
|
+
return { coords, elevationMeters };
|
|
184
211
|
}, _SelectionUIRenderer_applyMargin = function _SelectionUIRenderer_applyMargin(bbox, zoom) {
|
|
185
212
|
if (!__classPrivateFieldGet(this, _SelectionUIRenderer_transform, "f"))
|
|
186
213
|
return bbox;
|
|
@@ -192,13 +219,49 @@ _SelectionUIRenderer_strokeRenderer = new WeakMap(), _SelectionUIRenderer_extens
|
|
|
192
219
|
}, _SelectionUIRenderer_strokeBoundingBox = function _SelectionUIRenderer_strokeBoundingBox(bbox, zoom) {
|
|
193
220
|
const corners = [bbox.topLeft, bbox.topRight, bbox.bottomRight, bbox.bottomLeft];
|
|
194
221
|
__classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_strokePath).call(this, [...corners, bbox.topLeft], zoom);
|
|
195
|
-
}, _SelectionUIRenderer_strokePath = function _SelectionUIRenderer_strokePath(coords, zoom) {
|
|
222
|
+
}, _SelectionUIRenderer_strokePath = function _SelectionUIRenderer_strokePath(coords, zoom, placement = { followTerrain: true }) {
|
|
196
223
|
__classPrivateFieldGet(this, _SelectionUIRenderer_strokeRenderer, "f").draw(coords, __classPrivateFieldGet(this, _SelectionUIRenderer_config, "f").boundingBox.stroke, {
|
|
197
224
|
widthUnit: 'pixels',
|
|
198
225
|
closed: true,
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
226
|
+
followTerrain: placement.followTerrain,
|
|
227
|
+
...(placement.elevationMeters !== undefined && {
|
|
228
|
+
elevationMeters: placement.elevationMeters,
|
|
229
|
+
}),
|
|
203
230
|
}, zoom, __classPrivateFieldGet(this, _SelectionUIRenderer_projectionData, "f") ?? undefined);
|
|
204
231
|
};
|
|
232
|
+
/**
|
|
233
|
+
* The inverse of a projection around a point, to the first order: a point of the screen near
|
|
234
|
+
* `center` to the position whose projection it is
|
|
235
|
+
*
|
|
236
|
+
* The scale of the screen along the longitude and the latitude is measured by projecting
|
|
237
|
+
* positions a few pixels to either side of `coord`.
|
|
238
|
+
*
|
|
239
|
+
* @returns null when the projection is degenerate there (seen edge on, or a probe behind the
|
|
240
|
+
* camera)
|
|
241
|
+
*/
|
|
242
|
+
function screenToPlane(project, coord, center, zoom) {
|
|
243
|
+
const [lng, lat] = coord;
|
|
244
|
+
// Degrees of longitude per pixel at the zoom on a 512 px world, a few pixels' worth
|
|
245
|
+
const step = (360 / (512 * 2 ** zoom)) * POINT_FRAME_PROBE_PX;
|
|
246
|
+
const latStep = Math.min(step, Math.max(1e-9, (89.9 - Math.abs(lat)) / 2));
|
|
247
|
+
const east = project([lng + step, lat]);
|
|
248
|
+
const west = project([lng - step, lat]);
|
|
249
|
+
const north = project([lng, lat + latStep]);
|
|
250
|
+
const south = project([lng, lat - latStep]);
|
|
251
|
+
if (!east || !west || !north || !south)
|
|
252
|
+
return null;
|
|
253
|
+
// The screen per degree of longitude (a, c) and of latitude (b, d)
|
|
254
|
+
const a = (east.x - west.x) / (2 * step);
|
|
255
|
+
const c = (east.y - west.y) / (2 * step);
|
|
256
|
+
const b = (north.x - south.x) / (2 * latStep);
|
|
257
|
+
const d = (north.y - south.y) / (2 * latStep);
|
|
258
|
+
const det = a * d - b * c;
|
|
259
|
+
const scale = Math.max(Math.abs(a), Math.abs(b), Math.abs(c), Math.abs(d));
|
|
260
|
+
if (!Number.isFinite(det) || Math.abs(det) <= 1e-12 * scale * scale)
|
|
261
|
+
return null;
|
|
262
|
+
return (point) => {
|
|
263
|
+
const dx = point.x - center.x;
|
|
264
|
+
const dy = point.y - center.y;
|
|
265
|
+
return [lng + (d * dx - b * dy) / det, lat + (a * dy - c * dx) / det];
|
|
266
|
+
};
|
|
267
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 SAKAIDA Atsushi
|
|
2
2
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
3
|
import { THINNING_VIEWPORT_MARGIN_PX } from '../../shared/config/selection.js';
|
|
4
|
+
import { createCoordinateTransform } from '../../shared/math/index.js';
|
|
4
5
|
import { supportsVertexEditing } from '../../shared/utils/coordinates.js';
|
|
5
6
|
import { isGlobeProjection } from '../../shared/utils/map.js';
|
|
6
7
|
import { isLocallyHidden } from '../../store/local-visibility.js';
|
|
@@ -25,14 +26,9 @@ isLocked = false) {
|
|
|
25
26
|
if (pointInstanceRenderer) {
|
|
26
27
|
pointInstanceRenderer.setProjectionData(projectionData);
|
|
27
28
|
}
|
|
28
|
-
// Set the coordinate transform
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
unproject: (point) => {
|
|
32
|
-
const ll = map.unproject([point.x, point.y]);
|
|
33
|
-
return { lng: ll.lng, lat: ll.lat };
|
|
34
|
-
},
|
|
35
|
-
};
|
|
29
|
+
// Set the coordinate transform: the projection the markers are drawn with and the hit
|
|
30
|
+
// testing uses (the anchor projection while the terrain is on, the map's otherwise)
|
|
31
|
+
const coordinateTransform = createCoordinateTransform(map);
|
|
36
32
|
selectionUIRenderer.setTransform(coordinateTransform);
|
|
37
33
|
selectionUIRenderer.setProjectionData(projectionData);
|
|
38
34
|
selectionHandlesRenderer.setTransform(coordinateTransform);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sakuzu/maplibre-gl-draw",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
4
4
|
"description": "WebGL2 drawing and editing engine for MapLibre GL JS: points, lines, and polygons rendered in a custom layer, with selection, hit testing, and geometry utilities.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"maplibre",
|