@sakuzu/maplibre-gl-draw 2.1.2 → 2.1.4

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.
@@ -1,3 +1,4 @@
1
+ import type { AnchoredOutlineRenderer } from '../renderers/anchored-outline.js';
1
2
  import type { FeatureDrawer } from '../renderers/drawer.js';
2
3
  import type { SDFLineRenderer } from '../renderers/line/sdf-line.js';
3
4
  import type { PointInstanceRenderer } from '../renderers/point/point-instance.js';
@@ -16,6 +17,8 @@ export interface ShaderInitializerRenderers {
16
17
  tentativeRenderer: TentativeRenderer | null;
17
18
  quadShader: QuadShader | null;
18
19
  strokeRenderer: StrokeRenderer | null;
20
+ /** The outlines laid on the screen around an anchor (the frames of points) */
21
+ outlineRenderer: AnchoredOutlineRenderer | null;
19
22
  pointShapeRenderer: PointShapeRenderer | null;
20
23
  pointInstanceRenderer: PointInstanceRenderer | null;
21
24
  sdfLineRenderer: SDFLineRenderer | null;
@@ -23,7 +23,7 @@ export class ShaderInitializer {
23
23
  * Makes every renderer ensure its shader
24
24
  */
25
25
  ensureShaders(shaderData) {
26
- const { featureDrawer, tentativeRenderer, quadShader, strokeRenderer, pointShapeRenderer, pointInstanceRenderer, sdfLineRenderer, polygonBatchRenderer, sdfPolygonRenderer, fillShaderManager, } = this.renderers;
26
+ const { featureDrawer, tentativeRenderer, quadShader, strokeRenderer, outlineRenderer, pointShapeRenderer, pointInstanceRenderer, sdfLineRenderer, polygonBatchRenderer, sdfPolygonRenderer, fillShaderManager, } = this.renderers;
27
27
  if (featureDrawer) {
28
28
  featureDrawer.ensureShader(shaderData);
29
29
  }
@@ -36,6 +36,9 @@ export class ShaderInitializer {
36
36
  if (strokeRenderer) {
37
37
  strokeRenderer.ensureShader(shaderData);
38
38
  }
39
+ if (outlineRenderer) {
40
+ outlineRenderer.ensureShader(shaderData);
41
+ }
39
42
  if (pointShapeRenderer) {
40
43
  pointShapeRenderer.ensureShader(shaderData);
41
44
  }
@@ -80,7 +83,7 @@ export class ShaderInitializer {
80
83
  * uniforms once per frame and applies them for each slot.
81
84
  */
82
85
  applyOffsetUniforms(uniforms) {
83
- const { featureDrawer, tentativeRenderer, quadShader, strokeRenderer, pointShapeRenderer, pointInstanceRenderer, sdfLineRenderer, polygonBatchRenderer, sdfPolygonRenderer, fillShaderManager, } = this.renderers;
86
+ const { featureDrawer, tentativeRenderer, quadShader, strokeRenderer, outlineRenderer, pointShapeRenderer, pointInstanceRenderer, sdfLineRenderer, polygonBatchRenderer, sdfPolygonRenderer, fillShaderManager, } = this.renderers;
84
87
  if (featureDrawer) {
85
88
  featureDrawer.setOffsetUniforms(uniforms);
86
89
  }
@@ -93,6 +96,9 @@ export class ShaderInitializer {
93
96
  if (strokeRenderer) {
94
97
  strokeRenderer.setOffsetUniforms(uniforms);
95
98
  }
99
+ if (outlineRenderer) {
100
+ outlineRenderer.setOffsetUniforms(uniforms);
101
+ }
96
102
  if (pointShapeRenderer) {
97
103
  pointShapeRenderer.setOffsetUniforms(uniforms);
98
104
  }
@@ -207,6 +207,15 @@ float dashDistance(vec2 sa, vec2 sb, float start, float len, float dash, float p
207
207
  return best;
208
208
  }
209
209
 
210
+ // The coverage of an outline of a half width at a screen distance from it. Below one
211
+ // pixel of width the outline is drawn one pixel wide and fainter by its width, so the ink
212
+ // per unit of length follows the width and goes to nothing with it (the rule of the
213
+ // vertex path's line and outline shaders)
214
+ float strokeCoverage(float halfWidth, float dist) {
215
+ float ink = clamp(2.0 * halfWidth, 0.0, 1.0);
216
+ return clamp(max(halfWidth, 0.5) + 0.5 - dist, 0.0, 1.0) * ink;
217
+ }
218
+
210
219
  // Compose on top (premultiplied alpha)
211
220
  vec4 over(vec4 below, vec3 rgb, float a) {
212
221
  return vec4(rgb * a + below.rgb * (1.0 - a), a + below.a * (1.0 - a));
@@ -342,7 +351,7 @@ void main() {
342
351
  }
343
352
 
344
353
  if (paints && halfWidth > 0.0 && stroke.a > 0.0) {
345
- float coverage = clamp(halfWidth + 0.5 - strokeDist, 0.0, 1.0);
354
+ float coverage = strokeCoverage(halfWidth, strokeDist);
346
355
  if (coverage > 0.0) acc = over(acc, stroke.rgb, stroke.a * coverage * factors.x);
347
356
  }
348
357
 
@@ -367,7 +376,7 @@ void main() {
367
376
  // for features that have no outline (the same as the immediate mode), and
368
377
  // it is solid under a dashed outline too
369
378
  float selHalf = halfWidth + u_selection_stroke_extra * 0.5;
370
- selStroke = max(selStroke, clamp(selHalf + 0.5 - minDist, 0.0, 1.0) * factors.x);
379
+ selStroke = max(selStroke, strokeCoverage(selHalf, minDist) * factors.x);
371
380
  }
372
381
  }
373
382
 
@@ -9,13 +9,14 @@ import type { ProjectionData } from 'maplibre-gl';
9
9
  import type { SelectionUIConfig } from '../../../shared/config/selection.js';
10
10
  import { type CoordinateTransform } from '../../../shared/math/index.js';
11
11
  import type { DragState, Feature } from '../../../store/types.js';
12
+ import type { AnchoredOutlineRenderer } from '../../renderers/anchored-outline.js';
12
13
  import type { StrokeRenderer } from '../../renderers/stroke.js';
13
14
  import { TerrainContext } from '../../terrain/context.js';
14
15
  import type { SelectionExtensionRegistry } from './extension-registry.js';
15
16
  import type { BoundingBoxCoords } from './types.js';
16
17
  export declare class SelectionUIRenderer {
17
18
  #private;
18
- constructor(strokeRenderer: StrokeRenderer, config: SelectionUIConfig, extensions: SelectionExtensionRegistry, terrain?: TerrainContext);
19
+ constructor(strokeRenderer: StrokeRenderer, outlineRenderer: AnchoredOutlineRenderer, config: SelectionUIConfig, extensions: SelectionExtensionRegistry, terrain?: TerrainContext);
19
20
  /** Compute the BoundingBox of a feature (also usable from outside) */
20
21
  computeFeatureBoundingBox(feature: Feature): BoundingBoxCoords | null;
21
22
  /** Compute the combined BoundingBox of several features (also usable from outside) */
@@ -11,20 +11,18 @@ 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_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;
14
+ var _SelectionUIRenderer_instances, _SelectionUIRenderer_strokeRenderer, _SelectionUIRenderer_outlineRenderer, _SelectionUIRenderer_extensions, _SelectionUIRenderer_terrain, _SelectionUIRenderer_config, _SelectionUIRenderer_transform, _SelectionUIRenderer_projectionData, _SelectionUIRenderer_drawRotatingBoundingBox, _SelectionUIRenderer_drawIndividualBoundingBox, _SelectionUIRenderer_drawBoundingBoxWithMargin, _SelectionUIRenderer_drawPointBoundingBox, _SelectionUIRenderer_pointFrame, _SelectionUIRenderer_applyMargin, _SelectionUIRenderer_strokeBoundingBox, _SelectionUIRenderer_strokePath;
15
15
  import { applyMarginToBoundingBox, } from '../../../shared/math/index.js';
16
16
  import { anchorElevationMeters, isAnchorActive, projectAnchorAt } from '../../terrain/anchor.js';
17
17
  import { TerrainContext } from '../../terrain/context.js';
18
+ import { anchorGhostOpacity } from '../../terrain/occlusion.js';
18
19
  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;
24
20
  export class SelectionUIRenderer {
25
- constructor(strokeRenderer, config, extensions, terrain = new TerrainContext()) {
21
+ constructor(strokeRenderer, outlineRenderer, config, extensions, terrain = new TerrainContext()) {
26
22
  _SelectionUIRenderer_instances.add(this);
27
23
  _SelectionUIRenderer_strokeRenderer.set(this, void 0);
24
+ /** Draws the frames of points, which are figures of the screen */
25
+ _SelectionUIRenderer_outlineRenderer.set(this, void 0);
28
26
  /** The Selection UI extension points of the draw instance this renderer belongs to */
29
27
  _SelectionUIRenderer_extensions.set(this, void 0);
30
28
  /** The terrain state of the draw instance (an inactive one projects with the map) */
@@ -33,6 +31,7 @@ export class SelectionUIRenderer {
33
31
  _SelectionUIRenderer_transform.set(this, null);
34
32
  _SelectionUIRenderer_projectionData.set(this, null);
35
33
  __classPrivateFieldSet(this, _SelectionUIRenderer_strokeRenderer, strokeRenderer, "f");
34
+ __classPrivateFieldSet(this, _SelectionUIRenderer_outlineRenderer, outlineRenderer, "f");
36
35
  __classPrivateFieldSet(this, _SelectionUIRenderer_config, config, "f");
37
36
  __classPrivateFieldSet(this, _SelectionUIRenderer_extensions, extensions, "f");
38
37
  __classPrivateFieldSet(this, _SelectionUIRenderer_terrain, terrain, "f");
@@ -87,10 +86,10 @@ export class SelectionUIRenderer {
87
86
  __classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_drawIndividualBoundingBox).call(this, feature, zoom);
88
87
  }
89
88
  }
90
- __classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_drawCombinedBoundingBox).call(this, features, zoom);
89
+ __classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_drawBoundingBoxWithMargin).call(this, features, zoom);
91
90
  }
92
91
  }
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) {
92
+ _SelectionUIRenderer_strokeRenderer = new WeakMap(), _SelectionUIRenderer_outlineRenderer = 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) {
94
93
  // When dragState.operation === 'rotate', rotateInfo always exists
95
94
  const rotateInfo = dragState.rotateInfo;
96
95
  if (!rotateInfo)
@@ -115,99 +114,32 @@ _SelectionUIRenderer_strokeRenderer = new WeakMap(), _SelectionUIRenderer_extens
115
114
  if (!bbox)
116
115
  return;
117
116
  __classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_strokeBoundingBox).call(this, __classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_applyMargin).call(this, bbox, zoom), zoom);
118
- }, _SelectionUIRenderer_drawCombinedBoundingBox = function _SelectionUIRenderer_drawCombinedBoundingBox(features, zoom) {
119
- if (!__classPrivateFieldGet(this, _SelectionUIRenderer_transform, "f")) {
120
- // The fallback when there is no transform (without a margin)
121
- const bbox = computeCombinedBoundingBox(features, __classPrivateFieldGet(this, _SelectionUIRenderer_extensions, "f"));
122
- if (bbox)
123
- __classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_strokeBoundingBox).call(this, bbox, zoom);
124
- return;
125
- }
126
- const margin = __classPrivateFieldGet(this, _SelectionUIRenderer_config, "f").boundingBox.margin;
127
- const transform = __classPrivateFieldGet(this, _SelectionUIRenderer_transform, "f");
128
- let minLng = Number.POSITIVE_INFINITY;
129
- let maxLng = Number.NEGATIVE_INFINITY;
130
- let minLat = Number.POSITIVE_INFINITY;
131
- let maxLat = Number.NEGATIVE_INFINITY;
132
- for (const feature of features) {
133
- const bbox = computeBoundingBox(feature, __classPrivateFieldGet(this, _SelectionUIRenderer_extensions, "f"));
134
- if (!bbox)
135
- continue;
136
- // A single-coordinate feature (such as Point) is computed from the extent of the
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)
140
- if (hasZeroArea(bbox)) {
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);
147
- }
148
- continue;
149
- }
150
- const marginedBbox = applyMarginToBoundingBox(bbox, margin, transform, zoom);
151
- const corners = [
152
- marginedBbox.topLeft,
153
- marginedBbox.topRight,
154
- marginedBbox.bottomRight,
155
- marginedBbox.bottomLeft,
156
- ];
157
- for (const corner of corners) {
158
- minLng = Math.min(minLng, corner[0]);
159
- maxLng = Math.max(maxLng, corner[0]);
160
- minLat = Math.min(minLat, corner[1]);
161
- maxLat = Math.max(maxLat, corner[1]);
162
- }
163
- }
164
- if (!Number.isFinite(minLng))
165
- return;
166
- const coords = [
167
- [minLng, maxLat],
168
- [maxLng, maxLat],
169
- [maxLng, minLat],
170
- [minLng, minLat],
171
- [minLng, maxLat],
172
- ];
173
- __classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_strokePath).call(this, coords, zoom);
174
117
  }, _SelectionUIRenderer_drawBoundingBoxWithMargin = function _SelectionUIRenderer_drawBoundingBoxWithMargin(features, zoom) {
175
118
  const bbox = computeCombinedBoundingBox(features, __classPrivateFieldGet(this, _SelectionUIRenderer_extensions, "f"));
176
119
  if (!bbox)
177
120
  return;
178
121
  __classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_strokeBoundingBox).call(this, __classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_applyMargin).call(this, bbox, zoom), zoom);
179
122
  }, _SelectionUIRenderer_drawPointBoundingBox = function _SelectionUIRenderer_drawPointBoundingBox(feature, coord, zoom) {
180
- const frame = __classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_pointFrame).call(this, feature, coord, zoom);
181
- if (!frame)
123
+ const frame = __classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_pointFrame).call(this, feature, coord);
124
+ const projectionData = __classPrivateFieldGet(this, _SelectionUIRenderer_projectionData, "f");
125
+ if (!frame || !projectionData)
182
126
  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) {
127
+ const { x, y } = frame.center;
128
+ __classPrivateFieldGet(this, _SelectionUIRenderer_outlineRenderer, "f").draw([coord[0], coord[1]], frame.elevationMeters, frame.corners.map((corner) => ({ x: corner.x - x, y: corner.y - y })), __classPrivateFieldGet(this, _SelectionUIRenderer_config, "f").boundingBox.stroke, anchorGhostOpacity(__classPrivateFieldGet(this, _SelectionUIRenderer_terrain, "f"), coord[0], coord[1]), zoom, projectionData);
129
+ }, _SelectionUIRenderer_pointFrame = function _SelectionUIRenderer_pointFrame(feature, coord) {
188
130
  const transform = __classPrivateFieldGet(this, _SelectionUIRenderer_transform, "f");
189
131
  if (!transform)
190
132
  return null;
191
133
  const terrain = __classPrivateFieldGet(this, _SelectionUIRenderer_terrain, "f");
192
134
  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);
135
+ const center = isAnchorActive(terrain)
136
+ ? projectAnchorAt(terrain, coord[0], coord[1], elevationMeters)
137
+ : transform.project(coord);
196
138
  if (!center)
197
139
  return null;
198
140
  const margin = __classPrivateFieldGet(this, _SelectionUIRenderer_config, "f").boundingBox.margin;
199
141
  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
206
- const at = transform.unproject(corner);
207
- return [at.lng, at.lat];
208
- });
209
- coords.push(coords[0]);
210
- return { coords, elevationMeters };
142
+ return { anchor: coord, elevationMeters, center, corners };
211
143
  }, _SelectionUIRenderer_applyMargin = function _SelectionUIRenderer_applyMargin(bbox, zoom) {
212
144
  if (!__classPrivateFieldGet(this, _SelectionUIRenderer_transform, "f"))
213
145
  return bbox;
@@ -219,49 +151,6 @@ _SelectionUIRenderer_strokeRenderer = new WeakMap(), _SelectionUIRenderer_extens
219
151
  }, _SelectionUIRenderer_strokeBoundingBox = function _SelectionUIRenderer_strokeBoundingBox(bbox, zoom) {
220
152
  const corners = [bbox.topLeft, bbox.topRight, bbox.bottomRight, bbox.bottomLeft];
221
153
  __classPrivateFieldGet(this, _SelectionUIRenderer_instances, "m", _SelectionUIRenderer_strokePath).call(this, [...corners, bbox.topLeft], zoom);
222
- }, _SelectionUIRenderer_strokePath = function _SelectionUIRenderer_strokePath(coords, zoom, placement = { followTerrain: true }) {
223
- __classPrivateFieldGet(this, _SelectionUIRenderer_strokeRenderer, "f").draw(coords, __classPrivateFieldGet(this, _SelectionUIRenderer_config, "f").boundingBox.stroke, {
224
- widthUnit: 'pixels',
225
- closed: true,
226
- followTerrain: placement.followTerrain,
227
- ...(placement.elevationMeters !== undefined && {
228
- elevationMeters: placement.elevationMeters,
229
- }),
230
- }, zoom, __classPrivateFieldGet(this, _SelectionUIRenderer_projectionData, "f") ?? undefined);
154
+ }, _SelectionUIRenderer_strokePath = function _SelectionUIRenderer_strokePath(coords, zoom) {
155
+ __classPrivateFieldGet(this, _SelectionUIRenderer_strokeRenderer, "f").draw(coords, __classPrivateFieldGet(this, _SelectionUIRenderer_config, "f").boundingBox.stroke, { widthUnit: 'pixels', closed: true, followTerrain: true }, zoom, __classPrivateFieldGet(this, _SelectionUIRenderer_projectionData, "f") ?? undefined);
231
156
  };
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
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sakuzu/maplibre-gl-draw",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
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",