@india-boundary-corrector/leaflet-layer 0.2.0 → 0.2.2

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.
@@ -28,7 +28,7 @@ var IndiaBoundaryCorrector = (() => {
28
28
  });
29
29
 
30
30
  // ../data/version.js
31
- var packageVersion = "0.2.0";
31
+ var packageVersion = "0.2.2";
32
32
 
33
33
  // ../data/index.js
34
34
  var import_meta = {};
@@ -126,12 +126,11 @@ var IndiaBoundaryCorrector = (() => {
126
126
  "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}.png",
127
127
  "https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}.png"
128
128
  ],
129
- lineWidthStops: { "1": 0.5, "2": 0.75, "3": 0.75, "4": 1, "5": 1, "7": 1.5, "16": 2.5 },
129
+ lineWidthStops: { "1": 0.5, "2": 0.75, "3": 0.75, "4": 1, "5": 1, "7": 1.75, "16": 2.5 },
130
130
  lineStyles: [
131
131
  { color: "rgb(235, 214, 214)", layerSuffix: "ne", endZoom: 4, lineExtensionFactor: 0.1, delWidthFactor: 2.5 },
132
132
  { color: "rgb(235, 214, 214)", layerSuffix: "ne-disp", endZoom: 4, delWidthFactor: 0 },
133
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.2, startZoom: 6, endZoom: 11, widthFraction: 5, lineExtensionFactor: 0.1 },
134
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.2, startZoom: 12, widthFraction: 4, lineExtensionFactor: 0.1 },
133
+ { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 6, lineWidthStops: { "6": 9, "10": 8, "14": 8 }, lineExtensionFactor: 0.1 },
135
134
  { color: "rgb(235, 214, 214)", layerSuffix: "osm", startZoom: 5, lineExtensionFactor: 0.1 },
136
135
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", startZoom: 5, delWidthFactor: 0 },
137
136
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-internal", startZoom: 5, widthFraction: 0.5, dashArray: [2, 2], delWidthFactor: 2 },
@@ -154,12 +153,11 @@ var IndiaBoundaryCorrector = (() => {
154
153
  "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png",
155
154
  "https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png"
156
155
  ],
157
- lineWidthStops: { "1": 0.75, "2": 0.75, "3": 0.75, "4": 1, "5": 1, "7": 1.5, "11": 2 },
156
+ lineWidthStops: { "1": 1, "3": 1, "4": 2, "5": 2, "6": 2.5, "7": 3, "8": 3, "10": 4, "11": 4, "12": 4 },
158
157
  lineStyles: [
159
158
  { color: "rgb(235, 214, 214)", layerSuffix: "ne", endZoom: 4, lineExtensionFactor: 0.1, delWidthFactor: 2.5 },
160
159
  { color: "rgb(235, 214, 214)", layerSuffix: "ne-disp", endZoom: 4, delWidthFactor: 0 },
161
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 6, endZoom: 11, widthFraction: 5, lineExtensionFactor: 0.1 },
162
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 12, widthFraction: 4, lineExtensionFactor: 0.1 },
160
+ { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 6, lineWidthStops: { "6": 20, "8": 19, "10": 18, "12": 17 }, lineExtensionFactor: 0.1 },
163
161
  { color: "rgb(235, 214, 214)", layerSuffix: "osm", startZoom: 5, lineExtensionFactor: 0.1 },
164
162
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", startZoom: 5, delWidthFactor: 0 },
165
163
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-internal", startZoom: 5, widthFraction: 0.5, dashArray: [4, 4], delWidthFactor: 2 },
@@ -170,15 +168,20 @@ var IndiaBoundaryCorrector = (() => {
170
168
  id: "open-topo",
171
169
  tileUrlTemplates: [
172
170
  "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
173
- "https://tile.opentopomap.org/{z}/{x}/{y}.png"
171
+ "https://tile.opentopomap.org/{z}/{x}/{y}.png",
172
+ "https://{s}.tile.top-o-map.de/{z}/{x}/{y}.png",
173
+ "https://tile.top-o-map.de/{z}/{x}/{y}.png"
174
174
  ],
175
175
  lineWidthStops: { "4": 0.75, "5": 1, "6": 1.25, "7": 1.5, "8": 1.75, "9": 1.25, "10": 1.25, "13": 1.5 },
176
176
  lineStyles: [
177
177
  { color: "rgb(83, 83, 83)", layerSuffix: "ne", startZoom: 4, endZoom: 6 },
178
178
  { color: "rgb(173, 173, 173)", layerSuffix: "osm", startZoom: 7, endZoom: 8, alpha: 0.5, widthFraction: 4 },
179
179
  { color: "rgb(83, 83, 83)", layerSuffix: "osm", startZoom: 7, endZoom: 8 },
180
+ { color: "rgb(83, 83, 83)", layerSuffix: "osm-internal", widthFraction: 0.75, startZoom: 7, endZoom: 8 },
180
181
  { color: "rgb(199, 158, 204)", layerSuffix: "osm", startZoom: 9, widthFraction: 7, alpha: 0.6, lineExtensionFactor: 0.2 },
181
- { color: "rgb(175, 41, 203)", layerSuffix: "osm", startZoom: 9, lineExtensionFactor: 0.2 }
182
+ { color: "rgb(175, 41, 203)", layerSuffix: "osm", startZoom: 9, lineExtensionFactor: 0.2 },
183
+ { color: "rgb(199, 158, 204)", layerSuffix: "osm-internal", startZoom: 9, widthFraction: 2.25, alpha: 0.6, lineExtensionFactor: 0.2 },
184
+ { color: "rgb(175, 41, 203)", layerSuffix: "osm-internal", startZoom: 9, widthFactor: 0.75, lineExtensionFactor: 0.2 }
182
185
  ]
183
186
  },
184
187
  {
@@ -187,9 +190,8 @@ var IndiaBoundaryCorrector = (() => {
187
190
  "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
188
191
  "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
189
192
  ],
190
- lineWidthStops: { "1": 0.5, "2": 0.6, "3": 0.7, "4": 1, "10": 3.75 },
193
+ lineWidthStops: { "3": 0.7, "4": 1, "10": 3.75 },
191
194
  lineStyles: [
192
- { color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 1, endZoom: 3, delWidthFactor: 2.5, widthFraction: 1.5 },
193
195
  { color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 4, delWidthFactor: 1.5 },
194
196
  { color: "rgb(160, 120, 160)", layerSuffix: "osm", startZoom: 4, widthFraction: 0.333, dashArray: [30, 2, 8, 2], delWidthFactor: 0 },
195
197
  { color: "rgb(200, 180, 200)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.45 },
@@ -213,6 +215,39 @@ var IndiaBoundaryCorrector = (() => {
213
215
  var INFINITY = -1;
214
216
  var MIN_LINE_WIDTH = 0.1;
215
217
  var DEFAULT_LINE_WIDTH = 1;
218
+ function interpolateLineWidth(zoom, lineWidthStops) {
219
+ const zooms = Object.keys(lineWidthStops).map(Number).sort((a, b2) => a - b2);
220
+ if (lineWidthStops[zoom] !== void 0) {
221
+ return lineWidthStops[zoom];
222
+ }
223
+ if (zoom < zooms[0]) {
224
+ const z1 = zooms[0];
225
+ const z2 = zooms[1];
226
+ const w1 = lineWidthStops[z1];
227
+ const w2 = lineWidthStops[z2];
228
+ const slope = (w2 - w1) / (z2 - z1);
229
+ return Math.max(MIN_LINE_WIDTH, w1 + slope * (zoom - z1));
230
+ }
231
+ if (zoom > zooms[zooms.length - 1]) {
232
+ const z1 = zooms[zooms.length - 2];
233
+ const z2 = zooms[zooms.length - 1];
234
+ const w1 = lineWidthStops[z1];
235
+ const w2 = lineWidthStops[z2];
236
+ const slope = (w2 - w1) / (z2 - z1);
237
+ return Math.max(MIN_LINE_WIDTH, w2 + slope * (zoom - z2));
238
+ }
239
+ for (let i2 = 0; i2 < zooms.length - 1; i2++) {
240
+ if (zoom > zooms[i2] && zoom < zooms[i2 + 1]) {
241
+ const z1 = zooms[i2];
242
+ const z2 = zooms[i2 + 1];
243
+ const w1 = lineWidthStops[z1];
244
+ const w2 = lineWidthStops[z2];
245
+ const t = (zoom - z1) / (z2 - z1);
246
+ return w1 + t * (w2 - w1);
247
+ }
248
+ }
249
+ return DEFAULT_LINE_WIDTH;
250
+ }
216
251
  function templateToRegex(template) {
217
252
  const groups = [];
218
253
  const hasRetina = template.includes("{r}");
@@ -279,14 +314,33 @@ var IndiaBoundaryCorrector = (() => {
279
314
  if (/^[a-z]+$/.test(trimmed)) return true;
280
315
  return false;
281
316
  }
317
+ function validateLineWidthStops(lineWidthStops, prefix) {
318
+ if (!lineWidthStops || typeof lineWidthStops !== "object" || Array.isArray(lineWidthStops)) {
319
+ throw new Error(`${prefix}: lineWidthStops must be an object`);
320
+ }
321
+ const stopKeys = Object.keys(lineWidthStops);
322
+ if (stopKeys.length < 2) {
323
+ throw new Error(`${prefix}: lineWidthStops must have at least 2 entries`);
324
+ }
325
+ for (const key of stopKeys) {
326
+ const zoom = Number(key);
327
+ if (!Number.isInteger(zoom) || zoom < 0) {
328
+ throw new Error(`${prefix}: lineWidthStops keys must be non-negative integers, got "${key}"`);
329
+ }
330
+ if (typeof lineWidthStops[key] !== "number" || lineWidthStops[key] <= 0) {
331
+ throw new Error(`${prefix}: lineWidthStops values must be positive numbers`);
332
+ }
333
+ }
334
+ }
282
335
  var LineStyle = class _LineStyle {
283
336
  /**
284
337
  * Validate a LineStyle configuration object.
285
338
  * @param {Object} obj - The object to validate
286
339
  * @param {number} [index] - Optional index for error messages (when validating in an array)
340
+ * @param {boolean} [requireLineWidthStops=false] - Whether lineWidthStops is required
287
341
  * @throws {Error} If validation fails
288
342
  */
289
- static validateJSON(obj, index) {
343
+ static validateJSON(obj, index, requireLineWidthStops = false) {
290
344
  const prefix = index !== void 0 ? `lineStyles[${index}]` : "LineStyle";
291
345
  if (!obj || typeof obj !== "object") {
292
346
  throw new Error(`${prefix}: must be an object`);
@@ -321,22 +375,30 @@ var IndiaBoundaryCorrector = (() => {
321
375
  if (obj.delWidthFactor !== void 0 && (typeof obj.delWidthFactor !== "number" || obj.delWidthFactor < 0)) {
322
376
  throw new Error(`${prefix}: delWidthFactor must be a non-negative number`);
323
377
  }
378
+ if (requireLineWidthStops && obj.lineWidthStops === void 0) {
379
+ throw new Error(`${prefix}: lineWidthStops is required`);
380
+ }
381
+ if (obj.lineWidthStops !== void 0) {
382
+ validateLineWidthStops(obj.lineWidthStops, prefix);
383
+ }
324
384
  }
325
385
  /**
326
386
  * @param {Object} options
327
387
  * @param {string} options.color - CSS color string
328
388
  * @param {string} options.layerSuffix - Layer suffix (e.g., 'osm', 'ne', 'osm-disp')
389
+ * @param {Object<number, number>} options.lineWidthStops - Line width stops for this style
329
390
  * @param {number} [options.widthFraction=1.0] - Multiplier for base line width
330
391
  * @param {number[]} [options.dashArray] - Dash pattern for dashed lines
331
392
  * @param {number} [options.alpha=1.0] - Opacity (0-1)
332
393
  * @param {number} [options.startZoom=0] - Minimum zoom level for this style
333
394
  * @param {number} [options.endZoom=INFINITY] - Maximum zoom level for this style (INFINITY means no limit)
334
- * @param {number} [options.lineExtensionFactor=0.5] - Factor to extend lines by (multiplied by deletion line width)
395
+ * @param {number} [options.lineExtensionFactor=0.0] - Factor to extend lines by (multiplied by deletion line width)
335
396
  * @param {number} [options.delWidthFactor=1.5] - Factor to multiply line width for deletion blur
336
397
  */
337
- constructor({ color, layerSuffix, widthFraction = 1, dashArray, alpha = 1, startZoom = 0, endZoom = INFINITY, lineExtensionFactor = 0, delWidthFactor = 1.5 }) {
398
+ constructor({ color, layerSuffix, lineWidthStops, widthFraction = 1, dashArray, alpha = 1, startZoom = 0, endZoom = INFINITY, lineExtensionFactor = 0, delWidthFactor = 1.5 }) {
338
399
  this.color = color;
339
400
  this.layerSuffix = layerSuffix;
401
+ this.lineWidthStops = lineWidthStops;
340
402
  this.widthFraction = widthFraction;
341
403
  this.dashArray = dashArray;
342
404
  this.alpha = alpha;
@@ -345,6 +407,14 @@ var IndiaBoundaryCorrector = (() => {
345
407
  this.lineExtensionFactor = lineExtensionFactor;
346
408
  this.delWidthFactor = delWidthFactor;
347
409
  }
410
+ /**
411
+ * Get base line width for this style at a given zoom level.
412
+ * @param {number} zoom - Zoom level
413
+ * @returns {number}
414
+ */
415
+ getLineWidth(zoom) {
416
+ return interpolateLineWidth(zoom, this.lineWidthStops);
417
+ }
348
418
  /**
349
419
  * Check if this style is active at the given zoom level.
350
420
  * @param {number} z - Zoom level
@@ -361,6 +431,7 @@ var IndiaBoundaryCorrector = (() => {
361
431
  return {
362
432
  color: this.color,
363
433
  layerSuffix: this.layerSuffix,
434
+ lineWidthStops: this.lineWidthStops,
364
435
  widthFraction: this.widthFraction,
365
436
  dashArray: this.dashArray,
366
437
  alpha: this.alpha,
@@ -377,7 +448,7 @@ var IndiaBoundaryCorrector = (() => {
377
448
  * @returns {LineStyle}
378
449
  */
379
450
  static fromJSON(obj, index) {
380
- _LineStyle.validateJSON(obj, index);
451
+ _LineStyle.validateJSON(obj, index, true);
381
452
  return new _LineStyle(obj);
382
453
  }
383
454
  };
@@ -443,9 +514,13 @@ var IndiaBoundaryCorrector = (() => {
443
514
  this._compiledPatterns = templates.map((t) => templateToRegex(t));
444
515
  this._templatePatterns = templates.map((t) => templateToTemplateRegex(t));
445
516
  this.lineWidthStops = lineWidthStops;
446
- this.lineStyles = lineStyles.map(
447
- (style) => style instanceof LineStyle ? style : new LineStyle(style)
448
- );
517
+ this.lineStyles = lineStyles.map((style) => {
518
+ if (style instanceof LineStyle) {
519
+ return style;
520
+ }
521
+ const styleWithStops = style.lineWidthStops ? style : { ...style, lineWidthStops };
522
+ return new LineStyle(styleWithStops);
523
+ });
449
524
  }
450
525
  /**
451
526
  * Get line styles active at a given zoom level
@@ -464,45 +539,6 @@ var IndiaBoundaryCorrector = (() => {
464
539
  const activeStyles = this.getLineStylesForZoom(z2);
465
540
  return [...new Set(activeStyles.map((s) => s.layerSuffix))];
466
541
  }
467
- /**
468
- * Interpolate or extrapolate line width for a given zoom level.
469
- * Uses the lineWidthStops map to calculate the appropriate width.
470
- * @param {number} zoom - Zoom level
471
- * @returns {number}
472
- */
473
- getLineWidth(zoom) {
474
- const zooms = Object.keys(this.lineWidthStops).map(Number).sort((a, b2) => a - b2);
475
- if (this.lineWidthStops[zoom] !== void 0) {
476
- return this.lineWidthStops[zoom];
477
- }
478
- if (zoom < zooms[0]) {
479
- const z1 = zooms[0];
480
- const z2 = zooms[1];
481
- const w1 = this.lineWidthStops[z1];
482
- const w2 = this.lineWidthStops[z2];
483
- const slope = (w2 - w1) / (z2 - z1);
484
- return Math.max(MIN_LINE_WIDTH, w1 + slope * (zoom - z1));
485
- }
486
- if (zoom > zooms[zooms.length - 1]) {
487
- const z1 = zooms[zooms.length - 2];
488
- const z2 = zooms[zooms.length - 1];
489
- const w1 = this.lineWidthStops[z1];
490
- const w2 = this.lineWidthStops[z2];
491
- const slope = (w2 - w1) / (z2 - z1);
492
- return Math.max(MIN_LINE_WIDTH, w2 + slope * (zoom - z2));
493
- }
494
- for (let i2 = 0; i2 < zooms.length - 1; i2++) {
495
- if (zoom > zooms[i2] && zoom < zooms[i2 + 1]) {
496
- const z1 = zooms[i2];
497
- const z2 = zooms[i2 + 1];
498
- const w1 = this.lineWidthStops[z1];
499
- const w2 = this.lineWidthStops[z2];
500
- const t = (zoom - z1) / (z2 - z1);
501
- return w1 + t * (w2 - w1);
502
- }
503
- }
504
- return DEFAULT_LINE_WIDTH;
505
- }
506
542
  /**
507
543
  * Check if this config matches the given template URLs (with {z}/{x}/{y} placeholders)
508
544
  * @param {string | string[]} templates - Single template URL or array of template URLs
@@ -2956,12 +2992,11 @@ var IndiaBoundaryCorrector = (() => {
2956
2992
  "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}.png",
2957
2993
  "https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}.png"
2958
2994
  ],
2959
- lineWidthStops: { "1": 0.5, "2": 0.75, "3": 0.75, "4": 1, "5": 1, "7": 1.5, "16": 2.5 },
2995
+ lineWidthStops: { "1": 0.5, "2": 0.75, "3": 0.75, "4": 1, "5": 1, "7": 1.75, "16": 2.5 },
2960
2996
  lineStyles: [
2961
2997
  { color: "rgb(235, 214, 214)", layerSuffix: "ne", endZoom: 4, lineExtensionFactor: 0.1, delWidthFactor: 2.5 },
2962
2998
  { color: "rgb(235, 214, 214)", layerSuffix: "ne-disp", endZoom: 4, delWidthFactor: 0 },
2963
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.2, startZoom: 6, endZoom: 11, widthFraction: 5, lineExtensionFactor: 0.1 },
2964
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.2, startZoom: 12, widthFraction: 4, lineExtensionFactor: 0.1 },
2999
+ { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 6, lineWidthStops: { "6": 9, "10": 8, "14": 8 }, lineExtensionFactor: 0.1 },
2965
3000
  { color: "rgb(235, 214, 214)", layerSuffix: "osm", startZoom: 5, lineExtensionFactor: 0.1 },
2966
3001
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", startZoom: 5, delWidthFactor: 0 },
2967
3002
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-internal", startZoom: 5, widthFraction: 0.5, dashArray: [2, 2], delWidthFactor: 2 },
@@ -2984,12 +3019,11 @@ var IndiaBoundaryCorrector = (() => {
2984
3019
  "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png",
2985
3020
  "https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png"
2986
3021
  ],
2987
- lineWidthStops: { "1": 0.75, "2": 0.75, "3": 0.75, "4": 1, "5": 1, "7": 1.5, "11": 2 },
3022
+ lineWidthStops: { "1": 1, "3": 1, "4": 2, "5": 2, "6": 2.5, "7": 3, "8": 3, "10": 4, "11": 4, "12": 4 },
2988
3023
  lineStyles: [
2989
3024
  { color: "rgb(235, 214, 214)", layerSuffix: "ne", endZoom: 4, lineExtensionFactor: 0.1, delWidthFactor: 2.5 },
2990
3025
  { color: "rgb(235, 214, 214)", layerSuffix: "ne-disp", endZoom: 4, delWidthFactor: 0 },
2991
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 6, endZoom: 11, widthFraction: 5, lineExtensionFactor: 0.1 },
2992
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 12, widthFraction: 4, lineExtensionFactor: 0.1 },
3026
+ { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 6, lineWidthStops: { "6": 20, "8": 19, "10": 18, "12": 17 }, lineExtensionFactor: 0.1 },
2993
3027
  { color: "rgb(235, 214, 214)", layerSuffix: "osm", startZoom: 5, lineExtensionFactor: 0.1 },
2994
3028
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", startZoom: 5, delWidthFactor: 0 },
2995
3029
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-internal", startZoom: 5, widthFraction: 0.5, dashArray: [4, 4], delWidthFactor: 2 },
@@ -3000,15 +3034,20 @@ var IndiaBoundaryCorrector = (() => {
3000
3034
  id: "open-topo",
3001
3035
  tileUrlTemplates: [
3002
3036
  "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
3003
- "https://tile.opentopomap.org/{z}/{x}/{y}.png"
3037
+ "https://tile.opentopomap.org/{z}/{x}/{y}.png",
3038
+ "https://{s}.tile.top-o-map.de/{z}/{x}/{y}.png",
3039
+ "https://tile.top-o-map.de/{z}/{x}/{y}.png"
3004
3040
  ],
3005
3041
  lineWidthStops: { "4": 0.75, "5": 1, "6": 1.25, "7": 1.5, "8": 1.75, "9": 1.25, "10": 1.25, "13": 1.5 },
3006
3042
  lineStyles: [
3007
3043
  { color: "rgb(83, 83, 83)", layerSuffix: "ne", startZoom: 4, endZoom: 6 },
3008
3044
  { color: "rgb(173, 173, 173)", layerSuffix: "osm", startZoom: 7, endZoom: 8, alpha: 0.5, widthFraction: 4 },
3009
3045
  { color: "rgb(83, 83, 83)", layerSuffix: "osm", startZoom: 7, endZoom: 8 },
3046
+ { color: "rgb(83, 83, 83)", layerSuffix: "osm-internal", widthFraction: 0.75, startZoom: 7, endZoom: 8 },
3010
3047
  { color: "rgb(199, 158, 204)", layerSuffix: "osm", startZoom: 9, widthFraction: 7, alpha: 0.6, lineExtensionFactor: 0.2 },
3011
- { color: "rgb(175, 41, 203)", layerSuffix: "osm", startZoom: 9, lineExtensionFactor: 0.2 }
3048
+ { color: "rgb(175, 41, 203)", layerSuffix: "osm", startZoom: 9, lineExtensionFactor: 0.2 },
3049
+ { color: "rgb(199, 158, 204)", layerSuffix: "osm-internal", startZoom: 9, widthFraction: 2.25, alpha: 0.6, lineExtensionFactor: 0.2 },
3050
+ { color: "rgb(175, 41, 203)", layerSuffix: "osm-internal", startZoom: 9, widthFactor: 0.75, lineExtensionFactor: 0.2 }
3012
3051
  ]
3013
3052
  },
3014
3053
  {
@@ -3017,9 +3056,8 @@ var IndiaBoundaryCorrector = (() => {
3017
3056
  "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
3018
3057
  "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
3019
3058
  ],
3020
- lineWidthStops: { "1": 0.5, "2": 0.6, "3": 0.7, "4": 1, "10": 3.75 },
3059
+ lineWidthStops: { "3": 0.7, "4": 1, "10": 3.75 },
3021
3060
  lineStyles: [
3022
- { color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 1, endZoom: 3, delWidthFactor: 2.5, widthFraction: 1.5 },
3023
3061
  { color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 4, delWidthFactor: 1.5 },
3024
3062
  { color: "rgb(160, 120, 160)", layerSuffix: "osm", startZoom: 4, widthFraction: 0.333, dashArray: [30, 2, 8, 2], delWidthFactor: 0 },
3025
3063
  { color: "rgb(200, 180, 200)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.45 },
@@ -3043,6 +3081,39 @@ var IndiaBoundaryCorrector = (() => {
3043
3081
  var INFINITY2 = -1;
3044
3082
  var MIN_LINE_WIDTH2 = 0.1;
3045
3083
  var DEFAULT_LINE_WIDTH2 = 1;
3084
+ function interpolateLineWidth2(zoom, lineWidthStops) {
3085
+ const zooms = Object.keys(lineWidthStops).map(Number).sort((a, b2) => a - b2);
3086
+ if (lineWidthStops[zoom] !== void 0) {
3087
+ return lineWidthStops[zoom];
3088
+ }
3089
+ if (zoom < zooms[0]) {
3090
+ const z1 = zooms[0];
3091
+ const z2 = zooms[1];
3092
+ const w1 = lineWidthStops[z1];
3093
+ const w2 = lineWidthStops[z2];
3094
+ const slope = (w2 - w1) / (z2 - z1);
3095
+ return Math.max(MIN_LINE_WIDTH2, w1 + slope * (zoom - z1));
3096
+ }
3097
+ if (zoom > zooms[zooms.length - 1]) {
3098
+ const z1 = zooms[zooms.length - 2];
3099
+ const z2 = zooms[zooms.length - 1];
3100
+ const w1 = lineWidthStops[z1];
3101
+ const w2 = lineWidthStops[z2];
3102
+ const slope = (w2 - w1) / (z2 - z1);
3103
+ return Math.max(MIN_LINE_WIDTH2, w2 + slope * (zoom - z2));
3104
+ }
3105
+ for (let i2 = 0; i2 < zooms.length - 1; i2++) {
3106
+ if (zoom > zooms[i2] && zoom < zooms[i2 + 1]) {
3107
+ const z1 = zooms[i2];
3108
+ const z2 = zooms[i2 + 1];
3109
+ const w1 = lineWidthStops[z1];
3110
+ const w2 = lineWidthStops[z2];
3111
+ const t = (zoom - z1) / (z2 - z1);
3112
+ return w1 + t * (w2 - w1);
3113
+ }
3114
+ }
3115
+ return DEFAULT_LINE_WIDTH2;
3116
+ }
3046
3117
  function templateToRegex2(template) {
3047
3118
  const groups = [];
3048
3119
  const hasRetina = template.includes("{r}");
@@ -3109,14 +3180,33 @@ var IndiaBoundaryCorrector = (() => {
3109
3180
  if (/^[a-z]+$/.test(trimmed)) return true;
3110
3181
  return false;
3111
3182
  }
3183
+ function validateLineWidthStops2(lineWidthStops, prefix) {
3184
+ if (!lineWidthStops || typeof lineWidthStops !== "object" || Array.isArray(lineWidthStops)) {
3185
+ throw new Error(`${prefix}: lineWidthStops must be an object`);
3186
+ }
3187
+ const stopKeys = Object.keys(lineWidthStops);
3188
+ if (stopKeys.length < 2) {
3189
+ throw new Error(`${prefix}: lineWidthStops must have at least 2 entries`);
3190
+ }
3191
+ for (const key of stopKeys) {
3192
+ const zoom = Number(key);
3193
+ if (!Number.isInteger(zoom) || zoom < 0) {
3194
+ throw new Error(`${prefix}: lineWidthStops keys must be non-negative integers, got "${key}"`);
3195
+ }
3196
+ if (typeof lineWidthStops[key] !== "number" || lineWidthStops[key] <= 0) {
3197
+ throw new Error(`${prefix}: lineWidthStops values must be positive numbers`);
3198
+ }
3199
+ }
3200
+ }
3112
3201
  var LineStyle2 = class _LineStyle2 {
3113
3202
  /**
3114
3203
  * Validate a LineStyle configuration object.
3115
3204
  * @param {Object} obj - The object to validate
3116
3205
  * @param {number} [index] - Optional index for error messages (when validating in an array)
3206
+ * @param {boolean} [requireLineWidthStops=false] - Whether lineWidthStops is required
3117
3207
  * @throws {Error} If validation fails
3118
3208
  */
3119
- static validateJSON(obj, index) {
3209
+ static validateJSON(obj, index, requireLineWidthStops = false) {
3120
3210
  const prefix = index !== void 0 ? `lineStyles[${index}]` : "LineStyle";
3121
3211
  if (!obj || typeof obj !== "object") {
3122
3212
  throw new Error(`${prefix}: must be an object`);
@@ -3151,22 +3241,30 @@ var IndiaBoundaryCorrector = (() => {
3151
3241
  if (obj.delWidthFactor !== void 0 && (typeof obj.delWidthFactor !== "number" || obj.delWidthFactor < 0)) {
3152
3242
  throw new Error(`${prefix}: delWidthFactor must be a non-negative number`);
3153
3243
  }
3244
+ if (requireLineWidthStops && obj.lineWidthStops === void 0) {
3245
+ throw new Error(`${prefix}: lineWidthStops is required`);
3246
+ }
3247
+ if (obj.lineWidthStops !== void 0) {
3248
+ validateLineWidthStops2(obj.lineWidthStops, prefix);
3249
+ }
3154
3250
  }
3155
3251
  /**
3156
3252
  * @param {Object} options
3157
3253
  * @param {string} options.color - CSS color string
3158
3254
  * @param {string} options.layerSuffix - Layer suffix (e.g., 'osm', 'ne', 'osm-disp')
3255
+ * @param {Object<number, number>} options.lineWidthStops - Line width stops for this style
3159
3256
  * @param {number} [options.widthFraction=1.0] - Multiplier for base line width
3160
3257
  * @param {number[]} [options.dashArray] - Dash pattern for dashed lines
3161
3258
  * @param {number} [options.alpha=1.0] - Opacity (0-1)
3162
3259
  * @param {number} [options.startZoom=0] - Minimum zoom level for this style
3163
3260
  * @param {number} [options.endZoom=INFINITY] - Maximum zoom level for this style (INFINITY means no limit)
3164
- * @param {number} [options.lineExtensionFactor=0.5] - Factor to extend lines by (multiplied by deletion line width)
3261
+ * @param {number} [options.lineExtensionFactor=0.0] - Factor to extend lines by (multiplied by deletion line width)
3165
3262
  * @param {number} [options.delWidthFactor=1.5] - Factor to multiply line width for deletion blur
3166
3263
  */
3167
- constructor({ color, layerSuffix, widthFraction = 1, dashArray, alpha = 1, startZoom = 0, endZoom = INFINITY2, lineExtensionFactor = 0, delWidthFactor = 1.5 }) {
3264
+ constructor({ color, layerSuffix, lineWidthStops, widthFraction = 1, dashArray, alpha = 1, startZoom = 0, endZoom = INFINITY2, lineExtensionFactor = 0, delWidthFactor = 1.5 }) {
3168
3265
  this.color = color;
3169
3266
  this.layerSuffix = layerSuffix;
3267
+ this.lineWidthStops = lineWidthStops;
3170
3268
  this.widthFraction = widthFraction;
3171
3269
  this.dashArray = dashArray;
3172
3270
  this.alpha = alpha;
@@ -3175,6 +3273,14 @@ var IndiaBoundaryCorrector = (() => {
3175
3273
  this.lineExtensionFactor = lineExtensionFactor;
3176
3274
  this.delWidthFactor = delWidthFactor;
3177
3275
  }
3276
+ /**
3277
+ * Get base line width for this style at a given zoom level.
3278
+ * @param {number} zoom - Zoom level
3279
+ * @returns {number}
3280
+ */
3281
+ getLineWidth(zoom) {
3282
+ return interpolateLineWidth2(zoom, this.lineWidthStops);
3283
+ }
3178
3284
  /**
3179
3285
  * Check if this style is active at the given zoom level.
3180
3286
  * @param {number} z - Zoom level
@@ -3191,6 +3297,7 @@ var IndiaBoundaryCorrector = (() => {
3191
3297
  return {
3192
3298
  color: this.color,
3193
3299
  layerSuffix: this.layerSuffix,
3300
+ lineWidthStops: this.lineWidthStops,
3194
3301
  widthFraction: this.widthFraction,
3195
3302
  dashArray: this.dashArray,
3196
3303
  alpha: this.alpha,
@@ -3207,7 +3314,7 @@ var IndiaBoundaryCorrector = (() => {
3207
3314
  * @returns {LineStyle}
3208
3315
  */
3209
3316
  static fromJSON(obj, index) {
3210
- _LineStyle2.validateJSON(obj, index);
3317
+ _LineStyle2.validateJSON(obj, index, true);
3211
3318
  return new _LineStyle2(obj);
3212
3319
  }
3213
3320
  };
@@ -3273,9 +3380,13 @@ var IndiaBoundaryCorrector = (() => {
3273
3380
  this._compiledPatterns = templates.map((t) => templateToRegex2(t));
3274
3381
  this._templatePatterns = templates.map((t) => templateToTemplateRegex2(t));
3275
3382
  this.lineWidthStops = lineWidthStops;
3276
- this.lineStyles = lineStyles.map(
3277
- (style) => style instanceof LineStyle2 ? style : new LineStyle2(style)
3278
- );
3383
+ this.lineStyles = lineStyles.map((style) => {
3384
+ if (style instanceof LineStyle2) {
3385
+ return style;
3386
+ }
3387
+ const styleWithStops = style.lineWidthStops ? style : { ...style, lineWidthStops };
3388
+ return new LineStyle2(styleWithStops);
3389
+ });
3279
3390
  }
3280
3391
  /**
3281
3392
  * Get line styles active at a given zoom level
@@ -3294,45 +3405,6 @@ var IndiaBoundaryCorrector = (() => {
3294
3405
  const activeStyles = this.getLineStylesForZoom(z2);
3295
3406
  return [...new Set(activeStyles.map((s) => s.layerSuffix))];
3296
3407
  }
3297
- /**
3298
- * Interpolate or extrapolate line width for a given zoom level.
3299
- * Uses the lineWidthStops map to calculate the appropriate width.
3300
- * @param {number} zoom - Zoom level
3301
- * @returns {number}
3302
- */
3303
- getLineWidth(zoom) {
3304
- const zooms = Object.keys(this.lineWidthStops).map(Number).sort((a, b2) => a - b2);
3305
- if (this.lineWidthStops[zoom] !== void 0) {
3306
- return this.lineWidthStops[zoom];
3307
- }
3308
- if (zoom < zooms[0]) {
3309
- const z1 = zooms[0];
3310
- const z2 = zooms[1];
3311
- const w1 = this.lineWidthStops[z1];
3312
- const w2 = this.lineWidthStops[z2];
3313
- const slope = (w2 - w1) / (z2 - z1);
3314
- return Math.max(MIN_LINE_WIDTH2, w1 + slope * (zoom - z1));
3315
- }
3316
- if (zoom > zooms[zooms.length - 1]) {
3317
- const z1 = zooms[zooms.length - 2];
3318
- const z2 = zooms[zooms.length - 1];
3319
- const w1 = this.lineWidthStops[z1];
3320
- const w2 = this.lineWidthStops[z2];
3321
- const slope = (w2 - w1) / (z2 - z1);
3322
- return Math.max(MIN_LINE_WIDTH2, w2 + slope * (zoom - z2));
3323
- }
3324
- for (let i2 = 0; i2 < zooms.length - 1; i2++) {
3325
- if (zoom > zooms[i2] && zoom < zooms[i2 + 1]) {
3326
- const z1 = zooms[i2];
3327
- const z2 = zooms[i2 + 1];
3328
- const w1 = this.lineWidthStops[z1];
3329
- const w2 = this.lineWidthStops[z2];
3330
- const t = (zoom - z1) / (z2 - z1);
3331
- return w1 + t * (w2 - w1);
3332
- }
3333
- }
3334
- return DEFAULT_LINE_WIDTH2;
3335
- }
3336
3408
  /**
3337
3409
  * Check if this config matches the given template URLs (with {z}/{x}/{y} placeholders)
3338
3410
  * @param {string | string[]} templates - Single template URL or array of template URLs
@@ -3825,12 +3897,13 @@ var IndiaBoundaryCorrector = (() => {
3825
3897
  const canvas = this._canvas;
3826
3898
  const ctx = canvas.getContext("2d", { willReadFrequently: true });
3827
3899
  ctx.drawImage(imageBitmap, 0, 0, tileSize, tileSize);
3828
- const baseLineWidth = layerConfig.getLineWidth(zoom);
3829
3900
  const delLineWidthBySuffix = {};
3830
3901
  for (const suffix of layerSuffixes) {
3831
3902
  const stylesForSuffix = activeLineStyles.filter((s) => s.layerSuffix === suffix);
3832
- const maxProduct = Math.max(...stylesForSuffix.map((s) => s.widthFraction * s.delWidthFactor));
3833
- delLineWidthBySuffix[suffix] = baseLineWidth * maxProduct;
3903
+ const maxDelWidth = Math.max(...stylesForSuffix.map(
3904
+ (s) => s.getLineWidth(zoom) * s.widthFraction * s.delWidthFactor
3905
+ ));
3906
+ delLineWidthBySuffix[suffix] = maxDelWidth;
3834
3907
  }
3835
3908
  for (const suffix of layerSuffixes) {
3836
3909
  const delLineWidth = delLineWidthBySuffix[suffix];
@@ -3845,7 +3918,7 @@ var IndiaBoundaryCorrector = (() => {
3845
3918
  }
3846
3919
  }
3847
3920
  for (const style of activeLineStyles) {
3848
- const { color, layerSuffix, widthFraction, dashArray, alpha, lineExtensionFactor } = style;
3921
+ const { color, widthFraction, dashArray, alpha, lineExtensionFactor, layerSuffix } = style;
3849
3922
  const addLayerName = `to-add-${layerSuffix}`;
3850
3923
  let addFeatures = corrections[addLayerName] || [];
3851
3924
  if (addFeatures.length > 0) {
@@ -3853,7 +3926,7 @@ var IndiaBoundaryCorrector = (() => {
3853
3926
  if (lineExtensionFactor > 0) {
3854
3927
  addFeatures = extendFeaturesByFactor(addFeatures, lineExtensionFactor, delLineWidth, tileSize);
3855
3928
  }
3856
- const lineWidth = baseLineWidth * widthFraction;
3929
+ const lineWidth = style.getLineWidth(zoom) * widthFraction;
3857
3930
  drawFeatures(ctx, addFeatures, color, lineWidth, tileSize, dashArray, alpha);
3858
3931
  }
3859
3932
  }