maplibre-gl-layers 0.6.0 → 0.10.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/dist/index.cjs CHANGED
@@ -1,12 +1,15 @@
1
1
  "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
2
5
  /*!
3
6
  * name: maplibre-gl-layers
4
- * version: 0.6.0
7
+ * version: 0.10.0
5
8
  * description: MapLibre's layer extension library enabling the display, movement, and modification of large numbers of dynamic sprite images
6
9
  * author: Kouji Matsui (@kekyo@mi.kekyo.net)
7
10
  * license: MIT
8
11
  * repository.url: https://github.com/kekyo/maplibre-gl-layers.git
9
- * git.commit.hash: 481f544de02fd3e71a2ba6c28bbb7eeb98b49eff
12
+ * git.commit.hash: 58b99588e56fc80c6874d78a17e91a50901abc17
10
13
  */
11
14
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
12
15
  const UNLIMITED_SPRITE_SCALING_OPTIONS = {
@@ -39,6 +42,270 @@ const BETTER_TEXTURE_FILTERING_OPTIONS = {
39
42
  generateMipmaps: true,
40
43
  maxAnisotropy: 8
41
44
  };
45
+ class SvgSizeResolutionError extends Error {
46
+ constructor(message, code) {
47
+ super(message);
48
+ __publicField(this, "code");
49
+ this.name = "SvgSizeResolutionError";
50
+ this.code = code;
51
+ }
52
+ }
53
+ const parseNumericLength = (value) => {
54
+ if (!value) {
55
+ return void 0;
56
+ }
57
+ const trimmed = value.trim();
58
+ if (trimmed.length === 0) {
59
+ return void 0;
60
+ }
61
+ const parsed = Number.parseFloat(trimmed);
62
+ if (!Number.isFinite(parsed) || parsed <= 0) {
63
+ return void 0;
64
+ }
65
+ return parsed;
66
+ };
67
+ const extractStyleLength = (styleValue, property) => {
68
+ if (!styleValue) {
69
+ return void 0;
70
+ }
71
+ const declarations = styleValue.split(";").map((decl) => decl.trim()).filter((decl) => decl.length > 0);
72
+ for (const declaration of declarations) {
73
+ const [prop, rawValue] = declaration.split(":");
74
+ if (!prop || !rawValue) {
75
+ continue;
76
+ }
77
+ if (prop.trim().toLowerCase() === property) {
78
+ return parseNumericLength(rawValue);
79
+ }
80
+ }
81
+ return void 0;
82
+ };
83
+ const parseSvgSize = (svgText) => {
84
+ try {
85
+ const doc = new DOMParser().parseFromString(svgText, "image/svg+xml");
86
+ const svg = doc.documentElement;
87
+ if (!svg || svg.tagName.toLowerCase() !== "svg") {
88
+ return { hasViewBox: false };
89
+ }
90
+ const attrWidth = parseNumericLength(svg.getAttribute("width"));
91
+ const attrHeight = parseNumericLength(svg.getAttribute("height"));
92
+ const styleWidth = extractStyleLength(svg.getAttribute("style"), "width");
93
+ const styleHeight = extractStyleLength(svg.getAttribute("style"), "height");
94
+ const width = attrWidth != null ? attrWidth : styleWidth;
95
+ const height = attrHeight != null ? attrHeight : styleHeight;
96
+ let viewBoxWidth;
97
+ let viewBoxHeight;
98
+ let hasViewBox = false;
99
+ const viewBox = svg.getAttribute("viewBox");
100
+ if (viewBox) {
101
+ const parts = viewBox.split(/[\s,]+/).map((part) => Number.parseFloat(part)).filter((part) => Number.isFinite(part));
102
+ if (parts.length === 4) {
103
+ viewBoxWidth = parts[2];
104
+ viewBoxHeight = parts[3];
105
+ if (viewBoxWidth > 0 && viewBoxHeight > 0) {
106
+ hasViewBox = true;
107
+ } else {
108
+ viewBoxWidth = void 0;
109
+ viewBoxHeight = void 0;
110
+ }
111
+ }
112
+ }
113
+ return {
114
+ width: width !== void 0 && width > 0 ? width : void 0,
115
+ height: height !== void 0 && height > 0 ? height : void 0,
116
+ viewBoxWidth,
117
+ viewBoxHeight,
118
+ hasViewBox
119
+ };
120
+ } catch (e) {
121
+ return { hasViewBox: false };
122
+ }
123
+ };
124
+ const determineSvgRasterDimensions = (parsed, options) => {
125
+ var _a, _b;
126
+ const overrideWidth = options == null ? void 0 : options.width;
127
+ const overrideHeight = options == null ? void 0 : options.height;
128
+ if (overrideWidth !== void 0 && overrideHeight !== void 0 && overrideWidth > 0 && overrideHeight > 0) {
129
+ return {
130
+ width: Math.max(1, Math.round(overrideWidth)),
131
+ height: Math.max(1, Math.round(overrideHeight))
132
+ };
133
+ }
134
+ const intrinsicWidth = parsed == null ? void 0 : parsed.width;
135
+ const intrinsicHeight = parsed == null ? void 0 : parsed.height;
136
+ const hasValidViewBox = Boolean(
137
+ (parsed == null ? void 0 : parsed.hasViewBox) && parsed.viewBoxWidth !== void 0 && parsed.viewBoxHeight !== void 0 && parsed.viewBoxWidth > 0 && parsed.viewBoxHeight > 0
138
+ );
139
+ const viewBoxAspect = hasValidViewBox ? parsed.viewBoxWidth / parsed.viewBoxHeight : void 0;
140
+ let baseWidth;
141
+ let baseHeight;
142
+ let aspect = intrinsicWidth !== void 0 && intrinsicHeight !== void 0 && intrinsicHeight > 0 ? intrinsicWidth / intrinsicHeight : viewBoxAspect;
143
+ if (intrinsicWidth !== void 0 && intrinsicWidth > 0 && intrinsicHeight !== void 0 && intrinsicHeight > 0) {
144
+ baseWidth = intrinsicWidth;
145
+ baseHeight = intrinsicHeight;
146
+ } else if (intrinsicWidth !== void 0 && intrinsicWidth > 0 && aspect !== void 0) {
147
+ baseWidth = intrinsicWidth;
148
+ baseHeight = intrinsicWidth / aspect;
149
+ } else if (intrinsicHeight !== void 0 && intrinsicHeight > 0 && aspect !== void 0) {
150
+ baseHeight = intrinsicHeight;
151
+ baseWidth = intrinsicHeight * aspect;
152
+ } else if (hasValidViewBox && ((_a = options == null ? void 0 : options.svg) == null ? void 0 : _a.useViewBoxDimensions)) {
153
+ baseWidth = parsed.viewBoxWidth;
154
+ baseHeight = parsed.viewBoxHeight;
155
+ aspect = baseWidth / baseHeight;
156
+ }
157
+ if ((baseWidth === void 0 || baseHeight === void 0) && hasValidViewBox && !((_b = options == null ? void 0 : options.svg) == null ? void 0 : _b.useViewBoxDimensions)) {
158
+ throw new SvgSizeResolutionError(
159
+ "SVG width/height attributes are missing and useViewBoxDimensions option is disabled.",
160
+ "viewbox-disabled"
161
+ );
162
+ }
163
+ if (baseWidth === void 0 || baseHeight === void 0) {
164
+ throw new SvgSizeResolutionError(
165
+ "SVG image lacks sufficient sizing information.",
166
+ "size-missing"
167
+ );
168
+ }
169
+ aspect = aspect != null ? aspect : baseWidth / baseHeight;
170
+ let finalWidth = baseWidth;
171
+ let finalHeight = baseHeight;
172
+ if (overrideWidth !== void 0 && overrideWidth > 0) {
173
+ finalWidth = overrideWidth;
174
+ if (overrideHeight === void 0) {
175
+ if (aspect === void 0) {
176
+ throw new SvgSizeResolutionError(
177
+ "Unable to infer SVG height from width; aspect ratio is undefined.",
178
+ "invalid-dimensions"
179
+ );
180
+ }
181
+ finalHeight = finalWidth / aspect;
182
+ }
183
+ }
184
+ if (overrideHeight !== void 0 && overrideHeight > 0) {
185
+ finalHeight = overrideHeight;
186
+ if (overrideWidth === void 0) {
187
+ if (aspect === void 0) {
188
+ throw new SvgSizeResolutionError(
189
+ "Unable to infer SVG width from height; aspect ratio is undefined.",
190
+ "invalid-dimensions"
191
+ );
192
+ }
193
+ finalWidth = finalHeight * aspect;
194
+ }
195
+ }
196
+ if (!Number.isFinite(finalWidth) || !Number.isFinite(finalHeight) || finalWidth <= 0 || finalHeight <= 0) {
197
+ throw new SvgSizeResolutionError(
198
+ "Resolved SVG dimensions are invalid.",
199
+ "invalid-dimensions"
200
+ );
201
+ }
202
+ return {
203
+ width: Math.max(1, Math.round(finalWidth)),
204
+ height: Math.max(1, Math.round(finalHeight))
205
+ };
206
+ };
207
+ const isSvgMimeType = (mimeType) => {
208
+ if (!mimeType) {
209
+ return false;
210
+ }
211
+ return mimeType.toLowerCase().includes("image/svg");
212
+ };
213
+ const rasterizeSvgWithCanvas = async (blob, width, height, options) => {
214
+ if (typeof document === "undefined") {
215
+ throw new Error(
216
+ "SVG rasterization fallback requires a browser environment"
217
+ );
218
+ }
219
+ const blobUrl = URL.createObjectURL(blob);
220
+ try {
221
+ const image = await new Promise((resolve, reject) => {
222
+ const element = new Image();
223
+ element.onload = () => resolve(element);
224
+ element.onerror = () => reject(new Error("Failed to load SVG for rasterization"));
225
+ element.src = blobUrl;
226
+ });
227
+ const canvas = document.createElement("canvas");
228
+ canvas.width = width;
229
+ canvas.height = height;
230
+ const ctx = canvas.getContext("2d");
231
+ if (!ctx) {
232
+ throw new Error("Failed to acquire 2D context for SVG rasterization");
233
+ }
234
+ ctx.clearRect(0, 0, width, height);
235
+ ctx.imageSmoothingEnabled = true;
236
+ if ((options == null ? void 0 : options.resizeQuality) === "pixelated") {
237
+ ctx.imageSmoothingEnabled = false;
238
+ } else if (options == null ? void 0 : options.resizeQuality) {
239
+ ctx.imageSmoothingQuality = options.resizeQuality;
240
+ }
241
+ ctx.drawImage(image, 0, 0, width, height);
242
+ try {
243
+ return await createImageBitmap(canvas);
244
+ } catch (e) {
245
+ const canvasBlob = await new Promise((resolve, reject) => {
246
+ canvas.toBlob((result) => {
247
+ if (result) {
248
+ resolve(result);
249
+ } else {
250
+ reject(
251
+ new Error("Failed to convert canvas to blob during rasterization")
252
+ );
253
+ }
254
+ });
255
+ });
256
+ return await createImageBitmap(canvasBlob);
257
+ }
258
+ } finally {
259
+ URL.revokeObjectURL(blobUrl);
260
+ }
261
+ };
262
+ const resolveSvgBitmapWithFallback = async (blob, width, height, options) => {
263
+ const bitmapOptions = {
264
+ resizeWidth: width,
265
+ resizeHeight: height
266
+ };
267
+ if (options == null ? void 0 : options.resizeQuality) {
268
+ bitmapOptions.resizeQuality = options.resizeQuality;
269
+ }
270
+ try {
271
+ return await createImageBitmap(blob, bitmapOptions);
272
+ } catch (error) {
273
+ return await rasterizeSvgWithCanvas(blob, width, height, options);
274
+ }
275
+ };
276
+ const internalReadImageBitmap = async (blob, shouldTreatAsSvg, options) => {
277
+ const svgOptions = options == null ? void 0 : options.svg;
278
+ if (shouldTreatAsSvg) {
279
+ let parsed = null;
280
+ if ((svgOptions == null ? void 0 : svgOptions.inspectSize) !== false) {
281
+ const text = await blob.text();
282
+ parsed = parseSvgSize(text);
283
+ }
284
+ const { width, height } = determineSvgRasterDimensions(parsed, options);
285
+ return await resolveSvgBitmapWithFallback(blob, width, height, options);
286
+ }
287
+ return await createImageBitmap(blob, {
288
+ resizeWidth: options == null ? void 0 : options.width,
289
+ resizeHeight: options == null ? void 0 : options.height,
290
+ resizeQuality: options == null ? void 0 : options.resizeQuality
291
+ });
292
+ };
293
+ const readImageBitmap = (blob, options) => {
294
+ const svgOptions = options == null ? void 0 : options.svg;
295
+ const shouldTreatAsSvg = (svgOptions == null ? void 0 : svgOptions.assumeSvg) === true;
296
+ return internalReadImageBitmap(blob, shouldTreatAsSvg, options);
297
+ };
298
+ const loadImageBitmap = async (url, options) => {
299
+ var _a;
300
+ const response = await fetch(url);
301
+ if (!response.ok) {
302
+ throw new Error(`Failed to fetch image from ${url}`);
303
+ }
304
+ const mimeType = response.headers.get("content-type");
305
+ const blob = await response.blob();
306
+ const shouldTreatAsSvg = ((_a = options == null ? void 0 : options.svg) == null ? void 0 : _a.assumeSvg) === true || isSvgMimeType(mimeType);
307
+ return await internalReadImageBitmap(blob, shouldTreatAsSvg, options);
308
+ };
42
309
  var maplibreGl$1 = { exports: {} };
43
310
  /**
44
311
  * MapLibre GL JS
@@ -21113,14 +21380,6 @@ function transformMat4(out, a, m) {
21113
21380
  return a;
21114
21381
  };
21115
21382
  })();
21116
- const loadImageBitmap = async (url) => {
21117
- const response = await fetch(url);
21118
- if (!response.ok) {
21119
- throw new Error(`Failed to fetch image from ${url}`);
21120
- }
21121
- const blob = await response.blob();
21122
- return await createImageBitmap(blob);
21123
- };
21124
21383
  const cloneSpriteLocation = (location2) => {
21125
21384
  if (location2.z === void 0) {
21126
21385
  return { lng: location2.lng, lat: location2.lat };
@@ -21177,7 +21436,7 @@ const computeFeedforwardTarget = (previous, next) => {
21177
21436
  }
21178
21437
  return target;
21179
21438
  };
21180
- const normaliseOptions$1 = (options) => {
21439
+ const normalizeOptions$2 = (options) => {
21181
21440
  var _a;
21182
21441
  return {
21183
21442
  durationMs: Math.max(0, options.durationMs),
@@ -21187,7 +21446,7 @@ const normaliseOptions$1 = (options) => {
21187
21446
  };
21188
21447
  const createInterpolationState = (params) => {
21189
21448
  const { currentLocation, lastCommandLocation, nextCommandLocation } = params;
21190
- const options = normaliseOptions$1(params.options);
21449
+ const options = normalizeOptions$2(params.options);
21191
21450
  const from = cloneSpriteLocation(currentLocation);
21192
21451
  const easing = resolveEasing(options.easing);
21193
21452
  let to;
@@ -21232,8 +21491,8 @@ const evaluateInterpolation = (params) => {
21232
21491
  };
21233
21492
  };
21234
21493
  const NUMERIC_EPSILON = 1e-6;
21235
- const normaliseDuration = (durationMs) => Number.isFinite(durationMs) && durationMs > 0 ? durationMs : 0;
21236
- const normaliseDelta = (delta) => {
21494
+ const normalizeDuration$1 = (durationMs) => Number.isFinite(durationMs) && durationMs > 0 ? durationMs : 0;
21495
+ const normalizeDelta = (delta) => {
21237
21496
  if (!Number.isFinite(delta)) {
21238
21497
  return 0;
21239
21498
  }
@@ -21245,16 +21504,24 @@ const normaliseDelta = (delta) => {
21245
21504
  }
21246
21505
  return adjusted;
21247
21506
  };
21248
- const normaliseOptions = (options) => {
21507
+ const normalizeOptions$1 = (options) => {
21508
+ var _a;
21249
21509
  return {
21250
- durationMs: normaliseDuration(options.durationMs),
21251
- easing: resolveEasing(options.easing)
21510
+ durationMs: normalizeDuration$1(options.durationMs),
21511
+ easing: resolveEasing(options.easing),
21512
+ mode: (_a = options.mode) != null ? _a : "feedback"
21252
21513
  };
21253
21514
  };
21254
- const createNumericInterpolationState = (params) => {
21515
+ const createDegreeInterpolationState = (params) => {
21255
21516
  const { currentValue, targetValue } = params;
21256
- const options = normaliseOptions(params.options);
21257
- const delta = normaliseDelta(targetValue - currentValue);
21517
+ const options = normalizeOptions$1(params.options);
21518
+ let effectiveTarget = targetValue;
21519
+ const previousCommand = params.previousCommandValue;
21520
+ if (options.mode === "feedforward" && previousCommand !== void 0 && Number.isFinite(previousCommand)) {
21521
+ const commandDelta = normalizeDelta(targetValue - previousCommand);
21522
+ effectiveTarget = targetValue + commandDelta;
21523
+ }
21524
+ const delta = normalizeDelta(effectiveTarget - currentValue);
21258
21525
  const pathTarget = currentValue + delta;
21259
21526
  const requiresInterpolation = options.durationMs > 0 && Math.abs(delta) > NUMERIC_EPSILON;
21260
21527
  const state = {
@@ -21262,7 +21529,7 @@ const createNumericInterpolationState = (params) => {
21262
21529
  easing: options.easing,
21263
21530
  from: currentValue,
21264
21531
  to: pathTarget,
21265
- finalValue: targetValue,
21532
+ finalValue: effectiveTarget,
21266
21533
  startTimestamp: -1
21267
21534
  };
21268
21535
  return {
@@ -21270,7 +21537,7 @@ const createNumericInterpolationState = (params) => {
21270
21537
  requiresInterpolation
21271
21538
  };
21272
21539
  };
21273
- const clamp01 = (value) => {
21540
+ const clamp01$1 = (value) => {
21274
21541
  if (!Number.isFinite(value)) {
21275
21542
  return 1;
21276
21543
  }
@@ -21282,7 +21549,7 @@ const clamp01 = (value) => {
21282
21549
  }
21283
21550
  return value;
21284
21551
  };
21285
- const evaluateNumericInterpolation = (params) => {
21552
+ const evaluateDegreeInterpolation = (params) => {
21286
21553
  const { state } = params;
21287
21554
  const timestamp = Number.isFinite(params.timestamp) ? params.timestamp : Date.now();
21288
21555
  const duration = Math.max(0, state.durationMs);
@@ -21296,7 +21563,7 @@ const evaluateNumericInterpolation = (params) => {
21296
21563
  }
21297
21564
  const elapsed = timestamp - effectiveStart;
21298
21565
  const rawProgress = duration <= 0 ? 1 : elapsed / duration;
21299
- const eased = clamp01(state.easing(rawProgress));
21566
+ const eased = clamp01$1(state.easing(rawProgress));
21300
21567
  const interpolated = state.from + (state.to - state.from) * eased;
21301
21568
  const completed = rawProgress >= 1;
21302
21569
  return {
@@ -21305,7 +21572,7 @@ const evaluateNumericInterpolation = (params) => {
21305
21572
  effectiveStartTimestamp: effectiveStart
21306
21573
  };
21307
21574
  };
21308
- const normaliseAngleDeg = (angle) => {
21575
+ const normalizeAngleDeg = (angle) => {
21309
21576
  if (!Number.isFinite(angle)) {
21310
21577
  return 0;
21311
21578
  }
@@ -21315,17 +21582,19 @@ const normaliseAngleDeg = (angle) => {
21315
21582
  };
21316
21583
  const resolveRotationTarget = (params) => {
21317
21584
  const options = params.options;
21318
- const targetAngle = normaliseAngleDeg(params.targetAngleDeg);
21319
- const currentAngle = normaliseAngleDeg(params.currentAngleDeg);
21585
+ const targetAngle = normalizeAngleDeg(params.targetAngleDeg);
21586
+ const currentAngle = normalizeAngleDeg(params.currentAngleDeg);
21587
+ const previousCommandAngleDeg = params.previousCommandAngleDeg !== void 0 ? normalizeAngleDeg(params.previousCommandAngleDeg) : void 0;
21320
21588
  if (!options || options.durationMs <= 0) {
21321
21589
  return {
21322
21590
  nextAngleDeg: targetAngle,
21323
21591
  interpolationState: null
21324
21592
  };
21325
21593
  }
21326
- const { state, requiresInterpolation } = createNumericInterpolationState({
21594
+ const { state, requiresInterpolation } = createDegreeInterpolationState({
21327
21595
  currentValue: currentAngle,
21328
21596
  targetValue: targetAngle,
21597
+ previousCommandValue: previousCommandAngleDeg,
21329
21598
  options
21330
21599
  });
21331
21600
  if (!requiresInterpolation) {
@@ -22005,6 +22274,243 @@ const calculateSurfaceCornerDisplacements = (params) => {
22005
22274
  }
22006
22275
  return corners;
22007
22276
  };
22277
+ const DISTANCE_EPSILON = 1e-6;
22278
+ const normalizeDuration = (durationMs) => Number.isFinite(durationMs) && durationMs > 0 ? durationMs : 0;
22279
+ const normalizeOptions = (options) => {
22280
+ var _a;
22281
+ return {
22282
+ durationMs: normalizeDuration(options.durationMs),
22283
+ easing: resolveEasing(options.easing),
22284
+ mode: (_a = options.mode) != null ? _a : "feedback"
22285
+ };
22286
+ };
22287
+ const createDistanceInterpolationState = (params) => {
22288
+ const { currentValue, targetValue } = params;
22289
+ const options = normalizeOptions(params.options);
22290
+ let effectiveTarget = targetValue;
22291
+ const previousCommand = params.previousCommandValue;
22292
+ if (options.mode === "feedforward" && previousCommand !== void 0 && Number.isFinite(previousCommand)) {
22293
+ const commandDelta = targetValue - previousCommand;
22294
+ effectiveTarget = targetValue + commandDelta;
22295
+ }
22296
+ const delta = effectiveTarget - currentValue;
22297
+ const requiresInterpolation = options.durationMs > 0 && Math.abs(delta) > DISTANCE_EPSILON;
22298
+ const state = {
22299
+ durationMs: options.durationMs,
22300
+ easing: options.easing,
22301
+ from: currentValue,
22302
+ to: currentValue + delta,
22303
+ finalValue: effectiveTarget,
22304
+ startTimestamp: -1
22305
+ };
22306
+ return {
22307
+ state,
22308
+ requiresInterpolation
22309
+ };
22310
+ };
22311
+ const clamp01 = (value) => {
22312
+ if (!Number.isFinite(value)) {
22313
+ return 1;
22314
+ }
22315
+ if (value <= 0) {
22316
+ return 0;
22317
+ }
22318
+ if (value >= 1) {
22319
+ return 1;
22320
+ }
22321
+ return value;
22322
+ };
22323
+ const evaluateDistanceInterpolation = (params) => {
22324
+ const { state } = params;
22325
+ const timestamp = Number.isFinite(params.timestamp) ? params.timestamp : Date.now();
22326
+ const duration = Math.max(0, state.durationMs);
22327
+ const effectiveStart = state.startTimestamp >= 0 ? state.startTimestamp : timestamp;
22328
+ if (duration === 0 || Math.abs(state.to - state.from) <= DISTANCE_EPSILON) {
22329
+ return {
22330
+ value: state.finalValue,
22331
+ completed: true,
22332
+ effectiveStartTimestamp: effectiveStart
22333
+ };
22334
+ }
22335
+ const elapsed = timestamp - effectiveStart;
22336
+ const rawProgress = duration <= 0 ? 1 : elapsed / duration;
22337
+ const eased = clamp01(state.easing(rawProgress));
22338
+ const interpolated = state.from + (state.to - state.from) * eased;
22339
+ const completed = rawProgress >= 1;
22340
+ return {
22341
+ value: completed ? state.finalValue : interpolated,
22342
+ completed,
22343
+ effectiveStartTimestamp: effectiveStart
22344
+ };
22345
+ };
22346
+ const stepDegreeInterpolationState = (interpolationState, timestamp, applyValue, options) => {
22347
+ var _a, _b;
22348
+ if (!interpolationState) {
22349
+ return { state: null, active: false };
22350
+ }
22351
+ const evaluation = evaluateDegreeInterpolation({
22352
+ state: interpolationState,
22353
+ timestamp
22354
+ });
22355
+ if (interpolationState.startTimestamp < 0) {
22356
+ interpolationState.startTimestamp = evaluation.effectiveStartTimestamp;
22357
+ }
22358
+ const normalizeValue = (_a = options == null ? void 0 : options.normalize) != null ? _a : ((value) => value);
22359
+ const applyFinalValue = (_b = options == null ? void 0 : options.applyFinalValue) != null ? _b : applyValue;
22360
+ const interpolatedValue = normalizeValue(evaluation.value);
22361
+ applyValue(interpolatedValue);
22362
+ if (evaluation.completed) {
22363
+ const finalValue = normalizeValue(interpolationState.finalValue);
22364
+ applyFinalValue(finalValue);
22365
+ return { state: null, active: false };
22366
+ }
22367
+ return { state: interpolationState, active: true };
22368
+ };
22369
+ const updateImageDisplayedRotation = (image, optionsOverride) => {
22370
+ const targetAngle = normalizeAngleDeg(
22371
+ image.resolvedBaseRotateDeg + image.rotateDeg
22372
+ );
22373
+ const currentAngle = Number.isFinite(image.displayedRotateDeg) ? image.displayedRotateDeg : targetAngle;
22374
+ const previousCommandAngle = image.lastCommandRotateDeg;
22375
+ const options = optionsOverride === void 0 ? image.rotationInterpolationOptions : optionsOverride;
22376
+ const { nextAngleDeg, interpolationState } = resolveRotationTarget({
22377
+ currentAngleDeg: currentAngle,
22378
+ targetAngleDeg: targetAngle,
22379
+ previousCommandAngleDeg: previousCommandAngle,
22380
+ options: options != null ? options : void 0
22381
+ });
22382
+ image.displayedRotateDeg = nextAngleDeg;
22383
+ image.rotationInterpolationState = interpolationState;
22384
+ if (!interpolationState) {
22385
+ image.displayedRotateDeg = targetAngle;
22386
+ }
22387
+ image.lastCommandRotateDeg = targetAngle;
22388
+ };
22389
+ const syncImageRotationChannel = (image, optionsOverride) => {
22390
+ updateImageDisplayedRotation(image, optionsOverride);
22391
+ };
22392
+ const stepRotationInterpolation = (image, timestamp) => {
22393
+ const { state, active } = stepDegreeInterpolationState(
22394
+ image.rotationInterpolationState,
22395
+ timestamp,
22396
+ (value) => {
22397
+ image.displayedRotateDeg = value;
22398
+ },
22399
+ {
22400
+ normalize: normalizeAngleDeg
22401
+ }
22402
+ );
22403
+ image.rotationInterpolationState = state;
22404
+ return active;
22405
+ };
22406
+ const stepOffsetDegInterpolation = (image, timestamp) => {
22407
+ const { state, active } = stepDegreeInterpolationState(
22408
+ image.offsetDegInterpolationState,
22409
+ timestamp,
22410
+ (value) => {
22411
+ image.offset.offsetDeg = value;
22412
+ }
22413
+ );
22414
+ image.offsetDegInterpolationState = state;
22415
+ return active;
22416
+ };
22417
+ const clearOffsetDegInterpolation = (image) => {
22418
+ image.offsetDegInterpolationState = null;
22419
+ };
22420
+ const stepDistanceInterpolationState = (interpolationState, timestamp, applyValue) => {
22421
+ if (!interpolationState) {
22422
+ return { state: null, active: false };
22423
+ }
22424
+ const evaluation = evaluateDistanceInterpolation({
22425
+ state: interpolationState,
22426
+ timestamp
22427
+ });
22428
+ if (interpolationState.startTimestamp < 0) {
22429
+ interpolationState.startTimestamp = evaluation.effectiveStartTimestamp;
22430
+ }
22431
+ applyValue(evaluation.value);
22432
+ if (evaluation.completed) {
22433
+ applyValue(interpolationState.finalValue);
22434
+ return { state: null, active: false };
22435
+ }
22436
+ return { state: interpolationState, active: true };
22437
+ };
22438
+ const clearOffsetMetersInterpolation = (image) => {
22439
+ image.offsetMetersInterpolationState = null;
22440
+ };
22441
+ const applyOffsetDegUpdate = (image, nextOffset, interpolationOptions) => {
22442
+ const options = interpolationOptions;
22443
+ if (!options || options.durationMs <= 0) {
22444
+ image.offset.offsetDeg = nextOffset.offsetDeg;
22445
+ image.offsetDegInterpolationState = null;
22446
+ image.lastCommandOffsetDeg = nextOffset.offsetDeg;
22447
+ return;
22448
+ }
22449
+ const { state, requiresInterpolation } = createDegreeInterpolationState({
22450
+ currentValue: image.offset.offsetDeg,
22451
+ targetValue: nextOffset.offsetDeg,
22452
+ previousCommandValue: image.lastCommandOffsetDeg,
22453
+ options
22454
+ });
22455
+ image.lastCommandOffsetDeg = nextOffset.offsetDeg;
22456
+ if (requiresInterpolation) {
22457
+ image.offsetDegInterpolationState = state;
22458
+ } else {
22459
+ image.offset.offsetDeg = nextOffset.offsetDeg;
22460
+ image.offsetDegInterpolationState = null;
22461
+ }
22462
+ };
22463
+ const applyOffsetMetersUpdate = (image, nextOffset, interpolationOptions) => {
22464
+ const options = interpolationOptions;
22465
+ if (!options || options.durationMs <= 0) {
22466
+ image.offset.offsetMeters = nextOffset.offsetMeters;
22467
+ image.offsetMetersInterpolationState = null;
22468
+ image.lastCommandOffsetMeters = nextOffset.offsetMeters;
22469
+ return;
22470
+ }
22471
+ const { state, requiresInterpolation } = createDistanceInterpolationState({
22472
+ currentValue: image.offset.offsetMeters,
22473
+ targetValue: nextOffset.offsetMeters,
22474
+ previousCommandValue: image.lastCommandOffsetMeters,
22475
+ options
22476
+ });
22477
+ image.lastCommandOffsetMeters = nextOffset.offsetMeters;
22478
+ if (requiresInterpolation) {
22479
+ image.offsetMetersInterpolationState = state;
22480
+ } else {
22481
+ image.offset.offsetMeters = nextOffset.offsetMeters;
22482
+ image.offsetMetersInterpolationState = null;
22483
+ }
22484
+ };
22485
+ const stepOffsetMetersInterpolation = (image, timestamp) => {
22486
+ const { state, active } = stepDistanceInterpolationState(
22487
+ image.offsetMetersInterpolationState,
22488
+ timestamp,
22489
+ (value) => {
22490
+ image.offset.offsetMeters = value;
22491
+ }
22492
+ );
22493
+ image.offsetMetersInterpolationState = state;
22494
+ return active;
22495
+ };
22496
+ const IMAGE_INTERPOLATION_STEPPERS = [
22497
+ stepRotationInterpolation,
22498
+ stepOffsetDegInterpolation,
22499
+ stepOffsetMetersInterpolation
22500
+ ];
22501
+ const stepSpriteImageInterpolations = (image, timestamp) => {
22502
+ let active = false;
22503
+ for (const stepper of IMAGE_INTERPOLATION_STEPPERS) {
22504
+ if (stepper(image, timestamp)) {
22505
+ active = true;
22506
+ }
22507
+ }
22508
+ return active;
22509
+ };
22510
+ const applyOffsetUpdate = (image, nextOffset, options = {}) => {
22511
+ applyOffsetDegUpdate(image, nextOffset, options.deg);
22512
+ applyOffsetMetersUpdate(image, nextOffset, options.meters);
22513
+ };
22008
22514
  const DEFAULT_ANCHOR = { x: 0, y: 0 };
22009
22515
  const DEFAULT_AUTO_ROTATION_MIN_DISTANCE_METERS = 20;
22010
22516
  const DEFAULT_IMAGE_OFFSET = {
@@ -22222,14 +22728,14 @@ const applyAutoRotation = (sprite, nextLocation) => {
22222
22728
  return false;
22223
22729
  }
22224
22730
  const resolvedAngleRaw = isFiniteNumber(bearingDeg) ? bearingDeg : sprite.lastAutoRotationAngleDeg;
22225
- const resolvedAngle = normaliseAngleDeg(resolvedAngleRaw);
22731
+ const resolvedAngle = normalizeAngleDeg(resolvedAngleRaw);
22226
22732
  sprite.images.forEach((orderMap) => {
22227
22733
  orderMap.forEach((image) => {
22228
22734
  if (!image.autoRotation) {
22229
22735
  return;
22230
22736
  }
22231
22737
  image.resolvedBaseRotateDeg = resolvedAngle;
22232
- updateImageDisplayedRotation(image);
22738
+ syncImageRotationChannel(image);
22233
22739
  });
22234
22740
  });
22235
22741
  sprite.lastAutoRotationLocation = cloneSpriteLocation(nextLocation);
@@ -22665,23 +23171,6 @@ const cloneOffset = (offset) => {
22665
23171
  offsetDeg: offset.offsetDeg
22666
23172
  };
22667
23173
  };
22668
- const updateImageDisplayedRotation = (image, optionsOverride) => {
22669
- const targetAngle = normaliseAngleDeg(
22670
- image.resolvedBaseRotateDeg + image.rotateDeg
22671
- );
22672
- const currentAngle = Number.isFinite(image.displayedRotateDeg) ? image.displayedRotateDeg : targetAngle;
22673
- const options = optionsOverride === void 0 ? image.rotationInterpolationOptions : optionsOverride;
22674
- const { nextAngleDeg, interpolationState } = resolveRotationTarget({
22675
- currentAngleDeg: currentAngle,
22676
- targetAngleDeg: targetAngle,
22677
- options: options != null ? options : void 0
22678
- });
22679
- image.displayedRotateDeg = nextAngleDeg;
22680
- image.rotationInterpolationState = interpolationState;
22681
- if (!interpolationState) {
22682
- image.displayedRotateDeg = targetAngle;
22683
- }
22684
- };
22685
23174
  const cloneInterpolationOptions = (options) => {
22686
23175
  return {
22687
23176
  mode: options.mode,
@@ -22689,40 +23178,40 @@ const cloneInterpolationOptions = (options) => {
22689
23178
  easing: options.easing
22690
23179
  };
22691
23180
  };
22692
- const cloneNumericInterpolationOptions = (options) => {
22693
- return {
22694
- durationMs: options.durationMs,
22695
- easing: options.easing
22696
- };
22697
- };
22698
23181
  const createImageStateFromInit = (imageInit, subLayer, order) => {
22699
23182
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
22700
23183
  const mode = (_a = imageInit.mode) != null ? _a : "surface";
22701
23184
  const autoRotationDefault = mode === "surface";
23185
+ const initialOffset = cloneOffset(imageInit.offset);
23186
+ const initialRotateDeg = normalizeAngleDeg((_b = imageInit.rotateDeg) != null ? _b : 0);
22702
23187
  const state = {
22703
23188
  subLayer,
22704
23189
  order,
22705
23190
  imageId: imageInit.imageId,
22706
23191
  mode,
22707
- opacity: (_b = imageInit.opacity) != null ? _b : 1,
22708
- scale: (_c = imageInit.scale) != null ? _c : 1,
23192
+ opacity: (_c = imageInit.opacity) != null ? _c : 1,
23193
+ scale: (_d = imageInit.scale) != null ? _d : 1,
22709
23194
  anchor: cloneAnchor(imageInit.anchor),
22710
- offset: cloneOffset(imageInit.offset),
22711
- rotateDeg: (_d = imageInit.rotateDeg) != null ? _d : 0,
22712
- displayedRotateDeg: normaliseAngleDeg((_e = imageInit.rotateDeg) != null ? _e : 0),
23195
+ offset: initialOffset,
23196
+ rotateDeg: (_e = imageInit.rotateDeg) != null ? _e : 0,
23197
+ displayedRotateDeg: initialRotateDeg,
22713
23198
  autoRotation: (_f = imageInit.autoRotation) != null ? _f : autoRotationDefault,
22714
23199
  autoRotationMinDistanceMeters: (_g = imageInit.autoRotationMinDistanceMeters) != null ? _g : DEFAULT_AUTO_ROTATION_MIN_DISTANCE_METERS,
22715
23200
  resolvedBaseRotateDeg: 0,
22716
23201
  originLocation: cloneOriginLocation(imageInit.originLocation),
22717
23202
  rotationInterpolationState: null,
22718
23203
  rotationInterpolationOptions: null,
22719
- offsetInterpolationState: null
23204
+ offsetDegInterpolationState: null,
23205
+ offsetMetersInterpolationState: null,
23206
+ lastCommandRotateDeg: initialRotateDeg,
23207
+ lastCommandOffsetDeg: initialOffset.offsetDeg,
23208
+ lastCommandOffsetMeters: initialOffset.offsetMeters
22720
23209
  };
22721
- const rotateInitOption = (_i = (_h = imageInit.rotationInterpolation) == null ? void 0 : _h.rotateDeg) != null ? _i : null;
23210
+ const rotateInitOption = (_i = (_h = imageInit.interpolation) == null ? void 0 : _h.rotateDeg) != null ? _i : null;
22722
23211
  if (rotateInitOption) {
22723
- state.rotationInterpolationOptions = cloneNumericInterpolationOptions(rotateInitOption);
23212
+ state.rotationInterpolationOptions = cloneInterpolationOptions(rotateInitOption);
22724
23213
  }
22725
- updateImageDisplayedRotation(state);
23214
+ syncImageRotationChannel(state);
22726
23215
  return state;
22727
23216
  };
22728
23217
  const createSpriteLayer = (options) => {
@@ -22872,7 +23361,7 @@ const createSpriteLayer = (options) => {
22872
23361
  baseY = refCenter.y;
22873
23362
  }
22874
23363
  }
22875
- const totalRotDeg = Number.isFinite(img.displayedRotateDeg) ? img.displayedRotateDeg : normaliseAngleDeg(
23364
+ const totalRotDeg = Number.isFinite(img.displayedRotateDeg) ? img.displayedRotateDeg : normalizeAngleDeg(
22876
23365
  ((_d = img.resolvedBaseRotateDeg) != null ? _d : 0) + ((_e = img.rotateDeg) != null ? _e : 0)
22877
23366
  );
22878
23367
  const imageScaleLocal = (_f = img.scale) != null ? _f : 1;
@@ -23022,13 +23511,15 @@ const createSpriteLayer = (options) => {
23022
23511
  };
23023
23512
  let canvasElement = null;
23024
23513
  const inputListenerDisposers = [];
23025
- const hasSpriteClickListeners = () => {
23514
+ const hasSpriteListeners = (type) => {
23026
23515
  var _a2, _b;
23027
23516
  return (
23028
23517
  // Treat missing listener sets as zero, otherwise check the registered count.
23029
- ((_b = (_a2 = eventListeners.get("spriteclick")) == null ? void 0 : _a2.size) != null ? _b : 0) > 0
23518
+ ((_b = (_a2 = eventListeners.get(type)) == null ? void 0 : _a2.size) != null ? _b : 0) > 0
23030
23519
  );
23031
23520
  };
23521
+ const hasSpriteClickListeners = () => hasSpriteListeners("spriteclick");
23522
+ const hasSpriteHoverListeners = () => hasSpriteListeners("spritehover");
23032
23523
  const resolveScreenPointFromEvent = (nativeEvent) => {
23033
23524
  var _a2, _b, _c, _d;
23034
23525
  if (!canvasElement) {
@@ -23053,20 +23544,31 @@ const createSpriteLayer = (options) => {
23053
23544
  const mouseLike = nativeEvent;
23054
23545
  return toScreenPoint(mouseLike.clientX, mouseLike.clientY);
23055
23546
  };
23547
+ const resolveSpriteEventPayload = (hitEntry) => {
23548
+ var _a2, _b;
23549
+ if (!hitEntry) {
23550
+ return {
23551
+ sprite: void 0,
23552
+ image: void 0
23553
+ };
23554
+ }
23555
+ const spriteState = getSpriteState(hitEntry.sprite.spriteId);
23556
+ const imageState = (_b = (_a2 = spriteState == null ? void 0 : spriteState.images.get(hitEntry.image.subLayer)) == null ? void 0 : _a2.get(hitEntry.image.order)) != null ? _b : void 0;
23557
+ return {
23558
+ sprite: spriteState,
23559
+ image: imageState
23560
+ };
23561
+ };
23056
23562
  const dispatchSpriteClick = (hitEntry, screenPoint, originalEvent) => {
23057
23563
  const listeners = eventListeners.get("spriteclick");
23058
23564
  if (!listeners || listeners.size === 0) {
23059
23565
  return;
23060
23566
  }
23061
- const spriteState = getSpriteState(hitEntry.sprite.spriteId);
23062
- if (!spriteState) {
23063
- return;
23064
- }
23065
- const imageState = hitEntry.image;
23567
+ const payload = resolveSpriteEventPayload(hitEntry);
23066
23568
  const clickEvent = {
23067
23569
  type: "spriteclick",
23068
- sprite: spriteState,
23069
- image: imageState,
23570
+ sprite: payload.sprite,
23571
+ image: payload.image,
23070
23572
  screenPoint,
23071
23573
  originalEvent
23072
23574
  };
@@ -23074,22 +23576,50 @@ const createSpriteLayer = (options) => {
23074
23576
  listener(clickEvent);
23075
23577
  });
23076
23578
  };
23077
- const processInteractionEvent = (nativeEvent) => {
23579
+ const dispatchSpriteHover = (hitEntry, screenPoint, originalEvent) => {
23580
+ const listeners = eventListeners.get("spritehover");
23581
+ if (!listeners || listeners.size === 0) {
23582
+ return;
23583
+ }
23584
+ const payload = resolveSpriteEventPayload(hitEntry);
23585
+ const hoverEvent = {
23586
+ type: "spritehover",
23587
+ sprite: payload.sprite,
23588
+ image: payload.image,
23589
+ screenPoint,
23590
+ originalEvent
23591
+ };
23592
+ listeners.forEach((listener) => {
23593
+ listener(hoverEvent);
23594
+ });
23595
+ };
23596
+ const resolveHitTestResult = (nativeEvent) => {
23597
+ const screenPoint = resolveScreenPointFromEvent(nativeEvent);
23598
+ if (!screenPoint) {
23599
+ return null;
23600
+ }
23601
+ const hitEntry = findTopmostHitEntry(screenPoint);
23602
+ return { hitEntry: hitEntry != null ? hitEntry : null, screenPoint };
23603
+ };
23604
+ const processClickEvent = (nativeEvent) => {
23078
23605
  if (!hasSpriteClickListeners()) {
23079
23606
  return;
23080
23607
  }
23081
- if (hitTestEntries.length === 0) {
23608
+ const hitResult = resolveHitTestResult(nativeEvent);
23609
+ if (!hitResult || !hitResult.hitEntry) {
23082
23610
  return;
23083
23611
  }
23084
- const screenPoint = resolveScreenPointFromEvent(nativeEvent);
23085
- if (!screenPoint) {
23612
+ dispatchSpriteClick(hitResult.hitEntry, hitResult.screenPoint, nativeEvent);
23613
+ };
23614
+ const processHoverEvent = (nativeEvent) => {
23615
+ if (!hasSpriteHoverListeners()) {
23086
23616
  return;
23087
23617
  }
23088
- const hitEntry = findTopmostHitEntry(screenPoint);
23089
- if (!hitEntry) {
23618
+ const hitResult = resolveHitTestResult(nativeEvent);
23619
+ if (!hitResult) {
23090
23620
  return;
23091
23621
  }
23092
- dispatchSpriteClick(hitEntry, screenPoint, nativeEvent);
23622
+ dispatchSpriteHover(hitResult.hitEntry, hitResult.screenPoint, nativeEvent);
23093
23623
  };
23094
23624
  const ensureTextures = () => {
23095
23625
  if (!gl) {
@@ -23242,24 +23772,42 @@ const createSpriteLayer = (options) => {
23242
23772
  const supportsPointerEvents = typeof window !== "undefined" && "PointerEvent" in window;
23243
23773
  if (canvasElement) {
23244
23774
  if (supportsPointerEvents) {
23245
- const pointerListener = (event) => {
23775
+ const pointerUpListener = (event) => {
23246
23776
  if (event.pointerType === "mouse" && event.button !== 0) {
23247
23777
  return;
23248
23778
  }
23249
- processInteractionEvent(event);
23779
+ processClickEvent(event);
23780
+ };
23781
+ canvasElement.addEventListener("pointerup", pointerUpListener, {
23782
+ passive: true
23783
+ });
23784
+ registerDisposer(() => {
23785
+ canvasElement == null ? void 0 : canvasElement.removeEventListener("pointerup", pointerUpListener);
23786
+ });
23787
+ const pointerMoveListener = (event) => {
23788
+ if (!event.isPrimary) {
23789
+ return;
23790
+ }
23791
+ if (event.pointerType === "touch") {
23792
+ return;
23793
+ }
23794
+ processHoverEvent(event);
23250
23795
  };
23251
- canvasElement.addEventListener("pointerup", pointerListener, {
23796
+ canvasElement.addEventListener("pointermove", pointerMoveListener, {
23252
23797
  passive: true
23253
23798
  });
23254
23799
  registerDisposer(() => {
23255
- canvasElement == null ? void 0 : canvasElement.removeEventListener("pointerup", pointerListener);
23800
+ canvasElement == null ? void 0 : canvasElement.removeEventListener(
23801
+ "pointermove",
23802
+ pointerMoveListener
23803
+ );
23256
23804
  });
23257
23805
  } else {
23258
23806
  const clickListener = (event) => {
23259
23807
  if (event.button !== 0) {
23260
23808
  return;
23261
23809
  }
23262
- processInteractionEvent(event);
23810
+ processClickEvent(event);
23263
23811
  };
23264
23812
  canvasElement.addEventListener("click", clickListener, {
23265
23813
  passive: true
@@ -23268,7 +23816,7 @@ const createSpriteLayer = (options) => {
23268
23816
  canvasElement == null ? void 0 : canvasElement.removeEventListener("click", clickListener);
23269
23817
  });
23270
23818
  const touchListener = (event) => {
23271
- processInteractionEvent(event);
23819
+ processClickEvent(event);
23272
23820
  };
23273
23821
  canvasElement.addEventListener("touchend", touchListener, {
23274
23822
  passive: true
@@ -23276,6 +23824,15 @@ const createSpriteLayer = (options) => {
23276
23824
  registerDisposer(() => {
23277
23825
  canvasElement == null ? void 0 : canvasElement.removeEventListener("touchend", touchListener);
23278
23826
  });
23827
+ const mouseMoveListener = (event) => {
23828
+ processHoverEvent(event);
23829
+ };
23830
+ canvasElement.addEventListener("mousemove", mouseMoveListener, {
23831
+ passive: true
23832
+ });
23833
+ registerDisposer(() => {
23834
+ canvasElement == null ? void 0 : canvasElement.removeEventListener("mousemove", mouseMoveListener);
23835
+ });
23279
23836
  }
23280
23837
  }
23281
23838
  const buffer = glContext.createBuffer();
@@ -23411,41 +23968,8 @@ const createSpriteLayer = (options) => {
23411
23968
  }
23412
23969
  sprite.images.forEach((orderMap) => {
23413
23970
  orderMap.forEach((image) => {
23414
- const rotationState = image.rotationInterpolationState;
23415
- if (rotationState) {
23416
- const evaluation = evaluateNumericInterpolation({
23417
- state: rotationState,
23418
- timestamp
23419
- });
23420
- if (rotationState.startTimestamp < 0) {
23421
- rotationState.startTimestamp = evaluation.effectiveStartTimestamp;
23422
- }
23423
- image.displayedRotateDeg = normaliseAngleDeg(evaluation.value);
23424
- if (evaluation.completed) {
23425
- image.displayedRotateDeg = normaliseAngleDeg(
23426
- rotationState.finalValue
23427
- );
23428
- image.rotationInterpolationState = null;
23429
- } else {
23430
- hasActiveInterpolation = true;
23431
- }
23432
- }
23433
- const offsetState = image.offsetInterpolationState;
23434
- if (offsetState) {
23435
- const evaluation = evaluateNumericInterpolation({
23436
- state: offsetState,
23437
- timestamp
23438
- });
23439
- if (offsetState.startTimestamp < 0) {
23440
- offsetState.startTimestamp = evaluation.effectiveStartTimestamp;
23441
- }
23442
- image.offset.offsetDeg = evaluation.value;
23443
- if (evaluation.completed) {
23444
- image.offset.offsetDeg = offsetState.finalValue;
23445
- image.offsetInterpolationState = null;
23446
- } else {
23447
- hasActiveInterpolation = true;
23448
- }
23971
+ if (stepSpriteImageInterpolations(image, timestamp)) {
23972
+ hasActiveInterpolation = true;
23449
23973
  }
23450
23974
  });
23451
23975
  });
@@ -23502,7 +24026,7 @@ const createSpriteLayer = (options) => {
23502
24026
  let screenCornerBuffer = null;
23503
24027
  const anchor = (_a2 = imageEntry.anchor) != null ? _a2 : DEFAULT_ANCHOR;
23504
24028
  const offsetDef = (_b = imageEntry.offset) != null ? _b : DEFAULT_IMAGE_OFFSET;
23505
- const totalRotateDeg = Number.isFinite(imageEntry.displayedRotateDeg) ? imageEntry.displayedRotateDeg : normaliseAngleDeg(
24029
+ const totalRotateDeg = Number.isFinite(imageEntry.displayedRotateDeg) ? imageEntry.displayedRotateDeg : normalizeAngleDeg(
23506
24030
  ((_c = imageEntry.resolvedBaseRotateDeg) != null ? _c : 0) + ((_d = imageEntry.rotateDeg) != null ? _d : 0)
23507
24031
  );
23508
24032
  const projected = mapInstance.project(spriteEntry.currentLocation);
@@ -23801,7 +24325,7 @@ const createSpriteLayer = (options) => {
23801
24325
  spriteMaxPixel
23802
24326
  }
23803
24327
  );
23804
- const totalRotateDeg = Number.isFinite(imageEntry.displayedRotateDeg) ? imageEntry.displayedRotateDeg : normaliseAngleDeg(
24328
+ const totalRotateDeg = Number.isFinite(imageEntry.displayedRotateDeg) ? imageEntry.displayedRotateDeg : normalizeAngleDeg(
23805
24329
  ((_e = imageEntry.resolvedBaseRotateDeg) != null ? _e : 0) + ((_f = imageEntry.rotateDeg) != null ? _f : 0)
23806
24330
  );
23807
24331
  const offsetMeters = calculateSurfaceOffsetMeters(
@@ -23921,8 +24445,20 @@ const createSpriteLayer = (options) => {
23921
24445
  glContext.disable(glContext.BLEND);
23922
24446
  scheduleRender();
23923
24447
  };
23924
- const registerImage = async (imageId, imageSource) => {
23925
- const bitmap = typeof imageSource === "string" ? await loadImageBitmap(imageSource) : imageSource;
24448
+ const registerImage = async (imageId, imageSource, options2) => {
24449
+ let bitmap;
24450
+ try {
24451
+ bitmap = typeof imageSource === "string" ? await loadImageBitmap(imageSource, options2) : imageSource;
24452
+ } catch (error) {
24453
+ if (error instanceof SvgSizeResolutionError) {
24454
+ console.warn(
24455
+ `[SpriteLayer] Unable to register image "${imageId}": ${error.message}`,
24456
+ error
24457
+ );
24458
+ return false;
24459
+ }
24460
+ throw error;
24461
+ }
23926
24462
  if (images.has(imageId)) {
23927
24463
  return false;
23928
24464
  }
@@ -24371,7 +24907,7 @@ const createSpriteLayer = (options) => {
24371
24907
  if (state.autoRotation) {
24372
24908
  state.resolvedBaseRotateDeg = sprite.lastAutoRotationAngleDeg;
24373
24909
  }
24374
- updateImageDisplayedRotation(state);
24910
+ syncImageRotationChannel(state);
24375
24911
  setImageState(sprite, state);
24376
24912
  resultOut.isUpdated = true;
24377
24913
  return true;
@@ -24412,41 +24948,32 @@ const createSpriteLayer = (options) => {
24412
24948
  if (imageUpdate.anchor !== void 0) {
24413
24949
  state.anchor = cloneAnchor(imageUpdate.anchor);
24414
24950
  }
24415
- const rotationInterpolation = imageUpdate.rotationInterpolation;
24416
- const offsetInterpolationOption = rotationInterpolation == null ? void 0 : rotationInterpolation.offsetDeg;
24417
- const rotateInterpolationOption = rotationInterpolation == null ? void 0 : rotationInterpolation.rotateDeg;
24951
+ const interpolationOptions = imageUpdate.interpolation;
24952
+ const offsetDegInterpolationOption = interpolationOptions == null ? void 0 : interpolationOptions.offsetDeg;
24953
+ const offsetMetersInterpolationOption = interpolationOptions == null ? void 0 : interpolationOptions.offsetMeters;
24954
+ const rotateInterpolationOption = interpolationOptions == null ? void 0 : interpolationOptions.rotateDeg;
24418
24955
  let rotationOverride;
24419
24956
  let hasRotationOverride = false;
24420
24957
  if (imageUpdate.offset !== void 0) {
24421
- const newOffset = cloneOffset(imageUpdate.offset);
24422
- if (offsetInterpolationOption && offsetInterpolationOption.durationMs > 0) {
24423
- const { state: interpolationState, requiresInterpolation } = createNumericInterpolationState({
24424
- currentValue: state.offset.offsetDeg,
24425
- targetValue: newOffset.offsetDeg,
24426
- options: offsetInterpolationOption
24427
- });
24428
- if (requiresInterpolation) {
24429
- state.offset.offsetMeters = newOffset.offsetMeters;
24430
- state.offsetInterpolationState = interpolationState;
24431
- } else {
24432
- state.offset = newOffset;
24433
- state.offsetInterpolationState = null;
24434
- }
24435
- } else {
24436
- state.offset = newOffset;
24437
- state.offsetInterpolationState = null;
24958
+ const clonedOffset = cloneOffset(imageUpdate.offset);
24959
+ applyOffsetUpdate(state, clonedOffset, {
24960
+ deg: offsetDegInterpolationOption,
24961
+ meters: offsetMetersInterpolationOption
24962
+ });
24963
+ } else {
24964
+ if (offsetDegInterpolationOption === null) {
24965
+ clearOffsetDegInterpolation(state);
24966
+ }
24967
+ if (offsetMetersInterpolationOption === null) {
24968
+ clearOffsetMetersInterpolation(state);
24438
24969
  }
24439
- } else if (offsetInterpolationOption === null) {
24440
- state.offsetInterpolationState = null;
24441
24970
  }
24442
24971
  if (rotateInterpolationOption !== void 0) {
24443
24972
  if (rotateInterpolationOption === null) {
24444
24973
  state.rotationInterpolationOptions = null;
24445
24974
  rotationOverride = null;
24446
24975
  } else {
24447
- const cloned = cloneNumericInterpolationOptions(
24448
- rotateInterpolationOption
24449
- );
24976
+ const cloned = cloneInterpolationOptions(rotateInterpolationOption);
24450
24977
  state.rotationInterpolationOptions = cloned;
24451
24978
  rotationOverride = cloned;
24452
24979
  }
@@ -24488,7 +25015,7 @@ const createSpriteLayer = (options) => {
24488
25015
  }
24489
25016
  }
24490
25017
  if (requireRotationSync) {
24491
- updateImageDisplayedRotation(
25018
+ syncImageRotationChannel(
24492
25019
  state,
24493
25020
  // When a rotation override has been computed, pass it along (null clears interpolation); otherwise leave undefined.
24494
25021
  hasRotationOverride ? rotationOverride != null ? rotationOverride : null : void 0
@@ -24653,34 +25180,6 @@ const createSpriteLayer = (options) => {
24653
25180
  return true;
24654
25181
  }
24655
25182
  };
24656
- const updateBulk = (updateBulkList) => {
24657
- let updatedCount = 0;
24658
- let isRequiredRender = false;
24659
- updateBulkList.forEach((update) => {
24660
- const result = updateSpriteInternal(update.spriteId, update);
24661
- switch (result) {
24662
- case "notfound":
24663
- // Sprite missing; nothing to do for this entry.
24664
- case "ignored":
24665
- break;
24666
- case "updated":
24667
- updatedCount++;
24668
- break;
24669
- // When rendering must occur because of this update
24670
- case "isRequiredRender":
24671
- ensureRenderTargetEntries();
24672
- scheduleRender();
24673
- updatedCount++;
24674
- isRequiredRender = true;
24675
- break;
24676
- }
24677
- });
24678
- if (isRequiredRender) {
24679
- ensureRenderTargetEntries();
24680
- scheduleRender();
24681
- }
24682
- return updatedCount;
24683
- };
24684
25183
  const mutateSprites = (sourceItems, mutator) => {
24685
25184
  if (sourceItems.length === 0) {
24686
25185
  return 0;
@@ -24693,6 +25192,10 @@ const createSpriteLayer = (options) => {
24693
25192
  isUpdated: false
24694
25193
  };
24695
25194
  const updateObject = {
25195
+ isEnabled: void 0,
25196
+ location: void 0,
25197
+ interpolation: void 0,
25198
+ tag: void 0,
24696
25199
  getImageIndexMap: () => {
24697
25200
  const map2 = /* @__PURE__ */ new Map();
24698
25201
  currentSprite.images.forEach((inner, subLayer) => {
@@ -24886,7 +25389,6 @@ const createSpriteLayer = (options) => {
24886
25389
  updateSpriteImage,
24887
25390
  removeSpriteImage,
24888
25391
  updateSprite,
24889
- updateBulk,
24890
25392
  mutateSprites,
24891
25393
  updateForEach,
24892
25394
  on: addEventListener2,
@@ -24897,6 +25399,7 @@ const createSpriteLayer = (options) => {
24897
25399
  exports.BETTER_TEXTURE_FILTERING_OPTIONS = BETTER_TEXTURE_FILTERING_OPTIONS;
24898
25400
  exports.DEFAULT_TEXTURE_FILTERING_OPTIONS = DEFAULT_TEXTURE_FILTERING_OPTIONS;
24899
25401
  exports.STANDARD_SPRITE_SCALING_OPTIONS = STANDARD_SPRITE_SCALING_OPTIONS;
25402
+ exports.SvgSizeResolutionError = SvgSizeResolutionError;
24900
25403
  exports.UNLIMITED_SPRITE_SCALING_OPTIONS = UNLIMITED_SPRITE_SCALING_OPTIONS;
24901
25404
  exports.applyAutoRotation = applyAutoRotation;
24902
25405
  exports.calculatePerspectiveRatio = calculatePerspectiveRatio;
@@ -24907,6 +25410,8 @@ exports.compileShader = compileShader;
24907
25410
  exports.createImageStateFromInit = createImageStateFromInit;
24908
25411
  exports.createShaderProgram = createShaderProgram;
24909
25412
  exports.createSpriteLayer = createSpriteLayer;
25413
+ exports.loadImageBitmap = loadImageBitmap;
24910
25414
  exports.multiplyMatrixAndVector = multiplyMatrixAndVector;
24911
25415
  exports.projectLngLatToClipSpace = projectLngLatToClipSpace;
25416
+ exports.readImageBitmap = readImageBitmap;
24912
25417
  //# sourceMappingURL=index.cjs.map