@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.
package/dist/index.js CHANGED
@@ -59,12 +59,11 @@ var configs_default = [
59
59
  "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}.png",
60
60
  "https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}.png"
61
61
  ],
62
- lineWidthStops: { "1": 0.5, "2": 0.75, "3": 0.75, "4": 1, "5": 1, "7": 1.5, "16": 2.5 },
62
+ lineWidthStops: { "1": 0.5, "2": 0.75, "3": 0.75, "4": 1, "5": 1, "7": 1.75, "16": 2.5 },
63
63
  lineStyles: [
64
64
  { color: "rgb(235, 214, 214)", layerSuffix: "ne", endZoom: 4, lineExtensionFactor: 0.1, delWidthFactor: 2.5 },
65
65
  { color: "rgb(235, 214, 214)", layerSuffix: "ne-disp", endZoom: 4, delWidthFactor: 0 },
66
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.2, startZoom: 6, endZoom: 11, widthFraction: 5, lineExtensionFactor: 0.1 },
67
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.2, startZoom: 12, widthFraction: 4, lineExtensionFactor: 0.1 },
66
+ { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 6, lineWidthStops: { "6": 9, "10": 8, "14": 8 }, lineExtensionFactor: 0.1 },
68
67
  { color: "rgb(235, 214, 214)", layerSuffix: "osm", startZoom: 5, lineExtensionFactor: 0.1 },
69
68
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", startZoom: 5, delWidthFactor: 0 },
70
69
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-internal", startZoom: 5, widthFraction: 0.5, dashArray: [2, 2], delWidthFactor: 2 },
@@ -87,12 +86,11 @@ var configs_default = [
87
86
  "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png",
88
87
  "https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png"
89
88
  ],
90
- lineWidthStops: { "1": 0.75, "2": 0.75, "3": 0.75, "4": 1, "5": 1, "7": 1.5, "11": 2 },
89
+ lineWidthStops: { "1": 1, "3": 1, "4": 2, "5": 2, "6": 2.5, "7": 3, "8": 3, "10": 4, "11": 4, "12": 4 },
91
90
  lineStyles: [
92
91
  { color: "rgb(235, 214, 214)", layerSuffix: "ne", endZoom: 4, lineExtensionFactor: 0.1, delWidthFactor: 2.5 },
93
92
  { color: "rgb(235, 214, 214)", layerSuffix: "ne-disp", endZoom: 4, delWidthFactor: 0 },
94
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 6, endZoom: 11, widthFraction: 5, lineExtensionFactor: 0.1 },
95
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 12, widthFraction: 4, lineExtensionFactor: 0.1 },
93
+ { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 6, lineWidthStops: { "6": 20, "8": 19, "10": 18, "12": 17 }, lineExtensionFactor: 0.1 },
96
94
  { color: "rgb(235, 214, 214)", layerSuffix: "osm", startZoom: 5, lineExtensionFactor: 0.1 },
97
95
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", startZoom: 5, delWidthFactor: 0 },
98
96
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-internal", startZoom: 5, widthFraction: 0.5, dashArray: [4, 4], delWidthFactor: 2 },
@@ -103,15 +101,20 @@ var configs_default = [
103
101
  id: "open-topo",
104
102
  tileUrlTemplates: [
105
103
  "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
106
- "https://tile.opentopomap.org/{z}/{x}/{y}.png"
104
+ "https://tile.opentopomap.org/{z}/{x}/{y}.png",
105
+ "https://{s}.tile.top-o-map.de/{z}/{x}/{y}.png",
106
+ "https://tile.top-o-map.de/{z}/{x}/{y}.png"
107
107
  ],
108
108
  lineWidthStops: { "4": 0.75, "5": 1, "6": 1.25, "7": 1.5, "8": 1.75, "9": 1.25, "10": 1.25, "13": 1.5 },
109
109
  lineStyles: [
110
110
  { color: "rgb(83, 83, 83)", layerSuffix: "ne", startZoom: 4, endZoom: 6 },
111
111
  { color: "rgb(173, 173, 173)", layerSuffix: "osm", startZoom: 7, endZoom: 8, alpha: 0.5, widthFraction: 4 },
112
112
  { color: "rgb(83, 83, 83)", layerSuffix: "osm", startZoom: 7, endZoom: 8 },
113
+ { color: "rgb(83, 83, 83)", layerSuffix: "osm-internal", widthFraction: 0.75, startZoom: 7, endZoom: 8 },
113
114
  { color: "rgb(199, 158, 204)", layerSuffix: "osm", startZoom: 9, widthFraction: 7, alpha: 0.6, lineExtensionFactor: 0.2 },
114
- { color: "rgb(175, 41, 203)", layerSuffix: "osm", startZoom: 9, lineExtensionFactor: 0.2 }
115
+ { color: "rgb(175, 41, 203)", layerSuffix: "osm", startZoom: 9, lineExtensionFactor: 0.2 },
116
+ { color: "rgb(199, 158, 204)", layerSuffix: "osm-internal", startZoom: 9, widthFraction: 2.25, alpha: 0.6, lineExtensionFactor: 0.2 },
117
+ { color: "rgb(175, 41, 203)", layerSuffix: "osm-internal", startZoom: 9, widthFactor: 0.75, lineExtensionFactor: 0.2 }
115
118
  ]
116
119
  },
117
120
  {
@@ -120,9 +123,8 @@ var configs_default = [
120
123
  "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
121
124
  "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
122
125
  ],
123
- lineWidthStops: { "1": 0.5, "2": 0.6, "3": 0.7, "4": 1, "10": 3.75 },
126
+ lineWidthStops: { "3": 0.7, "4": 1, "10": 3.75 },
124
127
  lineStyles: [
125
- { color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 1, endZoom: 3, delWidthFactor: 2.5, widthFraction: 1.5 },
126
128
  { color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 4, delWidthFactor: 1.5 },
127
129
  { color: "rgb(160, 120, 160)", layerSuffix: "osm", startZoom: 4, widthFraction: 0.333, dashArray: [30, 2, 8, 2], delWidthFactor: 0 },
128
130
  { color: "rgb(200, 180, 200)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.45 },
@@ -146,6 +148,39 @@ var configs_default = [
146
148
  var INFINITY = -1;
147
149
  var MIN_LINE_WIDTH = 0.1;
148
150
  var DEFAULT_LINE_WIDTH = 1;
151
+ function interpolateLineWidth(zoom, lineWidthStops) {
152
+ const zooms = Object.keys(lineWidthStops).map(Number).sort((a, b2) => a - b2);
153
+ if (lineWidthStops[zoom] !== void 0) {
154
+ return lineWidthStops[zoom];
155
+ }
156
+ if (zoom < zooms[0]) {
157
+ const z1 = zooms[0];
158
+ const z2 = zooms[1];
159
+ const w1 = lineWidthStops[z1];
160
+ const w2 = lineWidthStops[z2];
161
+ const slope = (w2 - w1) / (z2 - z1);
162
+ return Math.max(MIN_LINE_WIDTH, w1 + slope * (zoom - z1));
163
+ }
164
+ if (zoom > zooms[zooms.length - 1]) {
165
+ const z1 = zooms[zooms.length - 2];
166
+ const z2 = zooms[zooms.length - 1];
167
+ const w1 = lineWidthStops[z1];
168
+ const w2 = lineWidthStops[z2];
169
+ const slope = (w2 - w1) / (z2 - z1);
170
+ return Math.max(MIN_LINE_WIDTH, w2 + slope * (zoom - z2));
171
+ }
172
+ for (let i2 = 0; i2 < zooms.length - 1; i2++) {
173
+ if (zoom > zooms[i2] && zoom < zooms[i2 + 1]) {
174
+ const z1 = zooms[i2];
175
+ const z2 = zooms[i2 + 1];
176
+ const w1 = lineWidthStops[z1];
177
+ const w2 = lineWidthStops[z2];
178
+ const t = (zoom - z1) / (z2 - z1);
179
+ return w1 + t * (w2 - w1);
180
+ }
181
+ }
182
+ return DEFAULT_LINE_WIDTH;
183
+ }
149
184
  function templateToRegex(template) {
150
185
  const groups = [];
151
186
  const hasRetina = template.includes("{r}");
@@ -212,14 +247,33 @@ function isValidColor(color) {
212
247
  if (/^[a-z]+$/.test(trimmed)) return true;
213
248
  return false;
214
249
  }
250
+ function validateLineWidthStops(lineWidthStops, prefix) {
251
+ if (!lineWidthStops || typeof lineWidthStops !== "object" || Array.isArray(lineWidthStops)) {
252
+ throw new Error(`${prefix}: lineWidthStops must be an object`);
253
+ }
254
+ const stopKeys = Object.keys(lineWidthStops);
255
+ if (stopKeys.length < 2) {
256
+ throw new Error(`${prefix}: lineWidthStops must have at least 2 entries`);
257
+ }
258
+ for (const key of stopKeys) {
259
+ const zoom = Number(key);
260
+ if (!Number.isInteger(zoom) || zoom < 0) {
261
+ throw new Error(`${prefix}: lineWidthStops keys must be non-negative integers, got "${key}"`);
262
+ }
263
+ if (typeof lineWidthStops[key] !== "number" || lineWidthStops[key] <= 0) {
264
+ throw new Error(`${prefix}: lineWidthStops values must be positive numbers`);
265
+ }
266
+ }
267
+ }
215
268
  var LineStyle = class _LineStyle {
216
269
  /**
217
270
  * Validate a LineStyle configuration object.
218
271
  * @param {Object} obj - The object to validate
219
272
  * @param {number} [index] - Optional index for error messages (when validating in an array)
273
+ * @param {boolean} [requireLineWidthStops=false] - Whether lineWidthStops is required
220
274
  * @throws {Error} If validation fails
221
275
  */
222
- static validateJSON(obj, index) {
276
+ static validateJSON(obj, index, requireLineWidthStops = false) {
223
277
  const prefix = index !== void 0 ? `lineStyles[${index}]` : "LineStyle";
224
278
  if (!obj || typeof obj !== "object") {
225
279
  throw new Error(`${prefix}: must be an object`);
@@ -254,22 +308,30 @@ var LineStyle = class _LineStyle {
254
308
  if (obj.delWidthFactor !== void 0 && (typeof obj.delWidthFactor !== "number" || obj.delWidthFactor < 0)) {
255
309
  throw new Error(`${prefix}: delWidthFactor must be a non-negative number`);
256
310
  }
311
+ if (requireLineWidthStops && obj.lineWidthStops === void 0) {
312
+ throw new Error(`${prefix}: lineWidthStops is required`);
313
+ }
314
+ if (obj.lineWidthStops !== void 0) {
315
+ validateLineWidthStops(obj.lineWidthStops, prefix);
316
+ }
257
317
  }
258
318
  /**
259
319
  * @param {Object} options
260
320
  * @param {string} options.color - CSS color string
261
321
  * @param {string} options.layerSuffix - Layer suffix (e.g., 'osm', 'ne', 'osm-disp')
322
+ * @param {Object<number, number>} options.lineWidthStops - Line width stops for this style
262
323
  * @param {number} [options.widthFraction=1.0] - Multiplier for base line width
263
324
  * @param {number[]} [options.dashArray] - Dash pattern for dashed lines
264
325
  * @param {number} [options.alpha=1.0] - Opacity (0-1)
265
326
  * @param {number} [options.startZoom=0] - Minimum zoom level for this style
266
327
  * @param {number} [options.endZoom=INFINITY] - Maximum zoom level for this style (INFINITY means no limit)
267
- * @param {number} [options.lineExtensionFactor=0.5] - Factor to extend lines by (multiplied by deletion line width)
328
+ * @param {number} [options.lineExtensionFactor=0.0] - Factor to extend lines by (multiplied by deletion line width)
268
329
  * @param {number} [options.delWidthFactor=1.5] - Factor to multiply line width for deletion blur
269
330
  */
270
- constructor({ color, layerSuffix, widthFraction = 1, dashArray, alpha = 1, startZoom = 0, endZoom = INFINITY, lineExtensionFactor = 0, delWidthFactor = 1.5 }) {
331
+ constructor({ color, layerSuffix, lineWidthStops, widthFraction = 1, dashArray, alpha = 1, startZoom = 0, endZoom = INFINITY, lineExtensionFactor = 0, delWidthFactor = 1.5 }) {
271
332
  this.color = color;
272
333
  this.layerSuffix = layerSuffix;
334
+ this.lineWidthStops = lineWidthStops;
273
335
  this.widthFraction = widthFraction;
274
336
  this.dashArray = dashArray;
275
337
  this.alpha = alpha;
@@ -278,6 +340,14 @@ var LineStyle = class _LineStyle {
278
340
  this.lineExtensionFactor = lineExtensionFactor;
279
341
  this.delWidthFactor = delWidthFactor;
280
342
  }
343
+ /**
344
+ * Get base line width for this style at a given zoom level.
345
+ * @param {number} zoom - Zoom level
346
+ * @returns {number}
347
+ */
348
+ getLineWidth(zoom) {
349
+ return interpolateLineWidth(zoom, this.lineWidthStops);
350
+ }
281
351
  /**
282
352
  * Check if this style is active at the given zoom level.
283
353
  * @param {number} z - Zoom level
@@ -294,6 +364,7 @@ var LineStyle = class _LineStyle {
294
364
  return {
295
365
  color: this.color,
296
366
  layerSuffix: this.layerSuffix,
367
+ lineWidthStops: this.lineWidthStops,
297
368
  widthFraction: this.widthFraction,
298
369
  dashArray: this.dashArray,
299
370
  alpha: this.alpha,
@@ -310,7 +381,7 @@ var LineStyle = class _LineStyle {
310
381
  * @returns {LineStyle}
311
382
  */
312
383
  static fromJSON(obj, index) {
313
- _LineStyle.validateJSON(obj, index);
384
+ _LineStyle.validateJSON(obj, index, true);
314
385
  return new _LineStyle(obj);
315
386
  }
316
387
  };
@@ -376,9 +447,13 @@ var LayerConfig = class _LayerConfig {
376
447
  this._compiledPatterns = templates.map((t) => templateToRegex(t));
377
448
  this._templatePatterns = templates.map((t) => templateToTemplateRegex(t));
378
449
  this.lineWidthStops = lineWidthStops;
379
- this.lineStyles = lineStyles.map(
380
- (style) => style instanceof LineStyle ? style : new LineStyle(style)
381
- );
450
+ this.lineStyles = lineStyles.map((style) => {
451
+ if (style instanceof LineStyle) {
452
+ return style;
453
+ }
454
+ const styleWithStops = style.lineWidthStops ? style : { ...style, lineWidthStops };
455
+ return new LineStyle(styleWithStops);
456
+ });
382
457
  }
383
458
  /**
384
459
  * Get line styles active at a given zoom level
@@ -397,45 +472,6 @@ var LayerConfig = class _LayerConfig {
397
472
  const activeStyles = this.getLineStylesForZoom(z2);
398
473
  return [...new Set(activeStyles.map((s) => s.layerSuffix))];
399
474
  }
400
- /**
401
- * Interpolate or extrapolate line width for a given zoom level.
402
- * Uses the lineWidthStops map to calculate the appropriate width.
403
- * @param {number} zoom - Zoom level
404
- * @returns {number}
405
- */
406
- getLineWidth(zoom) {
407
- const zooms = Object.keys(this.lineWidthStops).map(Number).sort((a, b2) => a - b2);
408
- if (this.lineWidthStops[zoom] !== void 0) {
409
- return this.lineWidthStops[zoom];
410
- }
411
- if (zoom < zooms[0]) {
412
- const z1 = zooms[0];
413
- const z2 = zooms[1];
414
- const w1 = this.lineWidthStops[z1];
415
- const w2 = this.lineWidthStops[z2];
416
- const slope = (w2 - w1) / (z2 - z1);
417
- return Math.max(MIN_LINE_WIDTH, w1 + slope * (zoom - z1));
418
- }
419
- if (zoom > zooms[zooms.length - 1]) {
420
- const z1 = zooms[zooms.length - 2];
421
- const z2 = zooms[zooms.length - 1];
422
- const w1 = this.lineWidthStops[z1];
423
- const w2 = this.lineWidthStops[z2];
424
- const slope = (w2 - w1) / (z2 - z1);
425
- return Math.max(MIN_LINE_WIDTH, w2 + slope * (zoom - z2));
426
- }
427
- for (let i2 = 0; i2 < zooms.length - 1; i2++) {
428
- if (zoom > zooms[i2] && zoom < zooms[i2 + 1]) {
429
- const z1 = zooms[i2];
430
- const z2 = zooms[i2 + 1];
431
- const w1 = this.lineWidthStops[z1];
432
- const w2 = this.lineWidthStops[z2];
433
- const t = (zoom - z1) / (z2 - z1);
434
- return w1 + t * (w2 - w1);
435
- }
436
- }
437
- return DEFAULT_LINE_WIDTH;
438
- }
439
475
  /**
440
476
  * Check if this config matches the given template URLs (with {z}/{x}/{y} placeholders)
441
477
  * @param {string | string[]} templates - Single template URL or array of template URLs
@@ -2889,12 +2925,11 @@ var configs_default2 = [
2889
2925
  "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}.png",
2890
2926
  "https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}.png"
2891
2927
  ],
2892
- lineWidthStops: { "1": 0.5, "2": 0.75, "3": 0.75, "4": 1, "5": 1, "7": 1.5, "16": 2.5 },
2928
+ lineWidthStops: { "1": 0.5, "2": 0.75, "3": 0.75, "4": 1, "5": 1, "7": 1.75, "16": 2.5 },
2893
2929
  lineStyles: [
2894
2930
  { color: "rgb(235, 214, 214)", layerSuffix: "ne", endZoom: 4, lineExtensionFactor: 0.1, delWidthFactor: 2.5 },
2895
2931
  { color: "rgb(235, 214, 214)", layerSuffix: "ne-disp", endZoom: 4, delWidthFactor: 0 },
2896
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.2, startZoom: 6, endZoom: 11, widthFraction: 5, lineExtensionFactor: 0.1 },
2897
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.2, startZoom: 12, widthFraction: 4, lineExtensionFactor: 0.1 },
2932
+ { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 6, lineWidthStops: { "6": 9, "10": 8, "14": 8 }, lineExtensionFactor: 0.1 },
2898
2933
  { color: "rgb(235, 214, 214)", layerSuffix: "osm", startZoom: 5, lineExtensionFactor: 0.1 },
2899
2934
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", startZoom: 5, delWidthFactor: 0 },
2900
2935
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-internal", startZoom: 5, widthFraction: 0.5, dashArray: [2, 2], delWidthFactor: 2 },
@@ -2917,12 +2952,11 @@ var configs_default2 = [
2917
2952
  "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png",
2918
2953
  "https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png"
2919
2954
  ],
2920
- lineWidthStops: { "1": 0.75, "2": 0.75, "3": 0.75, "4": 1, "5": 1, "7": 1.5, "11": 2 },
2955
+ lineWidthStops: { "1": 1, "3": 1, "4": 2, "5": 2, "6": 2.5, "7": 3, "8": 3, "10": 4, "11": 4, "12": 4 },
2921
2956
  lineStyles: [
2922
2957
  { color: "rgb(235, 214, 214)", layerSuffix: "ne", endZoom: 4, lineExtensionFactor: 0.1, delWidthFactor: 2.5 },
2923
2958
  { color: "rgb(235, 214, 214)", layerSuffix: "ne-disp", endZoom: 4, delWidthFactor: 0 },
2924
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 6, endZoom: 11, widthFraction: 5, lineExtensionFactor: 0.1 },
2925
- { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 12, widthFraction: 4, lineExtensionFactor: 0.1 },
2959
+ { color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.1, startZoom: 6, lineWidthStops: { "6": 20, "8": 19, "10": 18, "12": 17 }, lineExtensionFactor: 0.1 },
2926
2960
  { color: "rgb(235, 214, 214)", layerSuffix: "osm", startZoom: 5, lineExtensionFactor: 0.1 },
2927
2961
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", startZoom: 5, delWidthFactor: 0 },
2928
2962
  { color: "rgb(235, 214, 214)", layerSuffix: "osm-internal", startZoom: 5, widthFraction: 0.5, dashArray: [4, 4], delWidthFactor: 2 },
@@ -2933,15 +2967,20 @@ var configs_default2 = [
2933
2967
  id: "open-topo",
2934
2968
  tileUrlTemplates: [
2935
2969
  "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
2936
- "https://tile.opentopomap.org/{z}/{x}/{y}.png"
2970
+ "https://tile.opentopomap.org/{z}/{x}/{y}.png",
2971
+ "https://{s}.tile.top-o-map.de/{z}/{x}/{y}.png",
2972
+ "https://tile.top-o-map.de/{z}/{x}/{y}.png"
2937
2973
  ],
2938
2974
  lineWidthStops: { "4": 0.75, "5": 1, "6": 1.25, "7": 1.5, "8": 1.75, "9": 1.25, "10": 1.25, "13": 1.5 },
2939
2975
  lineStyles: [
2940
2976
  { color: "rgb(83, 83, 83)", layerSuffix: "ne", startZoom: 4, endZoom: 6 },
2941
2977
  { color: "rgb(173, 173, 173)", layerSuffix: "osm", startZoom: 7, endZoom: 8, alpha: 0.5, widthFraction: 4 },
2942
2978
  { color: "rgb(83, 83, 83)", layerSuffix: "osm", startZoom: 7, endZoom: 8 },
2979
+ { color: "rgb(83, 83, 83)", layerSuffix: "osm-internal", widthFraction: 0.75, startZoom: 7, endZoom: 8 },
2943
2980
  { color: "rgb(199, 158, 204)", layerSuffix: "osm", startZoom: 9, widthFraction: 7, alpha: 0.6, lineExtensionFactor: 0.2 },
2944
- { color: "rgb(175, 41, 203)", layerSuffix: "osm", startZoom: 9, lineExtensionFactor: 0.2 }
2981
+ { color: "rgb(175, 41, 203)", layerSuffix: "osm", startZoom: 9, lineExtensionFactor: 0.2 },
2982
+ { color: "rgb(199, 158, 204)", layerSuffix: "osm-internal", startZoom: 9, widthFraction: 2.25, alpha: 0.6, lineExtensionFactor: 0.2 },
2983
+ { color: "rgb(175, 41, 203)", layerSuffix: "osm-internal", startZoom: 9, widthFactor: 0.75, lineExtensionFactor: 0.2 }
2945
2984
  ]
2946
2985
  },
2947
2986
  {
@@ -2950,9 +2989,8 @@ var configs_default2 = [
2950
2989
  "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
2951
2990
  "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
2952
2991
  ],
2953
- lineWidthStops: { "1": 0.5, "2": 0.6, "3": 0.7, "4": 1, "10": 3.75 },
2992
+ lineWidthStops: { "3": 0.7, "4": 1, "10": 3.75 },
2954
2993
  lineStyles: [
2955
- { color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 1, endZoom: 3, delWidthFactor: 2.5, widthFraction: 1.5 },
2956
2994
  { color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 4, delWidthFactor: 1.5 },
2957
2995
  { color: "rgb(160, 120, 160)", layerSuffix: "osm", startZoom: 4, widthFraction: 0.333, dashArray: [30, 2, 8, 2], delWidthFactor: 0 },
2958
2996
  { color: "rgb(200, 180, 200)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.45 },
@@ -2976,6 +3014,39 @@ var configs_default2 = [
2976
3014
  var INFINITY2 = -1;
2977
3015
  var MIN_LINE_WIDTH2 = 0.1;
2978
3016
  var DEFAULT_LINE_WIDTH2 = 1;
3017
+ function interpolateLineWidth2(zoom, lineWidthStops) {
3018
+ const zooms = Object.keys(lineWidthStops).map(Number).sort((a, b2) => a - b2);
3019
+ if (lineWidthStops[zoom] !== void 0) {
3020
+ return lineWidthStops[zoom];
3021
+ }
3022
+ if (zoom < zooms[0]) {
3023
+ const z1 = zooms[0];
3024
+ const z2 = zooms[1];
3025
+ const w1 = lineWidthStops[z1];
3026
+ const w2 = lineWidthStops[z2];
3027
+ const slope = (w2 - w1) / (z2 - z1);
3028
+ return Math.max(MIN_LINE_WIDTH2, w1 + slope * (zoom - z1));
3029
+ }
3030
+ if (zoom > zooms[zooms.length - 1]) {
3031
+ const z1 = zooms[zooms.length - 2];
3032
+ const z2 = zooms[zooms.length - 1];
3033
+ const w1 = lineWidthStops[z1];
3034
+ const w2 = lineWidthStops[z2];
3035
+ const slope = (w2 - w1) / (z2 - z1);
3036
+ return Math.max(MIN_LINE_WIDTH2, w2 + slope * (zoom - z2));
3037
+ }
3038
+ for (let i2 = 0; i2 < zooms.length - 1; i2++) {
3039
+ if (zoom > zooms[i2] && zoom < zooms[i2 + 1]) {
3040
+ const z1 = zooms[i2];
3041
+ const z2 = zooms[i2 + 1];
3042
+ const w1 = lineWidthStops[z1];
3043
+ const w2 = lineWidthStops[z2];
3044
+ const t = (zoom - z1) / (z2 - z1);
3045
+ return w1 + t * (w2 - w1);
3046
+ }
3047
+ }
3048
+ return DEFAULT_LINE_WIDTH2;
3049
+ }
2979
3050
  function templateToRegex2(template) {
2980
3051
  const groups = [];
2981
3052
  const hasRetina = template.includes("{r}");
@@ -3042,14 +3113,33 @@ function isValidColor2(color) {
3042
3113
  if (/^[a-z]+$/.test(trimmed)) return true;
3043
3114
  return false;
3044
3115
  }
3116
+ function validateLineWidthStops2(lineWidthStops, prefix) {
3117
+ if (!lineWidthStops || typeof lineWidthStops !== "object" || Array.isArray(lineWidthStops)) {
3118
+ throw new Error(`${prefix}: lineWidthStops must be an object`);
3119
+ }
3120
+ const stopKeys = Object.keys(lineWidthStops);
3121
+ if (stopKeys.length < 2) {
3122
+ throw new Error(`${prefix}: lineWidthStops must have at least 2 entries`);
3123
+ }
3124
+ for (const key of stopKeys) {
3125
+ const zoom = Number(key);
3126
+ if (!Number.isInteger(zoom) || zoom < 0) {
3127
+ throw new Error(`${prefix}: lineWidthStops keys must be non-negative integers, got "${key}"`);
3128
+ }
3129
+ if (typeof lineWidthStops[key] !== "number" || lineWidthStops[key] <= 0) {
3130
+ throw new Error(`${prefix}: lineWidthStops values must be positive numbers`);
3131
+ }
3132
+ }
3133
+ }
3045
3134
  var LineStyle2 = class _LineStyle2 {
3046
3135
  /**
3047
3136
  * Validate a LineStyle configuration object.
3048
3137
  * @param {Object} obj - The object to validate
3049
3138
  * @param {number} [index] - Optional index for error messages (when validating in an array)
3139
+ * @param {boolean} [requireLineWidthStops=false] - Whether lineWidthStops is required
3050
3140
  * @throws {Error} If validation fails
3051
3141
  */
3052
- static validateJSON(obj, index) {
3142
+ static validateJSON(obj, index, requireLineWidthStops = false) {
3053
3143
  const prefix = index !== void 0 ? `lineStyles[${index}]` : "LineStyle";
3054
3144
  if (!obj || typeof obj !== "object") {
3055
3145
  throw new Error(`${prefix}: must be an object`);
@@ -3084,22 +3174,30 @@ var LineStyle2 = class _LineStyle2 {
3084
3174
  if (obj.delWidthFactor !== void 0 && (typeof obj.delWidthFactor !== "number" || obj.delWidthFactor < 0)) {
3085
3175
  throw new Error(`${prefix}: delWidthFactor must be a non-negative number`);
3086
3176
  }
3177
+ if (requireLineWidthStops && obj.lineWidthStops === void 0) {
3178
+ throw new Error(`${prefix}: lineWidthStops is required`);
3179
+ }
3180
+ if (obj.lineWidthStops !== void 0) {
3181
+ validateLineWidthStops2(obj.lineWidthStops, prefix);
3182
+ }
3087
3183
  }
3088
3184
  /**
3089
3185
  * @param {Object} options
3090
3186
  * @param {string} options.color - CSS color string
3091
3187
  * @param {string} options.layerSuffix - Layer suffix (e.g., 'osm', 'ne', 'osm-disp')
3188
+ * @param {Object<number, number>} options.lineWidthStops - Line width stops for this style
3092
3189
  * @param {number} [options.widthFraction=1.0] - Multiplier for base line width
3093
3190
  * @param {number[]} [options.dashArray] - Dash pattern for dashed lines
3094
3191
  * @param {number} [options.alpha=1.0] - Opacity (0-1)
3095
3192
  * @param {number} [options.startZoom=0] - Minimum zoom level for this style
3096
3193
  * @param {number} [options.endZoom=INFINITY] - Maximum zoom level for this style (INFINITY means no limit)
3097
- * @param {number} [options.lineExtensionFactor=0.5] - Factor to extend lines by (multiplied by deletion line width)
3194
+ * @param {number} [options.lineExtensionFactor=0.0] - Factor to extend lines by (multiplied by deletion line width)
3098
3195
  * @param {number} [options.delWidthFactor=1.5] - Factor to multiply line width for deletion blur
3099
3196
  */
3100
- constructor({ color, layerSuffix, widthFraction = 1, dashArray, alpha = 1, startZoom = 0, endZoom = INFINITY2, lineExtensionFactor = 0, delWidthFactor = 1.5 }) {
3197
+ constructor({ color, layerSuffix, lineWidthStops, widthFraction = 1, dashArray, alpha = 1, startZoom = 0, endZoom = INFINITY2, lineExtensionFactor = 0, delWidthFactor = 1.5 }) {
3101
3198
  this.color = color;
3102
3199
  this.layerSuffix = layerSuffix;
3200
+ this.lineWidthStops = lineWidthStops;
3103
3201
  this.widthFraction = widthFraction;
3104
3202
  this.dashArray = dashArray;
3105
3203
  this.alpha = alpha;
@@ -3108,6 +3206,14 @@ var LineStyle2 = class _LineStyle2 {
3108
3206
  this.lineExtensionFactor = lineExtensionFactor;
3109
3207
  this.delWidthFactor = delWidthFactor;
3110
3208
  }
3209
+ /**
3210
+ * Get base line width for this style at a given zoom level.
3211
+ * @param {number} zoom - Zoom level
3212
+ * @returns {number}
3213
+ */
3214
+ getLineWidth(zoom) {
3215
+ return interpolateLineWidth2(zoom, this.lineWidthStops);
3216
+ }
3111
3217
  /**
3112
3218
  * Check if this style is active at the given zoom level.
3113
3219
  * @param {number} z - Zoom level
@@ -3124,6 +3230,7 @@ var LineStyle2 = class _LineStyle2 {
3124
3230
  return {
3125
3231
  color: this.color,
3126
3232
  layerSuffix: this.layerSuffix,
3233
+ lineWidthStops: this.lineWidthStops,
3127
3234
  widthFraction: this.widthFraction,
3128
3235
  dashArray: this.dashArray,
3129
3236
  alpha: this.alpha,
@@ -3140,7 +3247,7 @@ var LineStyle2 = class _LineStyle2 {
3140
3247
  * @returns {LineStyle}
3141
3248
  */
3142
3249
  static fromJSON(obj, index) {
3143
- _LineStyle2.validateJSON(obj, index);
3250
+ _LineStyle2.validateJSON(obj, index, true);
3144
3251
  return new _LineStyle2(obj);
3145
3252
  }
3146
3253
  };
@@ -3206,9 +3313,13 @@ var LayerConfig2 = class _LayerConfig2 {
3206
3313
  this._compiledPatterns = templates.map((t) => templateToRegex2(t));
3207
3314
  this._templatePatterns = templates.map((t) => templateToTemplateRegex2(t));
3208
3315
  this.lineWidthStops = lineWidthStops;
3209
- this.lineStyles = lineStyles.map(
3210
- (style) => style instanceof LineStyle2 ? style : new LineStyle2(style)
3211
- );
3316
+ this.lineStyles = lineStyles.map((style) => {
3317
+ if (style instanceof LineStyle2) {
3318
+ return style;
3319
+ }
3320
+ const styleWithStops = style.lineWidthStops ? style : { ...style, lineWidthStops };
3321
+ return new LineStyle2(styleWithStops);
3322
+ });
3212
3323
  }
3213
3324
  /**
3214
3325
  * Get line styles active at a given zoom level
@@ -3227,45 +3338,6 @@ var LayerConfig2 = class _LayerConfig2 {
3227
3338
  const activeStyles = this.getLineStylesForZoom(z2);
3228
3339
  return [...new Set(activeStyles.map((s) => s.layerSuffix))];
3229
3340
  }
3230
- /**
3231
- * Interpolate or extrapolate line width for a given zoom level.
3232
- * Uses the lineWidthStops map to calculate the appropriate width.
3233
- * @param {number} zoom - Zoom level
3234
- * @returns {number}
3235
- */
3236
- getLineWidth(zoom) {
3237
- const zooms = Object.keys(this.lineWidthStops).map(Number).sort((a, b2) => a - b2);
3238
- if (this.lineWidthStops[zoom] !== void 0) {
3239
- return this.lineWidthStops[zoom];
3240
- }
3241
- if (zoom < zooms[0]) {
3242
- const z1 = zooms[0];
3243
- const z2 = zooms[1];
3244
- const w1 = this.lineWidthStops[z1];
3245
- const w2 = this.lineWidthStops[z2];
3246
- const slope = (w2 - w1) / (z2 - z1);
3247
- return Math.max(MIN_LINE_WIDTH2, w1 + slope * (zoom - z1));
3248
- }
3249
- if (zoom > zooms[zooms.length - 1]) {
3250
- const z1 = zooms[zooms.length - 2];
3251
- const z2 = zooms[zooms.length - 1];
3252
- const w1 = this.lineWidthStops[z1];
3253
- const w2 = this.lineWidthStops[z2];
3254
- const slope = (w2 - w1) / (z2 - z1);
3255
- return Math.max(MIN_LINE_WIDTH2, w2 + slope * (zoom - z2));
3256
- }
3257
- for (let i2 = 0; i2 < zooms.length - 1; i2++) {
3258
- if (zoom > zooms[i2] && zoom < zooms[i2 + 1]) {
3259
- const z1 = zooms[i2];
3260
- const z2 = zooms[i2 + 1];
3261
- const w1 = this.lineWidthStops[z1];
3262
- const w2 = this.lineWidthStops[z2];
3263
- const t = (zoom - z1) / (z2 - z1);
3264
- return w1 + t * (w2 - w1);
3265
- }
3266
- }
3267
- return DEFAULT_LINE_WIDTH2;
3268
- }
3269
3341
  /**
3270
3342
  * Check if this config matches the given template URLs (with {z}/{x}/{y} placeholders)
3271
3343
  * @param {string | string[]} templates - Single template URL or array of template URLs
@@ -3758,12 +3830,13 @@ var _TileFixer = class _TileFixer2 {
3758
3830
  const canvas = this._canvas;
3759
3831
  const ctx = canvas.getContext("2d", { willReadFrequently: true });
3760
3832
  ctx.drawImage(imageBitmap, 0, 0, tileSize, tileSize);
3761
- const baseLineWidth = layerConfig.getLineWidth(zoom);
3762
3833
  const delLineWidthBySuffix = {};
3763
3834
  for (const suffix of layerSuffixes) {
3764
3835
  const stylesForSuffix = activeLineStyles.filter((s) => s.layerSuffix === suffix);
3765
- const maxProduct = Math.max(...stylesForSuffix.map((s) => s.widthFraction * s.delWidthFactor));
3766
- delLineWidthBySuffix[suffix] = baseLineWidth * maxProduct;
3836
+ const maxDelWidth = Math.max(...stylesForSuffix.map(
3837
+ (s) => s.getLineWidth(zoom) * s.widthFraction * s.delWidthFactor
3838
+ ));
3839
+ delLineWidthBySuffix[suffix] = maxDelWidth;
3767
3840
  }
3768
3841
  for (const suffix of layerSuffixes) {
3769
3842
  const delLineWidth = delLineWidthBySuffix[suffix];
@@ -3778,7 +3851,7 @@ var _TileFixer = class _TileFixer2 {
3778
3851
  }
3779
3852
  }
3780
3853
  for (const style of activeLineStyles) {
3781
- const { color, layerSuffix, widthFraction, dashArray, alpha, lineExtensionFactor } = style;
3854
+ const { color, widthFraction, dashArray, alpha, lineExtensionFactor, layerSuffix } = style;
3782
3855
  const addLayerName = `to-add-${layerSuffix}`;
3783
3856
  let addFeatures = corrections[addLayerName] || [];
3784
3857
  if (addFeatures.length > 0) {
@@ -3786,7 +3859,7 @@ var _TileFixer = class _TileFixer2 {
3786
3859
  if (lineExtensionFactor > 0) {
3787
3860
  addFeatures = extendFeaturesByFactor(addFeatures, lineExtensionFactor, delLineWidth, tileSize);
3788
3861
  }
3789
- const lineWidth = baseLineWidth * widthFraction;
3862
+ const lineWidth = style.getLineWidth(zoom) * widthFraction;
3790
3863
  drawFeatures(ctx, addFeatures, color, lineWidth, tileSize, dashArray, alpha);
3791
3864
  }
3792
3865
  }