@india-boundary-corrector/tilefixer 0.1.0 → 0.2.1

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
@@ -22,11 +22,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
22
22
  // src/index.js
23
23
  var index_exports = {};
24
24
  __export(index_exports, {
25
- MIN_LINE_WIDTH: () => MIN_LINE_WIDTH,
26
25
  TileFetchError: () => TileFetchError,
27
26
  TileFixer: () => TileFixer,
28
- buildFetchOptions: () => buildFetchOptions,
29
- getLineWidth: () => getLineWidth
27
+ buildFetchOptions: () => buildFetchOptions
30
28
  });
31
29
  module.exports = __toCommonJS(index_exports);
32
30
 
@@ -2274,6 +2272,26 @@ var CorrectionsSource = class {
2274
2272
  var configs_default = [
2275
2273
  {
2276
2274
  id: "cartodb-dark",
2275
+ tileUrlTemplates: [
2276
+ "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png",
2277
+ "https://basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png",
2278
+ "https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png",
2279
+ "https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png",
2280
+ "https://basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png",
2281
+ "https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_nolabels/{z}/{x}/{y}.png"
2282
+ ],
2283
+ lineWidthStops: { "0": 1, "2": 1, "3": 1, "10": 2, "12": 2 },
2284
+ lineStyles: [
2285
+ { color: "rgb(40, 40, 40)", layerSuffix: "ne", endZoom: 4 },
2286
+ { color: "rgb(40, 40, 40)", layerSuffix: "ne-disp", endZoom: 4 },
2287
+ { color: "rgb(40, 40, 40)", layerSuffix: "osm", startZoom: 5 },
2288
+ { color: "rgb(40, 40, 40)", layerSuffix: "osm-disp", startZoom: 5 },
2289
+ { color: "rgb(40, 40, 40)", layerSuffix: "osm-internal", startZoom: 5, widthFraction: 0.3, dashArray: [2, 2], delWidthFactor: 2 },
2290
+ { color: "rgb(40, 40, 40)", layerSuffix: "ne-internal", startZoom: 4, endZoom: 4, widthFraction: 0.3, dashArray: [2, 2], delWidthFactor: 3 }
2291
+ ]
2292
+ },
2293
+ {
2294
+ id: "cartodb-dark-retina",
2277
2295
  tileUrlTemplates: [
2278
2296
  "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
2279
2297
  "https://basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
@@ -2282,17 +2300,45 @@ var configs_default = [
2282
2300
  "https://basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}{r}.png",
2283
2301
  "https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_nolabels/{z}/{x}/{y}{r}.png"
2284
2302
  ],
2285
- lineWidthStops: { "0": 1, "2": 1, "3": 1, "10": 2.5 },
2303
+ lineWidthStops: { "0": 1.5, "2": 1.5, "3": 1.5, "6": 2.5, "10": 3 },
2286
2304
  lineStyles: [
2287
2305
  { color: "rgb(40, 40, 40)", layerSuffix: "ne", endZoom: 4 },
2288
2306
  { color: "rgb(40, 40, 40)", layerSuffix: "ne-disp", endZoom: 4 },
2289
2307
  { color: "rgb(40, 40, 40)", layerSuffix: "osm", startZoom: 5 },
2290
2308
  { color: "rgb(40, 40, 40)", layerSuffix: "osm-disp", startZoom: 5 },
2291
- { color: "rgb(40, 40, 40)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.3, dashArray: [2, 2] }
2309
+ { color: "rgb(40, 40, 40)", layerSuffix: "osm-internal", startZoom: 5, widthFraction: 0.3, dashArray: [4, 4], delWidthFactor: 2 },
2310
+ { color: "rgb(40, 40, 40)", layerSuffix: "ne-internal", startZoom: 4, endZoom: 4, widthFraction: 0.3, dashArray: [4, 4], delWidthFactor: 3 }
2292
2311
  ]
2293
2312
  },
2294
2313
  {
2295
2314
  id: "cartodb-light",
2315
+ tileUrlTemplates: [
2316
+ "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png",
2317
+ "https://basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png",
2318
+ "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png",
2319
+ "https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png",
2320
+ "https://basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png",
2321
+ "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_nolabels/{z}/{x}/{y}.png",
2322
+ "https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png",
2323
+ "https://basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png",
2324
+ "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png",
2325
+ "https://basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png",
2326
+ "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}.png",
2327
+ "https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}.png"
2328
+ ],
2329
+ lineWidthStops: { "1": 0.5, "2": 0.75, "3": 0.75, "4": 1, "5": 1, "7": 1.75, "16": 2.5 },
2330
+ lineStyles: [
2331
+ { color: "rgb(235, 214, 214)", layerSuffix: "ne", endZoom: 4, lineExtensionFactor: 0.1, delWidthFactor: 2.5 },
2332
+ { color: "rgb(235, 214, 214)", layerSuffix: "ne-disp", endZoom: 4, delWidthFactor: 0 },
2333
+ { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 6, lineWidthStops: { "6": 9, "10": 8, "14": 8 }, lineExtensionFactor: 0.1 },
2334
+ { color: "rgb(235, 214, 214)", layerSuffix: "osm", startZoom: 5, lineExtensionFactor: 0.1 },
2335
+ { color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", startZoom: 5, delWidthFactor: 0 },
2336
+ { color: "rgb(235, 214, 214)", layerSuffix: "osm-internal", startZoom: 5, widthFraction: 0.5, dashArray: [2, 2], delWidthFactor: 2 },
2337
+ { color: "rgb(235, 214, 214)", layerSuffix: "ne-internal", startZoom: 4, endZoom: 4, widthFraction: 0.5, dashArray: [2, 2], delWidthFactor: 2.5 }
2338
+ ]
2339
+ },
2340
+ {
2341
+ id: "cartodb-light-retina",
2296
2342
  tileUrlTemplates: [
2297
2343
  "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
2298
2344
  "https://basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
@@ -2307,15 +2353,15 @@ var configs_default = [
2307
2353
  "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png",
2308
2354
  "https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png"
2309
2355
  ],
2310
- lineWidthStops: { "1": 0.5, "2": 0.5, "3": 0.5, "4": 1, "5": 1.25, "7": 1.5, "16": 2.5 },
2356
+ lineWidthStops: { "1": 1, "3": 1, "4": 2, "5": 2, "6": 2.5, "7": 3, "8": 3, "10": 4, "11": 4, "12": 4 },
2311
2357
  lineStyles: [
2312
- { color: "rgb(235, 214, 214)", layerSuffix: "ne", endZoom: 4, lineExtensionFactor: 0.1, delWidthFactor: 2 },
2313
- { color: "rgb(235, 214, 214)", layerSuffix: "ne-disp", endZoom: 4, lineExtensionFactor: 0 },
2314
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.2, startZoom: 6, widthFraction: 3, lineExtensionFactor: 0.1 },
2358
+ { color: "rgb(235, 214, 214)", layerSuffix: "ne", endZoom: 4, lineExtensionFactor: 0.1, delWidthFactor: 2.5 },
2359
+ { color: "rgb(235, 214, 214)", layerSuffix: "ne-disp", endZoom: 4, delWidthFactor: 0 },
2360
+ { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 6, lineWidthStops: { "6": 20, "8": 19, "10": 18, "12": 17 }, lineExtensionFactor: 0.1 },
2315
2361
  { color: "rgb(235, 214, 214)", layerSuffix: "osm", startZoom: 5, lineExtensionFactor: 0.1 },
2316
- { color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", alpha: 0.2, startZoom: 6, widthFraction: 3, lineExtensionFactor: 0 },
2317
- { color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", startZoom: 5, lineExtensionFactor: 0 },
2318
- { color: "rgb(235, 214, 214)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.75, dashArray: [2, 2], delWidthFactor: 2 }
2362
+ { color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", startZoom: 5, delWidthFactor: 0 },
2363
+ { color: "rgb(235, 214, 214)", layerSuffix: "osm-internal", startZoom: 5, widthFraction: 0.5, dashArray: [4, 4], delWidthFactor: 2 },
2364
+ { color: "rgb(235, 214, 214)", layerSuffix: "ne-internal", startZoom: 4, endZoom: 4, widthFraction: 0.5, dashArray: [4, 4], delWidthFactor: 2.5 }
2319
2365
  ]
2320
2366
  },
2321
2367
  {
@@ -2329,8 +2375,11 @@ var configs_default = [
2329
2375
  { color: "rgb(83, 83, 83)", layerSuffix: "ne", startZoom: 4, endZoom: 6 },
2330
2376
  { color: "rgb(173, 173, 173)", layerSuffix: "osm", startZoom: 7, endZoom: 8, alpha: 0.5, widthFraction: 4 },
2331
2377
  { color: "rgb(83, 83, 83)", layerSuffix: "osm", startZoom: 7, endZoom: 8 },
2378
+ { color: "rgb(83, 83, 83)", layerSuffix: "osm-internal", widthFraction: 0.75, startZoom: 7, endZoom: 8 },
2332
2379
  { color: "rgb(199, 158, 204)", layerSuffix: "osm", startZoom: 9, widthFraction: 7, alpha: 0.6, lineExtensionFactor: 0.2 },
2333
- { color: "rgb(175, 41, 203)", layerSuffix: "osm", startZoom: 9, lineExtensionFactor: 0.2 }
2380
+ { color: "rgb(175, 41, 203)", layerSuffix: "osm", startZoom: 9, lineExtensionFactor: 0.2 },
2381
+ { color: "rgb(199, 158, 204)", layerSuffix: "osm-internal", startZoom: 9, widthFraction: 2.25, alpha: 0.6, lineExtensionFactor: 0.2 },
2382
+ { color: "rgb(175, 41, 203)", layerSuffix: "osm-internal", startZoom: 9, widthFactor: 0.75, lineExtensionFactor: 0.2 }
2334
2383
  ]
2335
2384
  },
2336
2385
  {
@@ -2342,10 +2391,10 @@ var configs_default = [
2342
2391
  lineWidthStops: { "1": 0.5, "2": 0.6, "3": 0.7, "4": 1, "10": 3.75 },
2343
2392
  lineStyles: [
2344
2393
  { color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 1, endZoom: 3, delWidthFactor: 2.5, widthFraction: 1.5 },
2345
- { color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 4 },
2346
- { color: "rgb(160, 120, 160)", layerSuffix: "osm", startZoom: 4, widthFraction: 0.333, dashArray: [30, 2, 8, 2] },
2394
+ { color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 4, delWidthFactor: 1.5 },
2395
+ { color: "rgb(160, 120, 160)", layerSuffix: "osm", startZoom: 4, widthFraction: 0.333, dashArray: [30, 2, 8, 2], delWidthFactor: 0 },
2347
2396
  { color: "rgb(200, 180, 200)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.45 },
2348
- { color: "rgb(160, 120, 160)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.15, dashArray: [4, 2, 10] }
2397
+ { color: "rgb(160, 120, 160)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.15, dashArray: [10, 4, 2] }
2349
2398
  ]
2350
2399
  },
2351
2400
  {
@@ -2358,13 +2407,50 @@ var configs_default = [
2358
2407
  lineStyles: [
2359
2408
  { color: "rgb(149, 175, 180)", layerSuffix: "osm", lineExtensionFactor: 0.25, startZoom: 2 },
2360
2409
  { color: "rgb(89, 117, 123)", layerSuffix: "osm", widthFraction: 0.33, lineExtensionFactor: 0.25, startZoom: 2 },
2361
- { color: "rgb(172, 163, 163)", layerSuffix: "osm-internal", widthFraction: 0.33, startZoom: 4, dashArray: [7, 7, 7] }
2410
+ { color: "rgb(172, 163, 163)", layerSuffix: "osm-internal", widthFraction: 0.33, startZoom: 4, dashArray: [7, 7] }
2362
2411
  ]
2363
2412
  }
2364
2413
  ];
2365
2414
  var INFINITY = -1;
2415
+ var MIN_LINE_WIDTH = 0.1;
2416
+ var DEFAULT_LINE_WIDTH = 1;
2417
+ function interpolateLineWidth(zoom, lineWidthStops) {
2418
+ const zooms = Object.keys(lineWidthStops).map(Number).sort((a, b2) => a - b2);
2419
+ if (lineWidthStops[zoom] !== void 0) {
2420
+ return lineWidthStops[zoom];
2421
+ }
2422
+ if (zoom < zooms[0]) {
2423
+ const z1 = zooms[0];
2424
+ const z2 = zooms[1];
2425
+ const w1 = lineWidthStops[z1];
2426
+ const w2 = lineWidthStops[z2];
2427
+ const slope = (w2 - w1) / (z2 - z1);
2428
+ return Math.max(MIN_LINE_WIDTH, w1 + slope * (zoom - z1));
2429
+ }
2430
+ if (zoom > zooms[zooms.length - 1]) {
2431
+ const z1 = zooms[zooms.length - 2];
2432
+ const z2 = zooms[zooms.length - 1];
2433
+ const w1 = lineWidthStops[z1];
2434
+ const w2 = lineWidthStops[z2];
2435
+ const slope = (w2 - w1) / (z2 - z1);
2436
+ return Math.max(MIN_LINE_WIDTH, w2 + slope * (zoom - z2));
2437
+ }
2438
+ for (let i = 0; i < zooms.length - 1; i++) {
2439
+ if (zoom > zooms[i] && zoom < zooms[i + 1]) {
2440
+ const z1 = zooms[i];
2441
+ const z2 = zooms[i + 1];
2442
+ const w1 = lineWidthStops[z1];
2443
+ const w2 = lineWidthStops[z2];
2444
+ const t = (zoom - z1) / (z2 - z1);
2445
+ return w1 + t * (w2 - w1);
2446
+ }
2447
+ }
2448
+ return DEFAULT_LINE_WIDTH;
2449
+ }
2366
2450
  function templateToRegex(template) {
2367
2451
  const groups = [];
2452
+ const hasRetina = template.includes("{r}");
2453
+ const hasExtension = /\.(png|jpg|jpeg|webp|gif)$/i.test(template);
2368
2454
  let pattern = template.replace(/[.*+?^${}()|[\]\\]/g, (char) => {
2369
2455
  if (char === "{" || char === "}") return char;
2370
2456
  return "\\" + char;
@@ -2378,13 +2464,22 @@ function templateToRegex(template) {
2378
2464
  return "([a-z0-9]+)";
2379
2465
  }
2380
2466
  if (lowerName === "r") {
2381
- return "(@\\d+x)?";
2467
+ return "(@\\d+x)";
2382
2468
  }
2383
2469
  return "(\\d+)";
2384
2470
  });
2471
+ if (!hasRetina) {
2472
+ if (hasExtension) {
2473
+ pattern = pattern.replace(/(\\\.(png|jpg|jpeg|webp|gif))/, "(?!@\\d+x)$1");
2474
+ } else {
2475
+ pattern = pattern + "(?!@\\d+x)";
2476
+ }
2477
+ }
2385
2478
  return { pattern: new RegExp("^" + pattern + "(\\?.*)?$", "i"), groups };
2386
2479
  }
2387
2480
  function templateToTemplateRegex(template) {
2481
+ const hasRetina = template.includes("{r}");
2482
+ const hasExtension = /\.(png|jpg|jpeg|webp|gif)$/i.test(template);
2388
2483
  let pattern = template.replace(/[.*+?^${}()|[\]\\]/g, (char) => {
2389
2484
  if (char === "{" || char === "}") return char;
2390
2485
  return "\\" + char;
@@ -2394,10 +2489,17 @@ function templateToTemplateRegex(template) {
2394
2489
  return "(\\{s\\}|\\{[a-z0-9]-[a-z0-9]\\}|[a-z0-9]+)";
2395
2490
  }
2396
2491
  if (lowerName === "r") {
2397
- return "(\\{r\\}|@\\d+x)?";
2492
+ return "(\\{r\\}|@\\d+x)";
2398
2493
  }
2399
2494
  return `\\{${lowerName}\\}`;
2400
2495
  });
2496
+ if (!hasRetina) {
2497
+ if (hasExtension) {
2498
+ pattern = pattern.replace(/(\\\.(png|jpg|jpeg|webp|gif))/, "(?!@\\d+x|\\{r\\})$1");
2499
+ } else {
2500
+ pattern = pattern + "(?!@\\d+x|\\{r\\})";
2501
+ }
2502
+ }
2401
2503
  return new RegExp("^" + pattern + "(\\?.*)?$", "i");
2402
2504
  }
2403
2505
  function isValidColor(color) {
@@ -2411,14 +2513,33 @@ function isValidColor(color) {
2411
2513
  if (/^[a-z]+$/.test(trimmed)) return true;
2412
2514
  return false;
2413
2515
  }
2516
+ function validateLineWidthStops(lineWidthStops, prefix) {
2517
+ if (!lineWidthStops || typeof lineWidthStops !== "object" || Array.isArray(lineWidthStops)) {
2518
+ throw new Error(`${prefix}: lineWidthStops must be an object`);
2519
+ }
2520
+ const stopKeys = Object.keys(lineWidthStops);
2521
+ if (stopKeys.length < 2) {
2522
+ throw new Error(`${prefix}: lineWidthStops must have at least 2 entries`);
2523
+ }
2524
+ for (const key of stopKeys) {
2525
+ const zoom = Number(key);
2526
+ if (!Number.isInteger(zoom) || zoom < 0) {
2527
+ throw new Error(`${prefix}: lineWidthStops keys must be non-negative integers, got "${key}"`);
2528
+ }
2529
+ if (typeof lineWidthStops[key] !== "number" || lineWidthStops[key] <= 0) {
2530
+ throw new Error(`${prefix}: lineWidthStops values must be positive numbers`);
2531
+ }
2532
+ }
2533
+ }
2414
2534
  var LineStyle = class _LineStyle {
2415
2535
  /**
2416
2536
  * Validate a LineStyle configuration object.
2417
2537
  * @param {Object} obj - The object to validate
2418
2538
  * @param {number} [index] - Optional index for error messages (when validating in an array)
2539
+ * @param {boolean} [requireLineWidthStops=false] - Whether lineWidthStops is required
2419
2540
  * @throws {Error} If validation fails
2420
2541
  */
2421
- static validateJSON(obj, index) {
2542
+ static validateJSON(obj, index, requireLineWidthStops = false) {
2422
2543
  const prefix = index !== void 0 ? `lineStyles[${index}]` : "LineStyle";
2423
2544
  if (!obj || typeof obj !== "object") {
2424
2545
  throw new Error(`${prefix}: must be an object`);
@@ -2453,22 +2574,30 @@ var LineStyle = class _LineStyle {
2453
2574
  if (obj.delWidthFactor !== void 0 && (typeof obj.delWidthFactor !== "number" || obj.delWidthFactor < 0)) {
2454
2575
  throw new Error(`${prefix}: delWidthFactor must be a non-negative number`);
2455
2576
  }
2577
+ if (requireLineWidthStops && obj.lineWidthStops === void 0) {
2578
+ throw new Error(`${prefix}: lineWidthStops is required`);
2579
+ }
2580
+ if (obj.lineWidthStops !== void 0) {
2581
+ validateLineWidthStops(obj.lineWidthStops, prefix);
2582
+ }
2456
2583
  }
2457
2584
  /**
2458
2585
  * @param {Object} options
2459
2586
  * @param {string} options.color - CSS color string
2460
2587
  * @param {string} options.layerSuffix - Layer suffix (e.g., 'osm', 'ne', 'osm-disp')
2588
+ * @param {Object<number, number>} options.lineWidthStops - Line width stops for this style
2461
2589
  * @param {number} [options.widthFraction=1.0] - Multiplier for base line width
2462
2590
  * @param {number[]} [options.dashArray] - Dash pattern for dashed lines
2463
2591
  * @param {number} [options.alpha=1.0] - Opacity (0-1)
2464
2592
  * @param {number} [options.startZoom=0] - Minimum zoom level for this style
2465
2593
  * @param {number} [options.endZoom=INFINITY] - Maximum zoom level for this style (INFINITY means no limit)
2466
- * @param {number} [options.lineExtensionFactor=0.5] - Factor to extend lines by (multiplied by deletion line width)
2594
+ * @param {number} [options.lineExtensionFactor=0.0] - Factor to extend lines by (multiplied by deletion line width)
2467
2595
  * @param {number} [options.delWidthFactor=1.5] - Factor to multiply line width for deletion blur
2468
2596
  */
2469
- constructor({ color, layerSuffix, widthFraction = 1, dashArray, alpha = 1, startZoom = 0, endZoom = INFINITY, lineExtensionFactor = 0.5, delWidthFactor = 1.5 }) {
2597
+ constructor({ color, layerSuffix, lineWidthStops, widthFraction = 1, dashArray, alpha = 1, startZoom = 0, endZoom = INFINITY, lineExtensionFactor = 0, delWidthFactor = 1.5 }) {
2470
2598
  this.color = color;
2471
2599
  this.layerSuffix = layerSuffix;
2600
+ this.lineWidthStops = lineWidthStops;
2472
2601
  this.widthFraction = widthFraction;
2473
2602
  this.dashArray = dashArray;
2474
2603
  this.alpha = alpha;
@@ -2477,6 +2606,14 @@ var LineStyle = class _LineStyle {
2477
2606
  this.lineExtensionFactor = lineExtensionFactor;
2478
2607
  this.delWidthFactor = delWidthFactor;
2479
2608
  }
2609
+ /**
2610
+ * Get base line width for this style at a given zoom level.
2611
+ * @param {number} zoom - Zoom level
2612
+ * @returns {number}
2613
+ */
2614
+ getLineWidth(zoom) {
2615
+ return interpolateLineWidth(zoom, this.lineWidthStops);
2616
+ }
2480
2617
  /**
2481
2618
  * Check if this style is active at the given zoom level.
2482
2619
  * @param {number} z - Zoom level
@@ -2493,6 +2630,7 @@ var LineStyle = class _LineStyle {
2493
2630
  return {
2494
2631
  color: this.color,
2495
2632
  layerSuffix: this.layerSuffix,
2633
+ lineWidthStops: this.lineWidthStops,
2496
2634
  widthFraction: this.widthFraction,
2497
2635
  dashArray: this.dashArray,
2498
2636
  alpha: this.alpha,
@@ -2509,7 +2647,7 @@ var LineStyle = class _LineStyle {
2509
2647
  * @returns {LineStyle}
2510
2648
  */
2511
2649
  static fromJSON(obj, index) {
2512
- _LineStyle.validateJSON(obj, index);
2650
+ _LineStyle.validateJSON(obj, index, true);
2513
2651
  return new _LineStyle(obj);
2514
2652
  }
2515
2653
  };
@@ -2575,9 +2713,13 @@ var LayerConfig = class _LayerConfig {
2575
2713
  this._compiledPatterns = templates.map((t) => templateToRegex(t));
2576
2714
  this._templatePatterns = templates.map((t) => templateToTemplateRegex(t));
2577
2715
  this.lineWidthStops = lineWidthStops;
2578
- this.lineStyles = lineStyles.map(
2579
- (style) => style instanceof LineStyle ? style : new LineStyle(style)
2580
- );
2716
+ this.lineStyles = lineStyles.map((style) => {
2717
+ if (style instanceof LineStyle) {
2718
+ return style;
2719
+ }
2720
+ const styleWithStops = style.lineWidthStops ? style : { ...style, lineWidthStops };
2721
+ return new LineStyle(styleWithStops);
2722
+ });
2581
2723
  }
2582
2724
  /**
2583
2725
  * Get line styles active at a given zoom level
@@ -2788,9 +2930,7 @@ var TileFetchError = class _TileFetchError extends Error {
2788
2930
  return new _TileFetchError(response.status, response.url, body);
2789
2931
  }
2790
2932
  };
2791
- var MIN_LINE_WIDTH = 0.1;
2792
2933
  var DEFAULT_TILE_EXTENT = 4096;
2793
- var DEFAULT_LINE_WIDTH = 1;
2794
2934
  function buildFetchOptions(crossOrigin, referrerPolicy) {
2795
2935
  const options = {};
2796
2936
  if (crossOrigin === "use-credentials") {
@@ -2808,39 +2948,6 @@ function buildFetchOptions(crossOrigin, referrerPolicy) {
2808
2948
  }
2809
2949
  return options;
2810
2950
  }
2811
- function getLineWidth(zoom, lineWidthStops) {
2812
- const zooms = Object.keys(lineWidthStops).map(Number).sort((a, b2) => a - b2);
2813
- if (lineWidthStops[zoom] !== void 0) {
2814
- return lineWidthStops[zoom];
2815
- }
2816
- if (zoom < zooms[0]) {
2817
- const z1 = zooms[0];
2818
- const z2 = zooms[1];
2819
- const w1 = lineWidthStops[z1];
2820
- const w2 = lineWidthStops[z2];
2821
- const slope = (w2 - w1) / (z2 - z1);
2822
- return Math.max(MIN_LINE_WIDTH, w1 + slope * (zoom - z1));
2823
- }
2824
- if (zoom > zooms[zooms.length - 1]) {
2825
- const z1 = zooms[zooms.length - 2];
2826
- const z2 = zooms[zooms.length - 1];
2827
- const w1 = lineWidthStops[z1];
2828
- const w2 = lineWidthStops[z2];
2829
- const slope = (w2 - w1) / (z2 - z1);
2830
- return Math.max(MIN_LINE_WIDTH, w2 + slope * (zoom - z2));
2831
- }
2832
- for (let i = 0; i < zooms.length - 1; i++) {
2833
- if (zoom > zooms[i] && zoom < zooms[i + 1]) {
2834
- const z1 = zooms[i];
2835
- const z2 = zooms[i + 1];
2836
- const w1 = lineWidthStops[z1];
2837
- const w2 = lineWidthStops[z2];
2838
- const t = (zoom - z1) / (z2 - z1);
2839
- return w1 + t * (w2 - w1);
2840
- }
2841
- }
2842
- return DEFAULT_LINE_WIDTH;
2843
- }
2844
2951
  function getFeaturesBoundingBox(features, tileSize, padding = 0) {
2845
2952
  let minX = Infinity, minY = Infinity;
2846
2953
  let maxX = -Infinity, maxY = -Infinity;
@@ -3101,7 +3208,6 @@ var _TileFixer = class _TileFixer {
3101
3208
  * @returns {Promise<ArrayBuffer>} The corrected tile as ArrayBuffer (PNG)
3102
3209
  */
3103
3210
  async fixTile(corrections, rasterTile, layerConfig, zoom) {
3104
- const { lineWidthStops } = layerConfig;
3105
3211
  let activeLineStyles;
3106
3212
  if (layerConfig.getLineStylesForZoom) {
3107
3213
  activeLineStyles = layerConfig.getLineStylesForZoom(zoom);
@@ -3126,12 +3232,13 @@ var _TileFixer = class _TileFixer {
3126
3232
  const canvas = this._canvas;
3127
3233
  const ctx = canvas.getContext("2d", { willReadFrequently: true });
3128
3234
  ctx.drawImage(imageBitmap, 0, 0, tileSize, tileSize);
3129
- const baseLineWidth = getLineWidth(zoom, lineWidthStops);
3130
3235
  const delLineWidthBySuffix = {};
3131
3236
  for (const suffix of layerSuffixes) {
3132
3237
  const stylesForSuffix = activeLineStyles.filter((s) => s.layerSuffix === suffix);
3133
- const maxProduct = Math.max(...stylesForSuffix.map((s) => s.widthFraction * s.delWidthFactor));
3134
- delLineWidthBySuffix[suffix] = baseLineWidth * maxProduct;
3238
+ const maxDelWidth = Math.max(...stylesForSuffix.map(
3239
+ (s) => s.getLineWidth(zoom) * s.widthFraction * s.delWidthFactor
3240
+ ));
3241
+ delLineWidthBySuffix[suffix] = maxDelWidth;
3135
3242
  }
3136
3243
  for (const suffix of layerSuffixes) {
3137
3244
  const delLineWidth = delLineWidthBySuffix[suffix];
@@ -3146,7 +3253,7 @@ var _TileFixer = class _TileFixer {
3146
3253
  }
3147
3254
  }
3148
3255
  for (const style of activeLineStyles) {
3149
- const { color, layerSuffix, widthFraction, dashArray, alpha, lineExtensionFactor } = style;
3256
+ const { color, widthFraction, dashArray, alpha, lineExtensionFactor, layerSuffix } = style;
3150
3257
  const addLayerName = `to-add-${layerSuffix}`;
3151
3258
  let addFeatures = corrections[addLayerName] || [];
3152
3259
  if (addFeatures.length > 0) {
@@ -3154,7 +3261,7 @@ var _TileFixer = class _TileFixer {
3154
3261
  if (lineExtensionFactor > 0) {
3155
3262
  addFeatures = extendFeaturesByFactor(addFeatures, lineExtensionFactor, delLineWidth, tileSize);
3156
3263
  }
3157
- const lineWidth = baseLineWidth * widthFraction;
3264
+ const lineWidth = style.getLineWidth(zoom) * widthFraction;
3158
3265
  drawFeatures(ctx, addFeatures, color, lineWidth, tileSize, dashArray, alpha);
3159
3266
  }
3160
3267
  }