maplibre-gl-layers 0.2.0 → 0.4.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.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  /*!
2
2
  * name: maplibre-gl-layers
3
- * version: 0.2.0
3
+ * version: 0.4.0
4
4
  * description: MapLibre's layer extension library enabling the display, movement, and modification of large numbers of dynamic sprite images
5
5
  * author: Kouji Matsui (@kekyo@mi.kekyo.net)
6
6
  * license: MIT
7
7
  * repository.url: https://github.com/kekyo/maplibre-gl-layers.git
8
- * git.commit.hash: 4fe3389ad068a5950d4f01e01ec9d3b34c049fb2
8
+ * git.commit.hash: 366a9e1190bfe770b4002a06284ff627188b5c76
9
9
  */
10
10
 
11
11
  export * from './types.ts';
package/dist/index.mjs CHANGED
@@ -1,12 +1,30 @@
1
1
  /*!
2
2
  * name: maplibre-gl-layers
3
- * version: 0.2.0
3
+ * version: 0.4.0
4
4
  * description: MapLibre's layer extension library enabling the display, movement, and modification of large numbers of dynamic sprite images
5
5
  * author: Kouji Matsui (@kekyo@mi.kekyo.net)
6
6
  * license: MIT
7
7
  * repository.url: https://github.com/kekyo/maplibre-gl-layers.git
8
- * git.commit.hash: 4fe3389ad068a5950d4f01e01ec9d3b34c049fb2
8
+ * git.commit.hash: 366a9e1190bfe770b4002a06284ff627188b5c76
9
9
  */
10
+ const UNLIMITED_SPRITE_SCALING_OPTIONS = {
11
+ metersPerPixel: 1,
12
+ zoomMin: 0,
13
+ zoomMax: 30,
14
+ scaleMin: 1,
15
+ scaleMax: 1,
16
+ spriteMinPixel: 0,
17
+ spriteMaxPixel: 1e5
18
+ };
19
+ const STANDARD_SPRITE_SCALING_OPTIONS = {
20
+ metersPerPixel: 1,
21
+ zoomMin: 8,
22
+ zoomMax: 20,
23
+ scaleMin: 0.1,
24
+ scaleMax: 1,
25
+ spriteMinPixel: 24,
26
+ spriteMaxPixel: 100
27
+ };
10
28
  var maplibreGl$1 = { exports: {} };
11
29
  /**
12
30
  * MapLibre GL JS
@@ -21311,26 +21329,134 @@ const EARTH_RADIUS_METERS = 6378137;
21311
21329
  const DEG2RAD = Math.PI / 180;
21312
21330
  const RAD2DEG = 180 / Math.PI;
21313
21331
  const TILE_SIZE = 512;
21314
- const DEFAULT_SPRITE_SCALING_OPTIONS = {
21315
- metersPerPixel: 1,
21316
- zoomMin: 0,
21317
- zoomMax: 30,
21318
- scaleMin: 1,
21319
- scaleMax: 1,
21320
- spriteMinPixel: 0,
21321
- spriteMaxPixel: 1e4
21322
- };
21323
21332
  const resolveScalingOptions = (options) => {
21324
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
21325
- const base = DEFAULT_SPRITE_SCALING_OPTIONS;
21333
+ var _a, _b;
21334
+ const base = UNLIMITED_SPRITE_SCALING_OPTIONS;
21335
+ const warnings = [];
21336
+ const fallbackMetersPerPixel = Number.isFinite(base.metersPerPixel) && ((_a = base.metersPerPixel) != null ? _a : 0) > 0 ? base.metersPerPixel : 1;
21337
+ let metersPerPixel = (options == null ? void 0 : options.metersPerPixel) !== void 0 ? options.metersPerPixel : fallbackMetersPerPixel;
21338
+ if (!Number.isFinite(metersPerPixel) || metersPerPixel <= 0) {
21339
+ if ((options == null ? void 0 : options.metersPerPixel) !== void 0) {
21340
+ warnings.push(
21341
+ `metersPerPixel(${String(options.metersPerPixel)}) is invalid; using ${fallbackMetersPerPixel}`
21342
+ );
21343
+ }
21344
+ metersPerPixel = fallbackMetersPerPixel;
21345
+ }
21346
+ const fallbackZoomMin = Number.isFinite(base.zoomMin) ? base.zoomMin : 0;
21347
+ let zoomMin = (options == null ? void 0 : options.zoomMin) !== void 0 ? options.zoomMin : fallbackZoomMin;
21348
+ if (!Number.isFinite(zoomMin)) {
21349
+ if ((options == null ? void 0 : options.zoomMin) !== void 0) {
21350
+ warnings.push(
21351
+ `zoomMin(${String(options.zoomMin)}) is not finite; using ${fallbackZoomMin}`
21352
+ );
21353
+ }
21354
+ zoomMin = fallbackZoomMin;
21355
+ }
21356
+ const fallbackZoomMax = Number.isFinite(base.zoomMax) && base.zoomMax > fallbackZoomMin ? base.zoomMax : fallbackZoomMin;
21357
+ let zoomMax = (options == null ? void 0 : options.zoomMax) !== void 0 ? options.zoomMax : fallbackZoomMax;
21358
+ if (!Number.isFinite(zoomMax)) {
21359
+ if ((options == null ? void 0 : options.zoomMax) !== void 0) {
21360
+ warnings.push(
21361
+ `zoomMax(${String(options.zoomMax)}) is not finite; using ${fallbackZoomMax}`
21362
+ );
21363
+ }
21364
+ zoomMax = fallbackZoomMax;
21365
+ }
21366
+ if (zoomMax < zoomMin) {
21367
+ warnings.push(
21368
+ `zoomMax(${zoomMax}) < zoomMin(${zoomMin}); swapped values to maintain ascending order`
21369
+ );
21370
+ [zoomMin, zoomMax] = [zoomMax, zoomMin];
21371
+ }
21372
+ const fallbackScaleMin = Number.isFinite(base.scaleMin) ? base.scaleMin : 1;
21373
+ let scaleMin = (options == null ? void 0 : options.scaleMin) !== void 0 ? options.scaleMin : fallbackScaleMin;
21374
+ if (!Number.isFinite(scaleMin)) {
21375
+ if ((options == null ? void 0 : options.scaleMin) !== void 0) {
21376
+ warnings.push(
21377
+ `scaleMin(${String(options.scaleMin)}) is not finite; using ${fallbackScaleMin}`
21378
+ );
21379
+ }
21380
+ scaleMin = fallbackScaleMin;
21381
+ }
21382
+ if (scaleMin < 0) {
21383
+ warnings.push(`scaleMin(${scaleMin}) is negative; clamped to 0`);
21384
+ scaleMin = 0;
21385
+ }
21386
+ const fallbackScaleMax = Number.isFinite(base.scaleMax) ? base.scaleMax : 1;
21387
+ let scaleMax = (options == null ? void 0 : options.scaleMax) !== void 0 ? options.scaleMax : fallbackScaleMax;
21388
+ if (!Number.isFinite(scaleMax)) {
21389
+ if ((options == null ? void 0 : options.scaleMax) !== void 0) {
21390
+ warnings.push(
21391
+ `scaleMax(${String(options.scaleMax)}) is not finite; using ${fallbackScaleMax}`
21392
+ );
21393
+ }
21394
+ scaleMax = fallbackScaleMax;
21395
+ }
21396
+ if (scaleMax < 0) {
21397
+ warnings.push(`scaleMax(${scaleMax}) is negative; clamped to 0`);
21398
+ scaleMax = 0;
21399
+ }
21400
+ if (scaleMax < scaleMin) {
21401
+ warnings.push(
21402
+ `scaleMax(${scaleMax}) < scaleMin(${scaleMin}); swapped values to maintain ascending order`
21403
+ );
21404
+ [scaleMin, scaleMax] = [scaleMax, scaleMin];
21405
+ }
21406
+ const fallbackSpriteMin = Number.isFinite(base.spriteMinPixel) && base.spriteMinPixel >= 0 ? base.spriteMinPixel : 0;
21407
+ let spriteMinPixel = (options == null ? void 0 : options.spriteMinPixel) !== void 0 ? options.spriteMinPixel : fallbackSpriteMin;
21408
+ if (!Number.isFinite(spriteMinPixel)) {
21409
+ if ((options == null ? void 0 : options.spriteMinPixel) !== void 0) {
21410
+ warnings.push(
21411
+ `spriteMinPixel(${String(
21412
+ options.spriteMinPixel
21413
+ )}) is not finite; using ${fallbackSpriteMin}`
21414
+ );
21415
+ }
21416
+ spriteMinPixel = fallbackSpriteMin;
21417
+ } else if (spriteMinPixel < 0) {
21418
+ warnings.push(
21419
+ `spriteMinPixel(${spriteMinPixel}) is negative; clamped to 0`
21420
+ );
21421
+ spriteMinPixel = 0;
21422
+ }
21423
+ const fallbackSpriteMax = Number.isFinite(base.spriteMaxPixel) && base.spriteMaxPixel >= 0 ? base.spriteMaxPixel : 0;
21424
+ let spriteMaxPixel = (options == null ? void 0 : options.spriteMaxPixel) !== void 0 ? options.spriteMaxPixel : fallbackSpriteMax;
21425
+ if (!Number.isFinite(spriteMaxPixel)) {
21426
+ if ((options == null ? void 0 : options.spriteMaxPixel) !== void 0) {
21427
+ warnings.push(
21428
+ `spriteMaxPixel(${String(
21429
+ options.spriteMaxPixel
21430
+ )}) is not finite; using ${fallbackSpriteMax}`
21431
+ );
21432
+ }
21433
+ spriteMaxPixel = fallbackSpriteMax;
21434
+ } else if (spriteMaxPixel < 0) {
21435
+ warnings.push(
21436
+ `spriteMaxPixel(${spriteMaxPixel}) is negative; clamped to 0`
21437
+ );
21438
+ spriteMaxPixel = 0;
21439
+ }
21440
+ if (spriteMinPixel > 0 && spriteMaxPixel > 0 && spriteMaxPixel < spriteMinPixel) {
21441
+ warnings.push(
21442
+ `spriteMaxPixel(${spriteMaxPixel}) < spriteMinPixel(${spriteMinPixel}); swapped values to maintain ascending order`
21443
+ );
21444
+ [spriteMinPixel, spriteMaxPixel] = [spriteMaxPixel, spriteMinPixel];
21445
+ }
21446
+ if (warnings.length > 0 && typeof console !== "undefined") {
21447
+ const warn = (_b = console.warn) != null ? _b : null;
21448
+ if (typeof warn === "function") {
21449
+ warn(`[SpriteScalingOptions] ${warnings.join("; ")}`);
21450
+ }
21451
+ }
21326
21452
  return {
21327
- metersPerPixel: (_b = (_a = options == null ? void 0 : options.metersPerPixel) != null ? _a : base.metersPerPixel) != null ? _b : 1,
21328
- zoomMin: (_d = (_c = options == null ? void 0 : options.zoomMin) != null ? _c : base.zoomMin) != null ? _d : 0,
21329
- zoomMax: (_f = (_e = options == null ? void 0 : options.zoomMax) != null ? _e : base.zoomMax) != null ? _f : 24,
21330
- scaleMin: (_h = (_g = options == null ? void 0 : options.scaleMin) != null ? _g : base.scaleMin) != null ? _h : 1,
21331
- scaleMax: (_j = (_i = options == null ? void 0 : options.scaleMax) != null ? _i : base.scaleMax) != null ? _j : 1,
21332
- spriteMinPixel: (_l = (_k = options == null ? void 0 : options.spriteMinPixel) != null ? _k : base.spriteMinPixel) != null ? _l : 0,
21333
- spriteMaxPixel: (_n = (_m = options == null ? void 0 : options.spriteMaxPixel) != null ? _m : base.spriteMaxPixel) != null ? _n : 0
21453
+ metersPerPixel,
21454
+ zoomMin,
21455
+ zoomMax,
21456
+ scaleMin,
21457
+ scaleMax,
21458
+ spriteMinPixel,
21459
+ spriteMaxPixel
21334
21460
  };
21335
21461
  };
21336
21462
  const calculateZoomScaleFactor = (zoom, scaling) => {
@@ -21448,13 +21574,37 @@ const calculateBillboardAnchorShiftPixels = (halfWidth, halfHeight, anchor, tota
21448
21574
  const shiftY = -anchorX * sinR - anchorY * cosR;
21449
21575
  return { x: shiftX, y: shiftY };
21450
21576
  };
21451
- const calculateSurfaceWorldDimensions = (imageWidth, imageHeight, baseMetersPerPixel, imageScale, zoomScaleFactor) => {
21577
+ const calculateSurfaceWorldDimensions = (imageWidth, imageHeight, baseMetersPerPixel, imageScale, zoomScaleFactor, options) => {
21578
+ var _a, _b;
21452
21579
  if (!imageWidth || !imageHeight || imageWidth <= 0 || imageHeight <= 0 || baseMetersPerPixel <= 0) {
21453
21580
  return { width: 0, height: 0 };
21454
21581
  }
21455
21582
  const scaleFactor = baseMetersPerPixel * imageScale * zoomScaleFactor;
21456
- const width = ensureFinite(imageWidth * scaleFactor);
21457
- const height = ensureFinite(imageHeight * scaleFactor);
21583
+ let width = ensureFinite(imageWidth * scaleFactor);
21584
+ let height = ensureFinite(imageHeight * scaleFactor);
21585
+ const effectivePixelsPerMeter = (options == null ? void 0 : options.effectivePixelsPerMeter) !== void 0 ? options.effectivePixelsPerMeter : 0;
21586
+ const spriteMinPixel = (_a = options == null ? void 0 : options.spriteMinPixel) != null ? _a : 0;
21587
+ const spriteMaxPixel = (_b = options == null ? void 0 : options.spriteMaxPixel) != null ? _b : 0;
21588
+ if (effectivePixelsPerMeter > 0 && Number.isFinite(effectivePixelsPerMeter) && (spriteMinPixel > 0 || spriteMaxPixel > 0)) {
21589
+ const largestMeters = Math.max(width, height);
21590
+ if (largestMeters > 0 && Number.isFinite(largestMeters)) {
21591
+ const largestPixels = largestMeters * effectivePixelsPerMeter;
21592
+ if (Number.isFinite(largestPixels) && largestPixels > 0) {
21593
+ let scale = 1;
21594
+ if (spriteMinPixel > 0 && largestPixels < spriteMinPixel) {
21595
+ scale = spriteMinPixel / largestPixels;
21596
+ }
21597
+ const scaledLargest = largestPixels * scale;
21598
+ if (spriteMaxPixel > 0 && scaledLargest > spriteMaxPixel) {
21599
+ scale = spriteMaxPixel / largestPixels;
21600
+ }
21601
+ if (scale !== 1) {
21602
+ width *= scale;
21603
+ height *= scale;
21604
+ }
21605
+ }
21606
+ }
21607
+ }
21458
21608
  return { width, height };
21459
21609
  };
21460
21610
  const calculateSurfaceAnchorShiftMeters = (halfWidthMeters, halfHeightMeters, anchor, totalRotateDeg) => {
@@ -21474,9 +21624,9 @@ const calculateSurfaceAnchorShiftMeters = (halfWidthMeters, halfHeightMeters, an
21474
21624
  const north = -anchorEast * sinR - anchorNorth * cosR;
21475
21625
  return { east, north };
21476
21626
  };
21477
- const calculateSurfaceOffsetMeters = (offset, imageScale) => {
21627
+ const calculateSurfaceOffsetMeters = (offset, imageScale, zoomScaleFactor) => {
21478
21628
  var _a, _b;
21479
- const offsetMeters = ((_a = offset == null ? void 0 : offset.offsetMeters) != null ? _a : 0) * imageScale;
21629
+ const offsetMeters = ((_a = offset == null ? void 0 : offset.offsetMeters) != null ? _a : 0) * imageScale * zoomScaleFactor;
21480
21630
  if (offsetMeters === 0) {
21481
21631
  return { east: 0, north: 0 };
21482
21632
  }
@@ -21694,6 +21844,9 @@ const calculateSurfaceCenterPosition = (params) => {
21694
21844
  totalRotateDeg,
21695
21845
  anchor,
21696
21846
  offset,
21847
+ effectivePixelsPerMeter = 0,
21848
+ spriteMinPixel = 0,
21849
+ spriteMaxPixel = 0,
21697
21850
  project,
21698
21851
  projectToClipSpace,
21699
21852
  drawingBufferWidth,
@@ -21731,7 +21884,12 @@ const calculateSurfaceCenterPosition = (params) => {
21731
21884
  imageHeight,
21732
21885
  baseMetersPerPixel,
21733
21886
  imageScale,
21734
- zoomScaleFactor
21887
+ zoomScaleFactor,
21888
+ {
21889
+ effectivePixelsPerMeter,
21890
+ spriteMinPixel,
21891
+ spriteMaxPixel
21892
+ }
21735
21893
  );
21736
21894
  const halfWidthMeters = worldDims.width / 2;
21737
21895
  const halfHeightMeters = worldDims.height / 2;
@@ -21741,7 +21899,11 @@ const calculateSurfaceCenterPosition = (params) => {
21741
21899
  anchor,
21742
21900
  totalRotateDeg
21743
21901
  );
21744
- const offsetMeters = calculateSurfaceOffsetMeters(offset, imageScale);
21902
+ const offsetMeters = calculateSurfaceOffsetMeters(
21903
+ offset,
21904
+ imageScale,
21905
+ zoomScaleFactor
21906
+ );
21745
21907
  const totalEast = anchorShiftMeters.east + offsetMeters.east;
21746
21908
  const totalNorth = anchorShiftMeters.north + offsetMeters.north;
21747
21909
  const displaced = applySurfaceDisplacement(
@@ -22073,6 +22235,35 @@ const resolveTextGlyphPadding = (padding) => {
22073
22235
  }
22074
22236
  return { top: 0, right: 0, bottom: 0, left: 0 };
22075
22237
  };
22238
+ const resolveBorderSides = (sides) => {
22239
+ if (!Array.isArray(sides) || sides.length === 0) {
22240
+ return { top: true, right: true, bottom: true, left: true };
22241
+ }
22242
+ let top = false;
22243
+ let right = false;
22244
+ let bottom = false;
22245
+ let left = false;
22246
+ for (const side of sides) {
22247
+ switch (side) {
22248
+ case "top":
22249
+ top = true;
22250
+ break;
22251
+ case "right":
22252
+ right = true;
22253
+ break;
22254
+ case "bottom":
22255
+ bottom = true;
22256
+ break;
22257
+ case "left":
22258
+ left = true;
22259
+ break;
22260
+ }
22261
+ }
22262
+ if (!top && !right && !bottom && !left) {
22263
+ return { top: true, right: true, bottom: true, left: true };
22264
+ }
22265
+ return { top, right, bottom, left };
22266
+ };
22076
22267
  const resolveTextAlign = (align) => {
22077
22268
  switch (align) {
22078
22269
  case "left":
@@ -22116,7 +22307,7 @@ const resolveTextGlyphOptions = (options, preferredLineHeight) => {
22116
22307
  DEFAULT_TEXT_GLYPH_FONT_SIZE
22117
22308
  );
22118
22309
  const resolvedFontSize = resolvePositiveFinite(
22119
- options == null ? void 0 : options.fontSizePixel,
22310
+ options == null ? void 0 : options.fontSizePixelHint,
22120
22311
  fallbackFontSize
22121
22312
  );
22122
22313
  return {
@@ -22131,6 +22322,7 @@ const resolveTextGlyphOptions = (options, preferredLineHeight) => {
22131
22322
  borderColor: options == null ? void 0 : options.borderColor,
22132
22323
  borderWidthPixel: resolveNonNegativeFinite(options == null ? void 0 : options.borderWidthPixel, 0),
22133
22324
  borderRadiusPixel: resolveNonNegativeFinite(options == null ? void 0 : options.borderRadiusPixel, 0),
22325
+ borderSides: resolveBorderSides(options == null ? void 0 : options.borderSides),
22134
22326
  textAlign: resolveTextAlign(options == null ? void 0 : options.textAlign),
22135
22327
  renderPixelRatio: resolveRenderPixelRatio(options == null ? void 0 : options.renderPixelRatio)
22136
22328
  };
@@ -22242,13 +22434,58 @@ const fillRoundedRect = (ctx, width, height, radius, color) => {
22242
22434
  ctx.fill();
22243
22435
  ctx.restore();
22244
22436
  };
22245
- const strokeRoundedRect = (ctx, width, height, radius, color, lineWidth) => {
22437
+ const strokeRoundedRect = (ctx, width, height, radius, color, lineWidth, sides) => {
22438
+ const { top, right, bottom, left } = sides;
22439
+ if (lineWidth <= 0 || !top && !right && !bottom && !left) {
22440
+ return;
22441
+ }
22246
22442
  ctx.save();
22247
- ctx.beginPath();
22248
- drawRoundedRectPath(ctx, 0, 0, width, height, radius);
22249
22443
  ctx.strokeStyle = color;
22250
22444
  ctx.lineWidth = lineWidth;
22251
- ctx.stroke();
22445
+ const cornerRadius = Math.max(0, Math.min(radius, width / 2, height / 2));
22446
+ const previousCap = ctx.lineCap;
22447
+ ctx.lineCap = cornerRadius === 0 ? "square" : "butt";
22448
+ if (top) {
22449
+ const startX = cornerRadius;
22450
+ const endX = width - cornerRadius;
22451
+ if (endX > startX) {
22452
+ ctx.beginPath();
22453
+ ctx.moveTo(startX, 0);
22454
+ ctx.lineTo(endX, 0);
22455
+ ctx.stroke();
22456
+ }
22457
+ }
22458
+ if (right) {
22459
+ const startY = cornerRadius;
22460
+ const endY = height - cornerRadius;
22461
+ if (endY > startY) {
22462
+ ctx.beginPath();
22463
+ ctx.moveTo(width, startY);
22464
+ ctx.lineTo(width, endY);
22465
+ ctx.stroke();
22466
+ }
22467
+ }
22468
+ if (bottom) {
22469
+ const startX = width - cornerRadius;
22470
+ const endX = cornerRadius;
22471
+ if (startX > endX) {
22472
+ ctx.beginPath();
22473
+ ctx.moveTo(startX, height);
22474
+ ctx.lineTo(endX, height);
22475
+ ctx.stroke();
22476
+ }
22477
+ }
22478
+ if (left) {
22479
+ const startY = height - cornerRadius;
22480
+ const endY = cornerRadius;
22481
+ if (startY > endY) {
22482
+ ctx.beginPath();
22483
+ ctx.moveTo(0, startY);
22484
+ ctx.lineTo(0, endY);
22485
+ ctx.stroke();
22486
+ }
22487
+ }
22488
+ ctx.lineCap = previousCap;
22252
22489
  ctx.restore();
22253
22490
  };
22254
22491
  const measureTextWidthWithSpacing = (ctx, text, letterSpacing) => {
@@ -22574,6 +22811,9 @@ const createSpriteLayer = (options) => {
22574
22811
  totalRotateDeg: totalRotDeg,
22575
22812
  anchor: img.anchor,
22576
22813
  offset: img.offset,
22814
+ effectivePixelsPerMeter,
22815
+ spriteMinPixel,
22816
+ spriteMaxPixel,
22577
22817
  projectToClipSpace,
22578
22818
  drawingBufferWidth,
22579
22819
  drawingBufferHeight,
@@ -23174,6 +23414,9 @@ const createSpriteLayer = (options) => {
23174
23414
  totalRotateDeg,
23175
23415
  anchor,
23176
23416
  offset: offsetDef,
23417
+ effectivePixelsPerMeter,
23418
+ spriteMinPixel,
23419
+ spriteMaxPixel,
23177
23420
  projectToClipSpace: (lng, lat, elevation) => projectLngLatToClipSpace(lng, lat, elevation, clipContext),
23178
23421
  drawingBufferWidth,
23179
23422
  drawingBufferHeight,
@@ -23189,7 +23432,8 @@ const createSpriteLayer = (options) => {
23189
23432
  }
23190
23433
  const offsetMeters = calculateSurfaceOffsetMeters(
23191
23434
  offsetDef,
23192
- imageScale
23435
+ imageScale,
23436
+ zoomScaleFactor
23193
23437
  );
23194
23438
  const cornerDisplacements = calculateSurfaceCornerDisplacements({
23195
23439
  worldWidthMeters: surfaceCenter.worldDimensions.width,
@@ -23384,14 +23628,20 @@ const createSpriteLayer = (options) => {
23384
23628
  imageResource.height,
23385
23629
  baseMetersPerPixel,
23386
23630
  imageScale,
23387
- zoomScaleFactor
23631
+ zoomScaleFactor,
23632
+ {
23633
+ effectivePixelsPerMeter,
23634
+ spriteMinPixel,
23635
+ spriteMaxPixel
23636
+ }
23388
23637
  );
23389
23638
  const totalRotateDeg = Number.isFinite(imageEntry.displayedRotateDeg) ? imageEntry.displayedRotateDeg : normaliseAngleDeg(
23390
23639
  ((_e = imageEntry.resolvedBaseRotateDeg) != null ? _e : 0) + ((_f = imageEntry.rotateDeg) != null ? _f : 0)
23391
23640
  );
23392
23641
  const offsetMeters = calculateSurfaceOffsetMeters(
23393
23642
  offsetResolved,
23394
- imageScale
23643
+ imageScale,
23644
+ zoomScaleFactor
23395
23645
  );
23396
23646
  const cornerDisplacements = calculateSurfaceCornerDisplacements({
23397
23647
  worldWidthMeters: worldDims.width,
@@ -23654,7 +23904,8 @@ const createSpriteLayer = (options) => {
23654
23904
  strokeHeight,
23655
23905
  strokeRadius,
23656
23906
  resolved.borderColor,
23657
- borderWidth
23907
+ borderWidth,
23908
+ resolved.borderSides
23658
23909
  );
23659
23910
  ctx.restore();
23660
23911
  }
@@ -24263,6 +24514,124 @@ const createSpriteLayer = (options) => {
24263
24514
  }
24264
24515
  return updatedCount;
24265
24516
  };
24517
+ const mutateSprites = (sourceItems, mutator) => {
24518
+ if (sourceItems.length === 0) {
24519
+ return 0;
24520
+ }
24521
+ let changedCount = 0;
24522
+ let isRequiredRender = false;
24523
+ let currentSprite = void 0;
24524
+ let didMutateImages = false;
24525
+ const operationResult = {
24526
+ isUpdated: false
24527
+ };
24528
+ const updateObject = {
24529
+ getImageIndexMap: () => {
24530
+ const map2 = /* @__PURE__ */ new Map();
24531
+ currentSprite.images.forEach((inner, subLayer) => {
24532
+ map2.set(subLayer, new Set(inner.keys()));
24533
+ });
24534
+ return map2;
24535
+ },
24536
+ addImage: (subLayer, order, imageInit) => {
24537
+ const added = addSpriteImageInternal(
24538
+ currentSprite,
24539
+ subLayer,
24540
+ order,
24541
+ imageInit,
24542
+ operationResult
24543
+ );
24544
+ if (added) {
24545
+ didMutateImages = true;
24546
+ }
24547
+ return added;
24548
+ },
24549
+ updateImage: (subLayer, order, imageUpdate) => {
24550
+ const updated = updateSpriteImageInternal(
24551
+ currentSprite,
24552
+ subLayer,
24553
+ order,
24554
+ imageUpdate,
24555
+ operationResult
24556
+ );
24557
+ if (updated) {
24558
+ didMutateImages = true;
24559
+ }
24560
+ return updated;
24561
+ },
24562
+ removeImage: (subLayer, order) => {
24563
+ const removed = removeSpriteImageInternal(
24564
+ currentSprite,
24565
+ subLayer,
24566
+ order,
24567
+ operationResult
24568
+ );
24569
+ if (removed) {
24570
+ didMutateImages = true;
24571
+ }
24572
+ return removed;
24573
+ }
24574
+ };
24575
+ for (const sourceItem of sourceItems) {
24576
+ const spriteId = sourceItem.spriteId;
24577
+ const sprite = sprites.get(spriteId);
24578
+ if (!sprite) {
24579
+ const init = mutator.add(sourceItem);
24580
+ if (!init) {
24581
+ continue;
24582
+ }
24583
+ if (addSpriteInternal(spriteId, init)) {
24584
+ changedCount++;
24585
+ isRequiredRender = true;
24586
+ }
24587
+ continue;
24588
+ }
24589
+ currentSprite = sprite;
24590
+ operationResult.isUpdated = false;
24591
+ didMutateImages = false;
24592
+ const decision = mutator.modify(
24593
+ sourceItem,
24594
+ sprite,
24595
+ updateObject
24596
+ );
24597
+ if (decision === "remove") {
24598
+ if (removeSpriteInternal(spriteId)) {
24599
+ changedCount++;
24600
+ isRequiredRender = true;
24601
+ }
24602
+ } else {
24603
+ const updateResult = updateSpriteInternal(spriteId, updateObject);
24604
+ let spriteChanged = false;
24605
+ switch (updateResult) {
24606
+ case "updated":
24607
+ spriteChanged = true;
24608
+ break;
24609
+ case "isRequiredRender":
24610
+ spriteChanged = true;
24611
+ isRequiredRender = true;
24612
+ break;
24613
+ }
24614
+ if (didMutateImages) {
24615
+ spriteChanged = true;
24616
+ isRequiredRender = true;
24617
+ }
24618
+ if (spriteChanged) {
24619
+ changedCount++;
24620
+ }
24621
+ }
24622
+ updateObject.isEnabled = void 0;
24623
+ updateObject.location = void 0;
24624
+ updateObject.interpolation = void 0;
24625
+ updateObject.tag = void 0;
24626
+ operationResult.isUpdated = false;
24627
+ didMutateImages = false;
24628
+ }
24629
+ if (isRequiredRender) {
24630
+ ensureRenderTargetEntries();
24631
+ scheduleRender();
24632
+ }
24633
+ return changedCount;
24634
+ };
24266
24635
  const updateForEach = (updater) => {
24267
24636
  let updatedCount = 0;
24268
24637
  let isRequiredRender = false;
@@ -24351,6 +24720,7 @@ const createSpriteLayer = (options) => {
24351
24720
  removeSpriteImage,
24352
24721
  updateSprite,
24353
24722
  updateBulk,
24723
+ mutateSprites,
24354
24724
  updateForEach,
24355
24725
  on: addEventListener2,
24356
24726
  off: removeEventListener2
@@ -24358,6 +24728,8 @@ const createSpriteLayer = (options) => {
24358
24728
  return spriteLayout;
24359
24729
  };
24360
24730
  export {
24731
+ STANDARD_SPRITE_SCALING_OPTIONS,
24732
+ UNLIMITED_SPRITE_SCALING_OPTIONS,
24361
24733
  applyAutoRotation,
24362
24734
  calculatePerspectiveRatio,
24363
24735
  cloneAnchor,