@india-boundary-corrector/tilefixer 0.2.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
@@ -2326,12 +2326,11 @@ var configs_default = [
2326
2326
  "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}.png",
2327
2327
  "https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}.png"
2328
2328
  ],
2329
- lineWidthStops: { "1": 0.5, "2": 0.75, "3": 0.75, "4": 1, "5": 1, "7": 1.5, "16": 2.5 },
2329
+ lineWidthStops: { "1": 0.5, "2": 0.75, "3": 0.75, "4": 1, "5": 1, "7": 1.75, "16": 2.5 },
2330
2330
  lineStyles: [
2331
2331
  { color: "rgb(235, 214, 214)", layerSuffix: "ne", endZoom: 4, lineExtensionFactor: 0.1, delWidthFactor: 2.5 },
2332
2332
  { color: "rgb(235, 214, 214)", layerSuffix: "ne-disp", endZoom: 4, delWidthFactor: 0 },
2333
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.2, startZoom: 6, endZoom: 11, widthFraction: 5, lineExtensionFactor: 0.1 },
2334
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.2, startZoom: 12, widthFraction: 4, lineExtensionFactor: 0.1 },
2333
+ { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 6, lineWidthStops: { "6": 9, "10": 8, "14": 8 }, lineExtensionFactor: 0.1 },
2335
2334
  { color: "rgb(235, 214, 214)", layerSuffix: "osm", startZoom: 5, lineExtensionFactor: 0.1 },
2336
2335
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", startZoom: 5, delWidthFactor: 0 },
2337
2336
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-internal", startZoom: 5, widthFraction: 0.5, dashArray: [2, 2], delWidthFactor: 2 },
@@ -2354,12 +2353,11 @@ var configs_default = [
2354
2353
  "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png",
2355
2354
  "https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png"
2356
2355
  ],
2357
- lineWidthStops: { "1": 0.75, "2": 0.75, "3": 0.75, "4": 1, "5": 1, "7": 1.5, "11": 2 },
2356
+ lineWidthStops: { "1": 1, "3": 1, "4": 2, "5": 2, "6": 2.5, "7": 3, "8": 3, "10": 4, "11": 4, "12": 4 },
2358
2357
  lineStyles: [
2359
2358
  { color: "rgb(235, 214, 214)", layerSuffix: "ne", endZoom: 4, lineExtensionFactor: 0.1, delWidthFactor: 2.5 },
2360
2359
  { color: "rgb(235, 214, 214)", layerSuffix: "ne-disp", endZoom: 4, delWidthFactor: 0 },
2361
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 6, endZoom: 11, widthFraction: 5, lineExtensionFactor: 0.1 },
2362
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 12, widthFraction: 4, lineExtensionFactor: 0.1 },
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 },
2363
2361
  { color: "rgb(235, 214, 214)", layerSuffix: "osm", startZoom: 5, lineExtensionFactor: 0.1 },
2364
2362
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", startZoom: 5, delWidthFactor: 0 },
2365
2363
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-internal", startZoom: 5, widthFraction: 0.5, dashArray: [4, 4], delWidthFactor: 2 },
@@ -2377,8 +2375,11 @@ var configs_default = [
2377
2375
  { color: "rgb(83, 83, 83)", layerSuffix: "ne", startZoom: 4, endZoom: 6 },
2378
2376
  { color: "rgb(173, 173, 173)", layerSuffix: "osm", startZoom: 7, endZoom: 8, alpha: 0.5, widthFraction: 4 },
2379
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 },
2380
2379
  { color: "rgb(199, 158, 204)", layerSuffix: "osm", startZoom: 9, widthFraction: 7, alpha: 0.6, lineExtensionFactor: 0.2 },
2381
- { 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 }
2382
2383
  ]
2383
2384
  },
2384
2385
  {
@@ -2413,6 +2414,39 @@ var configs_default = [
2413
2414
  var INFINITY = -1;
2414
2415
  var MIN_LINE_WIDTH = 0.1;
2415
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
+ }
2416
2450
  function templateToRegex(template) {
2417
2451
  const groups = [];
2418
2452
  const hasRetina = template.includes("{r}");
@@ -2479,14 +2513,33 @@ function isValidColor(color) {
2479
2513
  if (/^[a-z]+$/.test(trimmed)) return true;
2480
2514
  return false;
2481
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
+ }
2482
2534
  var LineStyle = class _LineStyle {
2483
2535
  /**
2484
2536
  * Validate a LineStyle configuration object.
2485
2537
  * @param {Object} obj - The object to validate
2486
2538
  * @param {number} [index] - Optional index for error messages (when validating in an array)
2539
+ * @param {boolean} [requireLineWidthStops=false] - Whether lineWidthStops is required
2487
2540
  * @throws {Error} If validation fails
2488
2541
  */
2489
- static validateJSON(obj, index) {
2542
+ static validateJSON(obj, index, requireLineWidthStops = false) {
2490
2543
  const prefix = index !== void 0 ? `lineStyles[${index}]` : "LineStyle";
2491
2544
  if (!obj || typeof obj !== "object") {
2492
2545
  throw new Error(`${prefix}: must be an object`);
@@ -2521,22 +2574,30 @@ var LineStyle = class _LineStyle {
2521
2574
  if (obj.delWidthFactor !== void 0 && (typeof obj.delWidthFactor !== "number" || obj.delWidthFactor < 0)) {
2522
2575
  throw new Error(`${prefix}: delWidthFactor must be a non-negative number`);
2523
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
+ }
2524
2583
  }
2525
2584
  /**
2526
2585
  * @param {Object} options
2527
2586
  * @param {string} options.color - CSS color string
2528
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
2529
2589
  * @param {number} [options.widthFraction=1.0] - Multiplier for base line width
2530
2590
  * @param {number[]} [options.dashArray] - Dash pattern for dashed lines
2531
2591
  * @param {number} [options.alpha=1.0] - Opacity (0-1)
2532
2592
  * @param {number} [options.startZoom=0] - Minimum zoom level for this style
2533
2593
  * @param {number} [options.endZoom=INFINITY] - Maximum zoom level for this style (INFINITY means no limit)
2534
- * @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)
2535
2595
  * @param {number} [options.delWidthFactor=1.5] - Factor to multiply line width for deletion blur
2536
2596
  */
2537
- constructor({ color, layerSuffix, widthFraction = 1, dashArray, alpha = 1, startZoom = 0, endZoom = INFINITY, lineExtensionFactor = 0, delWidthFactor = 1.5 }) {
2597
+ constructor({ color, layerSuffix, lineWidthStops, widthFraction = 1, dashArray, alpha = 1, startZoom = 0, endZoom = INFINITY, lineExtensionFactor = 0, delWidthFactor = 1.5 }) {
2538
2598
  this.color = color;
2539
2599
  this.layerSuffix = layerSuffix;
2600
+ this.lineWidthStops = lineWidthStops;
2540
2601
  this.widthFraction = widthFraction;
2541
2602
  this.dashArray = dashArray;
2542
2603
  this.alpha = alpha;
@@ -2545,6 +2606,14 @@ var LineStyle = class _LineStyle {
2545
2606
  this.lineExtensionFactor = lineExtensionFactor;
2546
2607
  this.delWidthFactor = delWidthFactor;
2547
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
+ }
2548
2617
  /**
2549
2618
  * Check if this style is active at the given zoom level.
2550
2619
  * @param {number} z - Zoom level
@@ -2561,6 +2630,7 @@ var LineStyle = class _LineStyle {
2561
2630
  return {
2562
2631
  color: this.color,
2563
2632
  layerSuffix: this.layerSuffix,
2633
+ lineWidthStops: this.lineWidthStops,
2564
2634
  widthFraction: this.widthFraction,
2565
2635
  dashArray: this.dashArray,
2566
2636
  alpha: this.alpha,
@@ -2577,7 +2647,7 @@ var LineStyle = class _LineStyle {
2577
2647
  * @returns {LineStyle}
2578
2648
  */
2579
2649
  static fromJSON(obj, index) {
2580
- _LineStyle.validateJSON(obj, index);
2650
+ _LineStyle.validateJSON(obj, index, true);
2581
2651
  return new _LineStyle(obj);
2582
2652
  }
2583
2653
  };
@@ -2643,9 +2713,13 @@ var LayerConfig = class _LayerConfig {
2643
2713
  this._compiledPatterns = templates.map((t) => templateToRegex(t));
2644
2714
  this._templatePatterns = templates.map((t) => templateToTemplateRegex(t));
2645
2715
  this.lineWidthStops = lineWidthStops;
2646
- this.lineStyles = lineStyles.map(
2647
- (style) => style instanceof LineStyle ? style : new LineStyle(style)
2648
- );
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
+ });
2649
2723
  }
2650
2724
  /**
2651
2725
  * Get line styles active at a given zoom level
@@ -2664,45 +2738,6 @@ var LayerConfig = class _LayerConfig {
2664
2738
  const activeStyles = this.getLineStylesForZoom(z2);
2665
2739
  return [...new Set(activeStyles.map((s) => s.layerSuffix))];
2666
2740
  }
2667
- /**
2668
- * Interpolate or extrapolate line width for a given zoom level.
2669
- * Uses the lineWidthStops map to calculate the appropriate width.
2670
- * @param {number} zoom - Zoom level
2671
- * @returns {number}
2672
- */
2673
- getLineWidth(zoom) {
2674
- const zooms = Object.keys(this.lineWidthStops).map(Number).sort((a, b2) => a - b2);
2675
- if (this.lineWidthStops[zoom] !== void 0) {
2676
- return this.lineWidthStops[zoom];
2677
- }
2678
- if (zoom < zooms[0]) {
2679
- const z1 = zooms[0];
2680
- const z2 = zooms[1];
2681
- const w1 = this.lineWidthStops[z1];
2682
- const w2 = this.lineWidthStops[z2];
2683
- const slope = (w2 - w1) / (z2 - z1);
2684
- return Math.max(MIN_LINE_WIDTH, w1 + slope * (zoom - z1));
2685
- }
2686
- if (zoom > zooms[zooms.length - 1]) {
2687
- const z1 = zooms[zooms.length - 2];
2688
- const z2 = zooms[zooms.length - 1];
2689
- const w1 = this.lineWidthStops[z1];
2690
- const w2 = this.lineWidthStops[z2];
2691
- const slope = (w2 - w1) / (z2 - z1);
2692
- return Math.max(MIN_LINE_WIDTH, w2 + slope * (zoom - z2));
2693
- }
2694
- for (let i = 0; i < zooms.length - 1; i++) {
2695
- if (zoom > zooms[i] && zoom < zooms[i + 1]) {
2696
- const z1 = zooms[i];
2697
- const z2 = zooms[i + 1];
2698
- const w1 = this.lineWidthStops[z1];
2699
- const w2 = this.lineWidthStops[z2];
2700
- const t = (zoom - z1) / (z2 - z1);
2701
- return w1 + t * (w2 - w1);
2702
- }
2703
- }
2704
- return DEFAULT_LINE_WIDTH;
2705
- }
2706
2741
  /**
2707
2742
  * Check if this config matches the given template URLs (with {z}/{x}/{y} placeholders)
2708
2743
  * @param {string | string[]} templates - Single template URL or array of template URLs
@@ -3197,12 +3232,13 @@ var _TileFixer = class _TileFixer {
3197
3232
  const canvas = this._canvas;
3198
3233
  const ctx = canvas.getContext("2d", { willReadFrequently: true });
3199
3234
  ctx.drawImage(imageBitmap, 0, 0, tileSize, tileSize);
3200
- const baseLineWidth = layerConfig.getLineWidth(zoom);
3201
3235
  const delLineWidthBySuffix = {};
3202
3236
  for (const suffix of layerSuffixes) {
3203
3237
  const stylesForSuffix = activeLineStyles.filter((s) => s.layerSuffix === suffix);
3204
- const maxProduct = Math.max(...stylesForSuffix.map((s) => s.widthFraction * s.delWidthFactor));
3205
- 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;
3206
3242
  }
3207
3243
  for (const suffix of layerSuffixes) {
3208
3244
  const delLineWidth = delLineWidthBySuffix[suffix];
@@ -3217,7 +3253,7 @@ var _TileFixer = class _TileFixer {
3217
3253
  }
3218
3254
  }
3219
3255
  for (const style of activeLineStyles) {
3220
- const { color, layerSuffix, widthFraction, dashArray, alpha, lineExtensionFactor } = style;
3256
+ const { color, widthFraction, dashArray, alpha, lineExtensionFactor, layerSuffix } = style;
3221
3257
  const addLayerName = `to-add-${layerSuffix}`;
3222
3258
  let addFeatures = corrections[addLayerName] || [];
3223
3259
  if (addFeatures.length > 0) {
@@ -3225,7 +3261,7 @@ var _TileFixer = class _TileFixer {
3225
3261
  if (lineExtensionFactor > 0) {
3226
3262
  addFeatures = extendFeaturesByFactor(addFeatures, lineExtensionFactor, delLineWidth, tileSize);
3227
3263
  }
3228
- const lineWidth = baseLineWidth * widthFraction;
3264
+ const lineWidth = style.getLineWidth(zoom) * widthFraction;
3229
3265
  drawFeatures(ctx, addFeatures, color, lineWidth, tileSize, dashArray, alpha);
3230
3266
  }
3231
3267
  }