@india-boundary-corrector/service-worker 0.0.5 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/index.global.js +93 -98
- package/dist/index.global.js.map +1 -1
- package/dist/india_boundary_corrections.pmtiles +0 -0
- package/dist/india_boundary_corrections.pmtiles.gz +0 -0
- package/dist/worker.global.js +615 -128
- package/dist/worker.global.js.map +1 -1
- package/package.json +4 -4
package/dist/worker.global.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var IndiaBoundaryCorrector = (() => {
|
|
3
3
|
// ../data/version.js
|
|
4
|
-
var packageVersion = "0.0
|
|
4
|
+
var packageVersion = "0.1.0";
|
|
5
5
|
|
|
6
6
|
// ../data/index.js
|
|
7
7
|
var import_meta = {};
|
|
@@ -22,14 +22,17 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
22
22
|
scriptUrl = CURRENT_SCRIPT_URL;
|
|
23
23
|
}
|
|
24
24
|
if (scriptUrl) {
|
|
25
|
-
|
|
26
|
-
if (FALLBACK_CDNS.has(moduleUrl.hostname)) {
|
|
27
|
-
return DEFAULT_CDN_URL;
|
|
28
|
-
}
|
|
29
|
-
return new URL(PMTILES_FILENAME, moduleUrl).href;
|
|
25
|
+
return resolvePmtilesUrl(scriptUrl);
|
|
30
26
|
}
|
|
31
27
|
return DEFAULT_CDN_URL;
|
|
32
28
|
}
|
|
29
|
+
function resolvePmtilesUrl(scriptUrl) {
|
|
30
|
+
const moduleUrl = new URL(".", scriptUrl);
|
|
31
|
+
if (FALLBACK_CDNS.has(moduleUrl.hostname)) {
|
|
32
|
+
return DEFAULT_CDN_URL;
|
|
33
|
+
}
|
|
34
|
+
return new URL(PMTILES_FILENAME, moduleUrl).href;
|
|
35
|
+
}
|
|
33
36
|
var cachedPmtilesUrl = null;
|
|
34
37
|
function getPmtilesUrl() {
|
|
35
38
|
if (cachedPmtilesUrl === null) {
|
|
@@ -42,7 +45,6 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
42
45
|
var configs_default = [
|
|
43
46
|
{
|
|
44
47
|
id: "cartodb-dark",
|
|
45
|
-
zoomThreshold: 5,
|
|
46
48
|
tileUrlTemplates: [
|
|
47
49
|
"https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
|
|
48
50
|
"https://basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
|
|
@@ -51,15 +53,17 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
51
53
|
"https://basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}{r}.png",
|
|
52
54
|
"https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_nolabels/{z}/{x}/{y}{r}.png"
|
|
53
55
|
],
|
|
54
|
-
lineWidthStops: { "1":
|
|
56
|
+
lineWidthStops: { "0": 1, "2": 1, "3": 1, "10": 2.5 },
|
|
55
57
|
lineStyles: [
|
|
56
|
-
{ color: "rgb(40, 40, 40)" }
|
|
58
|
+
{ color: "rgb(40, 40, 40)", layerSuffix: "ne", endZoom: 4 },
|
|
59
|
+
{ color: "rgb(40, 40, 40)", layerSuffix: "ne-disp", endZoom: 4 },
|
|
60
|
+
{ color: "rgb(40, 40, 40)", layerSuffix: "osm", startZoom: 5 },
|
|
61
|
+
{ color: "rgb(40, 40, 40)", layerSuffix: "osm-disp", startZoom: 5 },
|
|
62
|
+
{ color: "rgb(40, 40, 40)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.3, dashArray: [2, 2] }
|
|
57
63
|
]
|
|
58
64
|
},
|
|
59
65
|
{
|
|
60
66
|
id: "cartodb-light",
|
|
61
|
-
startZoom: 0,
|
|
62
|
-
zoomThreshold: 5,
|
|
63
67
|
tileUrlTemplates: [
|
|
64
68
|
"https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
|
|
65
69
|
"https://basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
|
|
@@ -74,56 +78,62 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
74
78
|
"https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png",
|
|
75
79
|
"https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png"
|
|
76
80
|
],
|
|
77
|
-
lineWidthStops: { "1": 0.
|
|
81
|
+
lineWidthStops: { "1": 0.5, "2": 0.5, "3": 0.5, "4": 1, "5": 1.25, "7": 1.5, "16": 2.5 },
|
|
78
82
|
lineStyles: [
|
|
79
|
-
{ color: "rgb(235, 214, 214)",
|
|
80
|
-
{ color: "rgb(235, 214, 214)" }
|
|
83
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "ne", endZoom: 4, lineExtensionFactor: 0.1, delWidthFactor: 2 },
|
|
84
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "ne-disp", endZoom: 4, lineExtensionFactor: 0 },
|
|
85
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.2, startZoom: 6, widthFraction: 3, lineExtensionFactor: 0.1 },
|
|
86
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "osm", startZoom: 5, lineExtensionFactor: 0.1 },
|
|
87
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", alpha: 0.2, startZoom: 6, widthFraction: 3, lineExtensionFactor: 0 },
|
|
88
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", startZoom: 5, lineExtensionFactor: 0 },
|
|
89
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.75, dashArray: [2, 2], delWidthFactor: 2 }
|
|
81
90
|
]
|
|
82
91
|
},
|
|
83
92
|
{
|
|
84
93
|
id: "open-topo",
|
|
85
|
-
startZoom: 4,
|
|
86
|
-
zoomThreshold: 4,
|
|
87
94
|
tileUrlTemplates: [
|
|
88
95
|
"https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
|
|
89
96
|
"https://tile.opentopomap.org/{z}/{x}/{y}.png"
|
|
90
97
|
],
|
|
91
98
|
lineWidthStops: { "4": 0.75, "5": 1, "6": 1.25, "7": 1.5, "8": 1.75, "9": 1.25, "10": 1.25, "13": 1.5 },
|
|
92
99
|
lineStyles: [
|
|
93
|
-
{ color: "rgb(83, 83, 83)",
|
|
94
|
-
{ color: "rgb(
|
|
95
|
-
{ color: "rgb(
|
|
96
|
-
{ color: "rgb(
|
|
100
|
+
{ color: "rgb(83, 83, 83)", layerSuffix: "ne", startZoom: 4, endZoom: 6 },
|
|
101
|
+
{ color: "rgb(173, 173, 173)", layerSuffix: "osm", startZoom: 7, endZoom: 8, alpha: 0.5, widthFraction: 4 },
|
|
102
|
+
{ color: "rgb(83, 83, 83)", layerSuffix: "osm", startZoom: 7, endZoom: 8 },
|
|
103
|
+
{ color: "rgb(199, 158, 204)", layerSuffix: "osm", startZoom: 9, widthFraction: 7, alpha: 0.6, lineExtensionFactor: 0.2 },
|
|
104
|
+
{ color: "rgb(175, 41, 203)", layerSuffix: "osm", startZoom: 9, lineExtensionFactor: 0.2 }
|
|
97
105
|
]
|
|
98
106
|
},
|
|
99
107
|
{
|
|
100
108
|
id: "osm-carto",
|
|
101
|
-
startZoom: 1,
|
|
102
|
-
zoomThreshold: 1,
|
|
103
109
|
tileUrlTemplates: [
|
|
104
110
|
"https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
|
105
111
|
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
|
106
112
|
],
|
|
107
113
|
lineWidthStops: { "1": 0.5, "2": 0.6, "3": 0.7, "4": 1, "10": 3.75 },
|
|
108
114
|
lineStyles: [
|
|
109
|
-
{ color: "rgb(200, 180, 200)" },
|
|
110
|
-
{ color: "rgb(
|
|
115
|
+
{ color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 1, endZoom: 3, delWidthFactor: 2.5, widthFraction: 1.5 },
|
|
116
|
+
{ color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 4 },
|
|
117
|
+
{ color: "rgb(160, 120, 160)", layerSuffix: "osm", startZoom: 4, widthFraction: 0.333, dashArray: [30, 2, 8, 2] },
|
|
118
|
+
{ color: "rgb(200, 180, 200)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.45 },
|
|
119
|
+
{ color: "rgb(160, 120, 160)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.15, dashArray: [4, 2, 10] }
|
|
111
120
|
]
|
|
112
121
|
},
|
|
113
122
|
{
|
|
114
123
|
id: "osm-hot",
|
|
115
|
-
startZoom: 2,
|
|
116
|
-
zoomThreshold: 2,
|
|
117
124
|
tileUrlTemplates: [
|
|
118
|
-
"https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png"
|
|
125
|
+
"https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png",
|
|
126
|
+
"https://tile.openstreetmap.fr/hot/{z}/{x}/{y}.png"
|
|
119
127
|
],
|
|
120
128
|
lineWidthStops: { "2": 3, "3": 3, "7": 3, "8": 3.5, "9": 3.5 },
|
|
121
129
|
lineStyles: [
|
|
122
|
-
{ color: "rgb(149, 175, 180)" },
|
|
123
|
-
{ color: "rgb(89, 117, 123)", widthFraction: 0.33 }
|
|
130
|
+
{ color: "rgb(149, 175, 180)", layerSuffix: "osm", lineExtensionFactor: 0.25, startZoom: 2 },
|
|
131
|
+
{ color: "rgb(89, 117, 123)", layerSuffix: "osm", widthFraction: 0.33, lineExtensionFactor: 0.25, startZoom: 2 },
|
|
132
|
+
{ color: "rgb(172, 163, 163)", layerSuffix: "osm-internal", widthFraction: 0.33, startZoom: 4, dashArray: [7, 7, 7] }
|
|
124
133
|
]
|
|
125
134
|
}
|
|
126
135
|
];
|
|
136
|
+
var INFINITY = -1;
|
|
127
137
|
function templateToRegex(template) {
|
|
128
138
|
const groups = [];
|
|
129
139
|
let pattern = template.replace(/[.*+?^${}()|[\]\\]/g, (char) => {
|
|
@@ -190,6 +200,9 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
190
200
|
if (!isValidColor(obj.color)) {
|
|
191
201
|
throw new Error(`${prefix}: color "${obj.color}" is not a valid CSS color`);
|
|
192
202
|
}
|
|
203
|
+
if (!obj.layerSuffix || typeof obj.layerSuffix !== "string") {
|
|
204
|
+
throw new Error(`${prefix}: layerSuffix must be a non-empty string`);
|
|
205
|
+
}
|
|
193
206
|
if (obj.widthFraction !== void 0 && (typeof obj.widthFraction !== "number" || obj.widthFraction <= 0)) {
|
|
194
207
|
throw new Error(`${prefix}: widthFraction must be a positive number`);
|
|
195
208
|
}
|
|
@@ -202,26 +215,38 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
202
215
|
if (obj.startZoom !== void 0 && (typeof obj.startZoom !== "number" || obj.startZoom < 0)) {
|
|
203
216
|
throw new Error(`${prefix}: startZoom must be a non-negative number`);
|
|
204
217
|
}
|
|
205
|
-
if (obj.endZoom !== void 0 && (typeof obj.endZoom !== "number" || obj.endZoom < 0)) {
|
|
206
|
-
throw new Error(`${prefix}: endZoom must be a non-negative number`);
|
|
218
|
+
if (obj.endZoom !== void 0 && (typeof obj.endZoom !== "number" || obj.endZoom < 0 && obj.endZoom !== INFINITY)) {
|
|
219
|
+
throw new Error(`${prefix}: endZoom must be a non-negative number or INFINITY (${INFINITY})`);
|
|
220
|
+
}
|
|
221
|
+
if (obj.lineExtensionFactor !== void 0 && (typeof obj.lineExtensionFactor !== "number" || obj.lineExtensionFactor < 0)) {
|
|
222
|
+
throw new Error(`${prefix}: lineExtensionFactor must be a non-negative number`);
|
|
223
|
+
}
|
|
224
|
+
if (obj.delWidthFactor !== void 0 && (typeof obj.delWidthFactor !== "number" || obj.delWidthFactor < 0)) {
|
|
225
|
+
throw new Error(`${prefix}: delWidthFactor must be a non-negative number`);
|
|
207
226
|
}
|
|
208
227
|
}
|
|
209
228
|
/**
|
|
210
229
|
* @param {Object} options
|
|
211
230
|
* @param {string} options.color - CSS color string
|
|
231
|
+
* @param {string} options.layerSuffix - Layer suffix (e.g., 'osm', 'ne', 'osm-disp')
|
|
212
232
|
* @param {number} [options.widthFraction=1.0] - Multiplier for base line width
|
|
213
233
|
* @param {number[]} [options.dashArray] - Dash pattern for dashed lines
|
|
214
234
|
* @param {number} [options.alpha=1.0] - Opacity (0-1)
|
|
215
|
-
* @param {number} [options.startZoom] - Minimum zoom level for this style
|
|
216
|
-
* @param {number} [options.endZoom=
|
|
235
|
+
* @param {number} [options.startZoom=0] - Minimum zoom level for this style
|
|
236
|
+
* @param {number} [options.endZoom=INFINITY] - Maximum zoom level for this style (INFINITY means no limit)
|
|
237
|
+
* @param {number} [options.lineExtensionFactor=0.5] - Factor to extend lines by (multiplied by deletion line width)
|
|
238
|
+
* @param {number} [options.delWidthFactor=1.5] - Factor to multiply line width for deletion blur
|
|
217
239
|
*/
|
|
218
|
-
constructor({ color, widthFraction = 1, dashArray, alpha = 1, startZoom, endZoom =
|
|
240
|
+
constructor({ color, layerSuffix, widthFraction = 1, dashArray, alpha = 1, startZoom = 0, endZoom = INFINITY, lineExtensionFactor = 0.5, delWidthFactor = 1.5 }) {
|
|
219
241
|
this.color = color;
|
|
242
|
+
this.layerSuffix = layerSuffix;
|
|
220
243
|
this.widthFraction = widthFraction;
|
|
221
244
|
this.dashArray = dashArray;
|
|
222
245
|
this.alpha = alpha;
|
|
223
246
|
this.startZoom = startZoom;
|
|
224
247
|
this.endZoom = endZoom;
|
|
248
|
+
this.lineExtensionFactor = lineExtensionFactor;
|
|
249
|
+
this.delWidthFactor = delWidthFactor;
|
|
225
250
|
}
|
|
226
251
|
/**
|
|
227
252
|
* Check if this style is active at the given zoom level.
|
|
@@ -229,34 +254,34 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
229
254
|
* @returns {boolean}
|
|
230
255
|
*/
|
|
231
256
|
isActiveAtZoom(z2) {
|
|
232
|
-
return z2 >= this.startZoom && z2 <= this.endZoom;
|
|
257
|
+
return z2 >= this.startZoom && (this.endZoom === INFINITY || z2 <= this.endZoom);
|
|
233
258
|
}
|
|
234
259
|
/**
|
|
235
260
|
* Serialize to plain object.
|
|
236
261
|
* @returns {Object}
|
|
237
262
|
*/
|
|
238
263
|
toJSON() {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
264
|
+
return {
|
|
265
|
+
color: this.color,
|
|
266
|
+
layerSuffix: this.layerSuffix,
|
|
267
|
+
widthFraction: this.widthFraction,
|
|
268
|
+
dashArray: this.dashArray,
|
|
269
|
+
alpha: this.alpha,
|
|
270
|
+
startZoom: this.startZoom,
|
|
271
|
+
endZoom: this.endZoom,
|
|
272
|
+
lineExtensionFactor: this.lineExtensionFactor,
|
|
273
|
+
delWidthFactor: this.delWidthFactor
|
|
274
|
+
};
|
|
246
275
|
}
|
|
247
276
|
/**
|
|
248
277
|
* Create from plain object with validation.
|
|
249
278
|
* @param {Object} obj
|
|
250
|
-
* @param {number} [defaultStartZoom=0] - Default startZoom if not specified
|
|
251
279
|
* @param {number} [index] - Optional index for error messages
|
|
252
280
|
* @returns {LineStyle}
|
|
253
281
|
*/
|
|
254
|
-
static fromJSON(obj,
|
|
282
|
+
static fromJSON(obj, index) {
|
|
255
283
|
_LineStyle.validateJSON(obj, index);
|
|
256
|
-
return new _LineStyle(
|
|
257
|
-
...obj,
|
|
258
|
-
startZoom: obj.startZoom ?? defaultStartZoom
|
|
259
|
-
});
|
|
284
|
+
return new _LineStyle(obj);
|
|
260
285
|
}
|
|
261
286
|
};
|
|
262
287
|
var LayerConfig = class _LayerConfig {
|
|
@@ -277,17 +302,6 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
277
302
|
throw new Error(`LayerConfig: id cannot contain slashes: "${obj.id}"`);
|
|
278
303
|
}
|
|
279
304
|
const id = obj.id;
|
|
280
|
-
if (obj.startZoom !== void 0 && (typeof obj.startZoom !== "number" || obj.startZoom < 0)) {
|
|
281
|
-
throw new Error(`LayerConfig "${id}": startZoom must be a non-negative number`);
|
|
282
|
-
}
|
|
283
|
-
if (obj.zoomThreshold !== void 0 && (typeof obj.zoomThreshold !== "number" || obj.zoomThreshold < 0)) {
|
|
284
|
-
throw new Error(`LayerConfig "${id}": zoomThreshold must be a non-negative number`);
|
|
285
|
-
}
|
|
286
|
-
const startZoom = obj.startZoom ?? 0;
|
|
287
|
-
const zoomThreshold = obj.zoomThreshold ?? 5;
|
|
288
|
-
if (startZoom > zoomThreshold) {
|
|
289
|
-
throw new Error(`LayerConfig "${id}": startZoom (${startZoom}) must be <= zoomThreshold (${zoomThreshold})`);
|
|
290
|
-
}
|
|
291
305
|
if (obj.lineWidthStops !== void 0) {
|
|
292
306
|
if (!obj.lineWidthStops || typeof obj.lineWidthStops !== "object" || Array.isArray(obj.lineWidthStops)) {
|
|
293
307
|
throw new Error(`LayerConfig "${id}": lineWidthStops must be an object`);
|
|
@@ -306,59 +320,35 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
306
320
|
}
|
|
307
321
|
}
|
|
308
322
|
}
|
|
309
|
-
if (obj.lineStyles
|
|
310
|
-
|
|
311
|
-
throw new Error(`LayerConfig "${id}": lineStyles must be a non-empty array`);
|
|
312
|
-
}
|
|
313
|
-
for (let i2 = 0; i2 < obj.lineStyles.length; i2++) {
|
|
314
|
-
LineStyle.validateJSON(obj.lineStyles[i2], i2);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
if (obj.delWidthFactor !== void 0 && (typeof obj.delWidthFactor !== "number" || obj.delWidthFactor <= 0)) {
|
|
318
|
-
throw new Error(`LayerConfig "${id}": delWidthFactor must be a positive number`);
|
|
323
|
+
if (!Array.isArray(obj.lineStyles) || obj.lineStyles.length === 0) {
|
|
324
|
+
throw new Error(`LayerConfig "${id}": lineStyles must be a non-empty array`);
|
|
319
325
|
}
|
|
320
|
-
|
|
321
|
-
|
|
326
|
+
for (let i2 = 0; i2 < obj.lineStyles.length; i2++) {
|
|
327
|
+
LineStyle.validateJSON(obj.lineStyles[i2], i2);
|
|
322
328
|
}
|
|
323
329
|
}
|
|
324
330
|
constructor({
|
|
325
331
|
id,
|
|
326
|
-
startZoom = 0,
|
|
327
|
-
zoomThreshold = 5,
|
|
328
332
|
// Tile URL templates for matching (e.g., "https://{s}.tile.example.com/{z}/{x}/{y}.png")
|
|
329
333
|
tileUrlTemplates = [],
|
|
330
334
|
// Line width stops: map of zoom level to line width (at least 2 entries)
|
|
331
335
|
// Note: interpolated/extrapolated line width is capped at a minimum of 0.5
|
|
332
336
|
lineWidthStops = { 1: 0.5, 10: 2.5 },
|
|
333
|
-
// Line styles array - each element describes a line to draw
|
|
334
|
-
// { color: string, widthFraction?: number, dashArray?: number[],
|
|
335
|
-
//
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
// Higher values leave gaps where wiped lines meet existing lines
|
|
339
|
-
// Lower values mean wiped lines show through
|
|
340
|
-
delWidthFactor = 1.5,
|
|
341
|
-
// Factor to extend add lines by (multiplied by deletion line width)
|
|
342
|
-
// Helps cover gaps where deleted lines meet the new boundary
|
|
343
|
-
// Set to 0 to disable extension
|
|
344
|
-
lineExtensionFactor = 0.5
|
|
337
|
+
// Line styles array - each element describes a line to draw from a specific layer
|
|
338
|
+
// { color: string, layerSuffix: string, widthFraction?: number, dashArray?: number[],
|
|
339
|
+
// startZoom?: number, endZoom?: number, lineExtensionFactor?: number, delWidthFactor?: number }
|
|
340
|
+
// Lines are drawn in array order. layerSuffix determines which PMTiles layer to use.
|
|
341
|
+
lineStyles
|
|
345
342
|
}) {
|
|
346
343
|
this.id = id;
|
|
347
|
-
this.startZoom = startZoom;
|
|
348
|
-
this.zoomThreshold = zoomThreshold;
|
|
349
344
|
const templates = Array.isArray(tileUrlTemplates) ? tileUrlTemplates : tileUrlTemplates ? [tileUrlTemplates] : [];
|
|
350
345
|
this.tileUrlTemplates = templates;
|
|
351
346
|
this._compiledPatterns = templates.map((t) => templateToRegex(t));
|
|
352
347
|
this._templatePatterns = templates.map((t) => templateToTemplateRegex(t));
|
|
353
348
|
this.lineWidthStops = lineWidthStops;
|
|
354
349
|
this.lineStyles = lineStyles.map(
|
|
355
|
-
(style) => style instanceof LineStyle ? style : new LineStyle(
|
|
356
|
-
...style,
|
|
357
|
-
startZoom: style.startZoom ?? startZoom
|
|
358
|
-
})
|
|
350
|
+
(style) => style instanceof LineStyle ? style : new LineStyle(style)
|
|
359
351
|
);
|
|
360
|
-
this.delWidthFactor = delWidthFactor;
|
|
361
|
-
this.lineExtensionFactor = lineExtensionFactor;
|
|
362
352
|
}
|
|
363
353
|
/**
|
|
364
354
|
* Get line styles active at a given zoom level
|
|
@@ -368,6 +358,15 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
368
358
|
getLineStylesForZoom(z2) {
|
|
369
359
|
return this.lineStyles.filter((style) => style.isActiveAtZoom(z2));
|
|
370
360
|
}
|
|
361
|
+
/**
|
|
362
|
+
* Get unique layer suffixes from styles active at a given zoom level
|
|
363
|
+
* @param {number} z - Zoom level
|
|
364
|
+
* @returns {string[]}
|
|
365
|
+
*/
|
|
366
|
+
getLayerSuffixesForZoom(z2) {
|
|
367
|
+
const activeStyles = this.getLineStylesForZoom(z2);
|
|
368
|
+
return [...new Set(activeStyles.map((s) => s.layerSuffix))];
|
|
369
|
+
}
|
|
371
370
|
/**
|
|
372
371
|
* Check if this config matches the given template URLs (with {z}/{x}/{y} placeholders)
|
|
373
372
|
* @param {string | string[]} templates - Single template URL or array of template URLs
|
|
@@ -425,13 +424,9 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
425
424
|
toJSON() {
|
|
426
425
|
return {
|
|
427
426
|
id: this.id,
|
|
428
|
-
startZoom: this.startZoom,
|
|
429
|
-
zoomThreshold: this.zoomThreshold,
|
|
430
427
|
tileUrlTemplates: this.tileUrlTemplates,
|
|
431
428
|
lineWidthStops: this.lineWidthStops,
|
|
432
|
-
lineStyles: this.lineStyles.map((s) => s.toJSON())
|
|
433
|
-
delWidthFactor: this.delWidthFactor,
|
|
434
|
-
lineExtensionFactor: this.lineExtensionFactor
|
|
429
|
+
lineStyles: this.lineStyles.map((s) => s.toJSON())
|
|
435
430
|
};
|
|
436
431
|
}
|
|
437
432
|
/**
|
|
@@ -2768,6 +2763,494 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
2768
2763
|
return await this._fetchTile(z2, x22, y, signal);
|
|
2769
2764
|
}
|
|
2770
2765
|
};
|
|
2766
|
+
var configs_default2 = [
|
|
2767
|
+
{
|
|
2768
|
+
id: "cartodb-dark",
|
|
2769
|
+
tileUrlTemplates: [
|
|
2770
|
+
"https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
|
|
2771
|
+
"https://basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
|
|
2772
|
+
"https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}{r}.png",
|
|
2773
|
+
"https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}{r}.png",
|
|
2774
|
+
"https://basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}{r}.png",
|
|
2775
|
+
"https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_nolabels/{z}/{x}/{y}{r}.png"
|
|
2776
|
+
],
|
|
2777
|
+
lineWidthStops: { "0": 1, "2": 1, "3": 1, "10": 2.5 },
|
|
2778
|
+
lineStyles: [
|
|
2779
|
+
{ color: "rgb(40, 40, 40)", layerSuffix: "ne", endZoom: 4 },
|
|
2780
|
+
{ color: "rgb(40, 40, 40)", layerSuffix: "ne-disp", endZoom: 4 },
|
|
2781
|
+
{ color: "rgb(40, 40, 40)", layerSuffix: "osm", startZoom: 5 },
|
|
2782
|
+
{ color: "rgb(40, 40, 40)", layerSuffix: "osm-disp", startZoom: 5 },
|
|
2783
|
+
{ color: "rgb(40, 40, 40)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.3, dashArray: [2, 2] }
|
|
2784
|
+
]
|
|
2785
|
+
},
|
|
2786
|
+
{
|
|
2787
|
+
id: "cartodb-light",
|
|
2788
|
+
tileUrlTemplates: [
|
|
2789
|
+
"https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
|
|
2790
|
+
"https://basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
|
|
2791
|
+
"https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}{r}.png",
|
|
2792
|
+
"https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png",
|
|
2793
|
+
"https://basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png",
|
|
2794
|
+
"https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_nolabels/{z}/{x}/{y}{r}.png",
|
|
2795
|
+
"https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
|
|
2796
|
+
"https://basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
|
|
2797
|
+
"https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}{r}.png",
|
|
2798
|
+
"https://basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}{r}.png",
|
|
2799
|
+
"https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png",
|
|
2800
|
+
"https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png"
|
|
2801
|
+
],
|
|
2802
|
+
lineWidthStops: { "1": 0.5, "2": 0.5, "3": 0.5, "4": 1, "5": 1.25, "7": 1.5, "16": 2.5 },
|
|
2803
|
+
lineStyles: [
|
|
2804
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "ne", endZoom: 4, lineExtensionFactor: 0.1, delWidthFactor: 2 },
|
|
2805
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "ne-disp", endZoom: 4, lineExtensionFactor: 0 },
|
|
2806
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.2, startZoom: 6, widthFraction: 3, lineExtensionFactor: 0.1 },
|
|
2807
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "osm", startZoom: 5, lineExtensionFactor: 0.1 },
|
|
2808
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", alpha: 0.2, startZoom: 6, widthFraction: 3, lineExtensionFactor: 0 },
|
|
2809
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", startZoom: 5, lineExtensionFactor: 0 },
|
|
2810
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.75, dashArray: [2, 2], delWidthFactor: 2 }
|
|
2811
|
+
]
|
|
2812
|
+
},
|
|
2813
|
+
{
|
|
2814
|
+
id: "open-topo",
|
|
2815
|
+
tileUrlTemplates: [
|
|
2816
|
+
"https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
|
|
2817
|
+
"https://tile.opentopomap.org/{z}/{x}/{y}.png"
|
|
2818
|
+
],
|
|
2819
|
+
lineWidthStops: { "4": 0.75, "5": 1, "6": 1.25, "7": 1.5, "8": 1.75, "9": 1.25, "10": 1.25, "13": 1.5 },
|
|
2820
|
+
lineStyles: [
|
|
2821
|
+
{ color: "rgb(83, 83, 83)", layerSuffix: "ne", startZoom: 4, endZoom: 6 },
|
|
2822
|
+
{ color: "rgb(173, 173, 173)", layerSuffix: "osm", startZoom: 7, endZoom: 8, alpha: 0.5, widthFraction: 4 },
|
|
2823
|
+
{ color: "rgb(83, 83, 83)", layerSuffix: "osm", startZoom: 7, endZoom: 8 },
|
|
2824
|
+
{ color: "rgb(199, 158, 204)", layerSuffix: "osm", startZoom: 9, widthFraction: 7, alpha: 0.6, lineExtensionFactor: 0.2 },
|
|
2825
|
+
{ color: "rgb(175, 41, 203)", layerSuffix: "osm", startZoom: 9, lineExtensionFactor: 0.2 }
|
|
2826
|
+
]
|
|
2827
|
+
},
|
|
2828
|
+
{
|
|
2829
|
+
id: "osm-carto",
|
|
2830
|
+
tileUrlTemplates: [
|
|
2831
|
+
"https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
|
2832
|
+
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
|
2833
|
+
],
|
|
2834
|
+
lineWidthStops: { "1": 0.5, "2": 0.6, "3": 0.7, "4": 1, "10": 3.75 },
|
|
2835
|
+
lineStyles: [
|
|
2836
|
+
{ color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 1, endZoom: 3, delWidthFactor: 2.5, widthFraction: 1.5 },
|
|
2837
|
+
{ color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 4 },
|
|
2838
|
+
{ color: "rgb(160, 120, 160)", layerSuffix: "osm", startZoom: 4, widthFraction: 0.333, dashArray: [30, 2, 8, 2] },
|
|
2839
|
+
{ color: "rgb(200, 180, 200)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.45 },
|
|
2840
|
+
{ color: "rgb(160, 120, 160)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.15, dashArray: [4, 2, 10] }
|
|
2841
|
+
]
|
|
2842
|
+
},
|
|
2843
|
+
{
|
|
2844
|
+
id: "osm-hot",
|
|
2845
|
+
tileUrlTemplates: [
|
|
2846
|
+
"https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png",
|
|
2847
|
+
"https://tile.openstreetmap.fr/hot/{z}/{x}/{y}.png"
|
|
2848
|
+
],
|
|
2849
|
+
lineWidthStops: { "2": 3, "3": 3, "7": 3, "8": 3.5, "9": 3.5 },
|
|
2850
|
+
lineStyles: [
|
|
2851
|
+
{ color: "rgb(149, 175, 180)", layerSuffix: "osm", lineExtensionFactor: 0.25, startZoom: 2 },
|
|
2852
|
+
{ color: "rgb(89, 117, 123)", layerSuffix: "osm", widthFraction: 0.33, lineExtensionFactor: 0.25, startZoom: 2 },
|
|
2853
|
+
{ color: "rgb(172, 163, 163)", layerSuffix: "osm-internal", widthFraction: 0.33, startZoom: 4, dashArray: [7, 7, 7] }
|
|
2854
|
+
]
|
|
2855
|
+
}
|
|
2856
|
+
];
|
|
2857
|
+
var INFINITY2 = -1;
|
|
2858
|
+
function templateToRegex2(template) {
|
|
2859
|
+
const groups = [];
|
|
2860
|
+
let pattern = template.replace(/[.*+?^${}()|[\]\\]/g, (char) => {
|
|
2861
|
+
if (char === "{" || char === "}") return char;
|
|
2862
|
+
return "\\" + char;
|
|
2863
|
+
}).replace(/^https:\/\//, "https?://").replace(/^http:\/\//, "https?://").replace(/\{[a-z0-9]-[a-z0-9]\}/gi, () => {
|
|
2864
|
+
groups.push("s");
|
|
2865
|
+
return "([a-z0-9]+)";
|
|
2866
|
+
}).replace(/\{(z|x|y|s|r)\}/gi, (_2, name) => {
|
|
2867
|
+
const lowerName = name.toLowerCase();
|
|
2868
|
+
groups.push(lowerName);
|
|
2869
|
+
if (lowerName === "s") {
|
|
2870
|
+
return "([a-z0-9]+)";
|
|
2871
|
+
}
|
|
2872
|
+
if (lowerName === "r") {
|
|
2873
|
+
return "(@\\d+x)?";
|
|
2874
|
+
}
|
|
2875
|
+
return "(\\d+)";
|
|
2876
|
+
});
|
|
2877
|
+
return { pattern: new RegExp("^" + pattern + "(\\?.*)?$", "i"), groups };
|
|
2878
|
+
}
|
|
2879
|
+
function templateToTemplateRegex2(template) {
|
|
2880
|
+
let pattern = template.replace(/[.*+?^${}()|[\]\\]/g, (char) => {
|
|
2881
|
+
if (char === "{" || char === "}") return char;
|
|
2882
|
+
return "\\" + char;
|
|
2883
|
+
}).replace(/^https:\/\//, "https?://").replace(/^http:\/\//, "https?://").replace(/\{([a-z0-9])-([a-z0-9])\}/gi, (_2, start, end) => `(\\{${start}-${end}\\}|\\{s\\}|[a-z0-9]+)`).replace(/\{(z|x|y|s|r)\}/gi, (_2, name) => {
|
|
2884
|
+
const lowerName = name.toLowerCase();
|
|
2885
|
+
if (lowerName === "s") {
|
|
2886
|
+
return "(\\{s\\}|\\{[a-z0-9]-[a-z0-9]\\}|[a-z0-9]+)";
|
|
2887
|
+
}
|
|
2888
|
+
if (lowerName === "r") {
|
|
2889
|
+
return "(\\{r\\}|@\\d+x)?";
|
|
2890
|
+
}
|
|
2891
|
+
return `\\{${lowerName}\\}`;
|
|
2892
|
+
});
|
|
2893
|
+
return new RegExp("^" + pattern + "(\\?.*)?$", "i");
|
|
2894
|
+
}
|
|
2895
|
+
function isValidColor2(color) {
|
|
2896
|
+
if (typeof color !== "string" || !color.trim()) return false;
|
|
2897
|
+
if (typeof CSS !== "undefined" && CSS.supports) {
|
|
2898
|
+
return CSS.supports("color", color);
|
|
2899
|
+
}
|
|
2900
|
+
const trimmed = color.trim().toLowerCase();
|
|
2901
|
+
if (/^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/.test(trimmed)) return true;
|
|
2902
|
+
if (/^(rgb|hsl)a?\(/.test(trimmed)) return true;
|
|
2903
|
+
if (/^[a-z]+$/.test(trimmed)) return true;
|
|
2904
|
+
return false;
|
|
2905
|
+
}
|
|
2906
|
+
var LineStyle2 = class _LineStyle2 {
|
|
2907
|
+
/**
|
|
2908
|
+
* Validate a LineStyle configuration object.
|
|
2909
|
+
* @param {Object} obj - The object to validate
|
|
2910
|
+
* @param {number} [index] - Optional index for error messages (when validating in an array)
|
|
2911
|
+
* @throws {Error} If validation fails
|
|
2912
|
+
*/
|
|
2913
|
+
static validateJSON(obj, index) {
|
|
2914
|
+
const prefix = index !== void 0 ? `lineStyles[${index}]` : "LineStyle";
|
|
2915
|
+
if (!obj || typeof obj !== "object") {
|
|
2916
|
+
throw new Error(`${prefix}: must be an object`);
|
|
2917
|
+
}
|
|
2918
|
+
if (!obj.color || typeof obj.color !== "string") {
|
|
2919
|
+
throw new Error(`${prefix}: color must be a non-empty string`);
|
|
2920
|
+
}
|
|
2921
|
+
if (!isValidColor2(obj.color)) {
|
|
2922
|
+
throw new Error(`${prefix}: color "${obj.color}" is not a valid CSS color`);
|
|
2923
|
+
}
|
|
2924
|
+
if (!obj.layerSuffix || typeof obj.layerSuffix !== "string") {
|
|
2925
|
+
throw new Error(`${prefix}: layerSuffix must be a non-empty string`);
|
|
2926
|
+
}
|
|
2927
|
+
if (obj.widthFraction !== void 0 && (typeof obj.widthFraction !== "number" || obj.widthFraction <= 0)) {
|
|
2928
|
+
throw new Error(`${prefix}: widthFraction must be a positive number`);
|
|
2929
|
+
}
|
|
2930
|
+
if (obj.dashArray !== void 0 && !Array.isArray(obj.dashArray)) {
|
|
2931
|
+
throw new Error(`${prefix}: dashArray must be an array`);
|
|
2932
|
+
}
|
|
2933
|
+
if (obj.alpha !== void 0 && (typeof obj.alpha !== "number" || obj.alpha < 0 || obj.alpha > 1)) {
|
|
2934
|
+
throw new Error(`${prefix}: alpha must be a number between 0 and 1`);
|
|
2935
|
+
}
|
|
2936
|
+
if (obj.startZoom !== void 0 && (typeof obj.startZoom !== "number" || obj.startZoom < 0)) {
|
|
2937
|
+
throw new Error(`${prefix}: startZoom must be a non-negative number`);
|
|
2938
|
+
}
|
|
2939
|
+
if (obj.endZoom !== void 0 && (typeof obj.endZoom !== "number" || obj.endZoom < 0 && obj.endZoom !== INFINITY2)) {
|
|
2940
|
+
throw new Error(`${prefix}: endZoom must be a non-negative number or INFINITY (${INFINITY2})`);
|
|
2941
|
+
}
|
|
2942
|
+
if (obj.lineExtensionFactor !== void 0 && (typeof obj.lineExtensionFactor !== "number" || obj.lineExtensionFactor < 0)) {
|
|
2943
|
+
throw new Error(`${prefix}: lineExtensionFactor must be a non-negative number`);
|
|
2944
|
+
}
|
|
2945
|
+
if (obj.delWidthFactor !== void 0 && (typeof obj.delWidthFactor !== "number" || obj.delWidthFactor < 0)) {
|
|
2946
|
+
throw new Error(`${prefix}: delWidthFactor must be a non-negative number`);
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2949
|
+
/**
|
|
2950
|
+
* @param {Object} options
|
|
2951
|
+
* @param {string} options.color - CSS color string
|
|
2952
|
+
* @param {string} options.layerSuffix - Layer suffix (e.g., 'osm', 'ne', 'osm-disp')
|
|
2953
|
+
* @param {number} [options.widthFraction=1.0] - Multiplier for base line width
|
|
2954
|
+
* @param {number[]} [options.dashArray] - Dash pattern for dashed lines
|
|
2955
|
+
* @param {number} [options.alpha=1.0] - Opacity (0-1)
|
|
2956
|
+
* @param {number} [options.startZoom=0] - Minimum zoom level for this style
|
|
2957
|
+
* @param {number} [options.endZoom=INFINITY] - Maximum zoom level for this style (INFINITY means no limit)
|
|
2958
|
+
* @param {number} [options.lineExtensionFactor=0.5] - Factor to extend lines by (multiplied by deletion line width)
|
|
2959
|
+
* @param {number} [options.delWidthFactor=1.5] - Factor to multiply line width for deletion blur
|
|
2960
|
+
*/
|
|
2961
|
+
constructor({ color, layerSuffix, widthFraction = 1, dashArray, alpha = 1, startZoom = 0, endZoom = INFINITY2, lineExtensionFactor = 0.5, delWidthFactor = 1.5 }) {
|
|
2962
|
+
this.color = color;
|
|
2963
|
+
this.layerSuffix = layerSuffix;
|
|
2964
|
+
this.widthFraction = widthFraction;
|
|
2965
|
+
this.dashArray = dashArray;
|
|
2966
|
+
this.alpha = alpha;
|
|
2967
|
+
this.startZoom = startZoom;
|
|
2968
|
+
this.endZoom = endZoom;
|
|
2969
|
+
this.lineExtensionFactor = lineExtensionFactor;
|
|
2970
|
+
this.delWidthFactor = delWidthFactor;
|
|
2971
|
+
}
|
|
2972
|
+
/**
|
|
2973
|
+
* Check if this style is active at the given zoom level.
|
|
2974
|
+
* @param {number} z - Zoom level
|
|
2975
|
+
* @returns {boolean}
|
|
2976
|
+
*/
|
|
2977
|
+
isActiveAtZoom(z2) {
|
|
2978
|
+
return z2 >= this.startZoom && (this.endZoom === INFINITY2 || z2 <= this.endZoom);
|
|
2979
|
+
}
|
|
2980
|
+
/**
|
|
2981
|
+
* Serialize to plain object.
|
|
2982
|
+
* @returns {Object}
|
|
2983
|
+
*/
|
|
2984
|
+
toJSON() {
|
|
2985
|
+
return {
|
|
2986
|
+
color: this.color,
|
|
2987
|
+
layerSuffix: this.layerSuffix,
|
|
2988
|
+
widthFraction: this.widthFraction,
|
|
2989
|
+
dashArray: this.dashArray,
|
|
2990
|
+
alpha: this.alpha,
|
|
2991
|
+
startZoom: this.startZoom,
|
|
2992
|
+
endZoom: this.endZoom,
|
|
2993
|
+
lineExtensionFactor: this.lineExtensionFactor,
|
|
2994
|
+
delWidthFactor: this.delWidthFactor
|
|
2995
|
+
};
|
|
2996
|
+
}
|
|
2997
|
+
/**
|
|
2998
|
+
* Create from plain object with validation.
|
|
2999
|
+
* @param {Object} obj
|
|
3000
|
+
* @param {number} [index] - Optional index for error messages
|
|
3001
|
+
* @returns {LineStyle}
|
|
3002
|
+
*/
|
|
3003
|
+
static fromJSON(obj, index) {
|
|
3004
|
+
_LineStyle2.validateJSON(obj, index);
|
|
3005
|
+
return new _LineStyle2(obj);
|
|
3006
|
+
}
|
|
3007
|
+
};
|
|
3008
|
+
var LayerConfig2 = class _LayerConfig2 {
|
|
3009
|
+
/**
|
|
3010
|
+
* Validate a LayerConfig configuration object.
|
|
3011
|
+
* Also validates all lineStyles within the config.
|
|
3012
|
+
* @param {Object} obj - The object to validate
|
|
3013
|
+
* @throws {Error} If validation fails
|
|
3014
|
+
*/
|
|
3015
|
+
static validateJSON(obj) {
|
|
3016
|
+
if (!obj || typeof obj !== "object") {
|
|
3017
|
+
throw new Error("LayerConfig: must be an object");
|
|
3018
|
+
}
|
|
3019
|
+
if (!obj.id || typeof obj.id !== "string") {
|
|
3020
|
+
throw new Error("LayerConfig: id must be a non-empty string");
|
|
3021
|
+
}
|
|
3022
|
+
if (obj.id.includes("/")) {
|
|
3023
|
+
throw new Error(`LayerConfig: id cannot contain slashes: "${obj.id}"`);
|
|
3024
|
+
}
|
|
3025
|
+
const id = obj.id;
|
|
3026
|
+
if (obj.lineWidthStops !== void 0) {
|
|
3027
|
+
if (!obj.lineWidthStops || typeof obj.lineWidthStops !== "object" || Array.isArray(obj.lineWidthStops)) {
|
|
3028
|
+
throw new Error(`LayerConfig "${id}": lineWidthStops must be an object`);
|
|
3029
|
+
}
|
|
3030
|
+
const stopKeys = Object.keys(obj.lineWidthStops);
|
|
3031
|
+
if (stopKeys.length < 2) {
|
|
3032
|
+
throw new Error(`LayerConfig "${id}": lineWidthStops must have at least 2 entries`);
|
|
3033
|
+
}
|
|
3034
|
+
for (const key of stopKeys) {
|
|
3035
|
+
const zoom = Number(key);
|
|
3036
|
+
if (!Number.isInteger(zoom) || zoom < 0) {
|
|
3037
|
+
throw new Error(`LayerConfig "${id}": lineWidthStops keys must be non-negative integers, got "${key}"`);
|
|
3038
|
+
}
|
|
3039
|
+
if (typeof obj.lineWidthStops[key] !== "number" || obj.lineWidthStops[key] <= 0) {
|
|
3040
|
+
throw new Error(`LayerConfig "${id}": lineWidthStops values must be positive numbers`);
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
}
|
|
3044
|
+
if (!Array.isArray(obj.lineStyles) || obj.lineStyles.length === 0) {
|
|
3045
|
+
throw new Error(`LayerConfig "${id}": lineStyles must be a non-empty array`);
|
|
3046
|
+
}
|
|
3047
|
+
for (let i2 = 0; i2 < obj.lineStyles.length; i2++) {
|
|
3048
|
+
LineStyle2.validateJSON(obj.lineStyles[i2], i2);
|
|
3049
|
+
}
|
|
3050
|
+
}
|
|
3051
|
+
constructor({
|
|
3052
|
+
id,
|
|
3053
|
+
// Tile URL templates for matching (e.g., "https://{s}.tile.example.com/{z}/{x}/{y}.png")
|
|
3054
|
+
tileUrlTemplates = [],
|
|
3055
|
+
// Line width stops: map of zoom level to line width (at least 2 entries)
|
|
3056
|
+
// Note: interpolated/extrapolated line width is capped at a minimum of 0.5
|
|
3057
|
+
lineWidthStops = { 1: 0.5, 10: 2.5 },
|
|
3058
|
+
// Line styles array - each element describes a line to draw from a specific layer
|
|
3059
|
+
// { color: string, layerSuffix: string, widthFraction?: number, dashArray?: number[],
|
|
3060
|
+
// startZoom?: number, endZoom?: number, lineExtensionFactor?: number, delWidthFactor?: number }
|
|
3061
|
+
// Lines are drawn in array order. layerSuffix determines which PMTiles layer to use.
|
|
3062
|
+
lineStyles
|
|
3063
|
+
}) {
|
|
3064
|
+
this.id = id;
|
|
3065
|
+
const templates = Array.isArray(tileUrlTemplates) ? tileUrlTemplates : tileUrlTemplates ? [tileUrlTemplates] : [];
|
|
3066
|
+
this.tileUrlTemplates = templates;
|
|
3067
|
+
this._compiledPatterns = templates.map((t) => templateToRegex2(t));
|
|
3068
|
+
this._templatePatterns = templates.map((t) => templateToTemplateRegex2(t));
|
|
3069
|
+
this.lineWidthStops = lineWidthStops;
|
|
3070
|
+
this.lineStyles = lineStyles.map(
|
|
3071
|
+
(style) => style instanceof LineStyle2 ? style : new LineStyle2(style)
|
|
3072
|
+
);
|
|
3073
|
+
}
|
|
3074
|
+
/**
|
|
3075
|
+
* Get line styles active at a given zoom level
|
|
3076
|
+
* @param {number} z - Zoom level
|
|
3077
|
+
* @returns {LineStyle[]}
|
|
3078
|
+
*/
|
|
3079
|
+
getLineStylesForZoom(z2) {
|
|
3080
|
+
return this.lineStyles.filter((style) => style.isActiveAtZoom(z2));
|
|
3081
|
+
}
|
|
3082
|
+
/**
|
|
3083
|
+
* Get unique layer suffixes from styles active at a given zoom level
|
|
3084
|
+
* @param {number} z - Zoom level
|
|
3085
|
+
* @returns {string[]}
|
|
3086
|
+
*/
|
|
3087
|
+
getLayerSuffixesForZoom(z2) {
|
|
3088
|
+
const activeStyles = this.getLineStylesForZoom(z2);
|
|
3089
|
+
return [...new Set(activeStyles.map((s) => s.layerSuffix))];
|
|
3090
|
+
}
|
|
3091
|
+
/**
|
|
3092
|
+
* Check if this config matches the given template URLs (with {z}/{x}/{y} placeholders)
|
|
3093
|
+
* @param {string | string[]} templates - Single template URL or array of template URLs
|
|
3094
|
+
* @returns {boolean}
|
|
3095
|
+
*/
|
|
3096
|
+
matchTemplate(templates) {
|
|
3097
|
+
if (this._templatePatterns.length === 0) return false;
|
|
3098
|
+
const urls = Array.isArray(templates) ? templates : [templates];
|
|
3099
|
+
if (urls.length === 0) return false;
|
|
3100
|
+
return urls.some(
|
|
3101
|
+
(url) => this._templatePatterns.some((pattern) => pattern.test(url))
|
|
3102
|
+
);
|
|
3103
|
+
}
|
|
3104
|
+
/**
|
|
3105
|
+
* Check if this config matches the given tile URLs (with actual coordinates)
|
|
3106
|
+
* @param {string | string[]} tiles - Single tile URL or array of tile URLs
|
|
3107
|
+
* @returns {boolean}
|
|
3108
|
+
*/
|
|
3109
|
+
matchTileUrl(tiles) {
|
|
3110
|
+
if (this._compiledPatterns.length === 0) return false;
|
|
3111
|
+
const urls = Array.isArray(tiles) ? tiles : [tiles];
|
|
3112
|
+
if (urls.length === 0) return false;
|
|
3113
|
+
return urls.some(
|
|
3114
|
+
(url) => this._compiledPatterns.some(({ pattern }) => pattern.test(url))
|
|
3115
|
+
);
|
|
3116
|
+
}
|
|
3117
|
+
/**
|
|
3118
|
+
* Extract tile coordinates (z, x, y) from a URL using this config's templates
|
|
3119
|
+
* @param {string} url - Tile URL to extract coordinates from
|
|
3120
|
+
* @returns {{ z: number, x: number, y: number } | null}
|
|
3121
|
+
*/
|
|
3122
|
+
extractCoords(url) {
|
|
3123
|
+
for (const { pattern, groups } of this._compiledPatterns) {
|
|
3124
|
+
const match = url.match(pattern);
|
|
3125
|
+
if (match) {
|
|
3126
|
+
const result = {};
|
|
3127
|
+
for (let i2 = 0; i2 < groups.length; i2++) {
|
|
3128
|
+
const name = groups[i2];
|
|
3129
|
+
const value = match[i2 + 1];
|
|
3130
|
+
if (name === "z" || name === "x" || name === "y") {
|
|
3131
|
+
result[name] = parseInt(value, 10);
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3134
|
+
if ("z" in result && "x" in result && "y" in result) {
|
|
3135
|
+
return { z: result.z, x: result.x, y: result.y };
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
3139
|
+
return null;
|
|
3140
|
+
}
|
|
3141
|
+
/**
|
|
3142
|
+
* Serialize the config to a plain object for postMessage
|
|
3143
|
+
* @returns {Object}
|
|
3144
|
+
*/
|
|
3145
|
+
toJSON() {
|
|
3146
|
+
return {
|
|
3147
|
+
id: this.id,
|
|
3148
|
+
tileUrlTemplates: this.tileUrlTemplates,
|
|
3149
|
+
lineWidthStops: this.lineWidthStops,
|
|
3150
|
+
lineStyles: this.lineStyles.map((s) => s.toJSON())
|
|
3151
|
+
};
|
|
3152
|
+
}
|
|
3153
|
+
/**
|
|
3154
|
+
* Create a LayerConfig from a plain object with validation.
|
|
3155
|
+
* @param {Object} obj
|
|
3156
|
+
* @returns {LayerConfig}
|
|
3157
|
+
* @throws {Error} If validation fails
|
|
3158
|
+
*/
|
|
3159
|
+
static fromJSON(obj) {
|
|
3160
|
+
_LayerConfig2.validateJSON(obj);
|
|
3161
|
+
return new _LayerConfig2(obj);
|
|
3162
|
+
}
|
|
3163
|
+
};
|
|
3164
|
+
var LayerConfigRegistry2 = class _LayerConfigRegistry2 {
|
|
3165
|
+
constructor() {
|
|
3166
|
+
this.registry = {};
|
|
3167
|
+
}
|
|
3168
|
+
/**
|
|
3169
|
+
* Get a layer config by id
|
|
3170
|
+
*/
|
|
3171
|
+
get(id) {
|
|
3172
|
+
return this.registry[id];
|
|
3173
|
+
}
|
|
3174
|
+
/**
|
|
3175
|
+
* Register a new layer config
|
|
3176
|
+
*/
|
|
3177
|
+
register(config) {
|
|
3178
|
+
this.registry[config.id] = config;
|
|
3179
|
+
}
|
|
3180
|
+
/**
|
|
3181
|
+
* Remove a layer config by id
|
|
3182
|
+
*/
|
|
3183
|
+
remove(id) {
|
|
3184
|
+
if (!this.registry[id]) return false;
|
|
3185
|
+
delete this.registry[id];
|
|
3186
|
+
return true;
|
|
3187
|
+
}
|
|
3188
|
+
/**
|
|
3189
|
+
* Detect layer config from tile URL templates (with {z}/{x}/{y} placeholders)
|
|
3190
|
+
* @param {string | string[]} templates - Single template URL or array of template URLs
|
|
3191
|
+
*/
|
|
3192
|
+
detectFromTemplates(templates) {
|
|
3193
|
+
if (!templates || Array.isArray(templates) && templates.length === 0) return void 0;
|
|
3194
|
+
for (const config of Object.values(this.registry)) {
|
|
3195
|
+
if (config.matchTemplate(templates)) {
|
|
3196
|
+
return config;
|
|
3197
|
+
}
|
|
3198
|
+
}
|
|
3199
|
+
return void 0;
|
|
3200
|
+
}
|
|
3201
|
+
/**
|
|
3202
|
+
* Detect layer config from actual tile URLs (with numeric coordinates)
|
|
3203
|
+
* @param {string | string[]} urls - Single tile URL or array of tile URLs
|
|
3204
|
+
*/
|
|
3205
|
+
detectFromTileUrls(urls) {
|
|
3206
|
+
if (!urls || Array.isArray(urls) && urls.length === 0) return void 0;
|
|
3207
|
+
for (const config of Object.values(this.registry)) {
|
|
3208
|
+
if (config.matchTileUrl(urls)) {
|
|
3209
|
+
return config;
|
|
3210
|
+
}
|
|
3211
|
+
}
|
|
3212
|
+
return void 0;
|
|
3213
|
+
}
|
|
3214
|
+
/**
|
|
3215
|
+
* Get all available layer config ids
|
|
3216
|
+
*/
|
|
3217
|
+
getAvailableIds() {
|
|
3218
|
+
return Object.keys(this.registry);
|
|
3219
|
+
}
|
|
3220
|
+
/**
|
|
3221
|
+
* Create a new registry with all configs from this registry plus extra configs.
|
|
3222
|
+
* @param {LayerConfig[]} extraLayerConfigs - Additional configs to add
|
|
3223
|
+
* @returns {LayerConfigRegistry} A new registry with merged configs
|
|
3224
|
+
*/
|
|
3225
|
+
createMergedRegistry(extraLayerConfigs) {
|
|
3226
|
+
const registry = new _LayerConfigRegistry2();
|
|
3227
|
+
for (const id of this.getAvailableIds()) {
|
|
3228
|
+
registry.register(this.get(id));
|
|
3229
|
+
}
|
|
3230
|
+
if (extraLayerConfigs && extraLayerConfigs.length > 0) {
|
|
3231
|
+
for (const config of extraLayerConfigs) {
|
|
3232
|
+
registry.register(config);
|
|
3233
|
+
}
|
|
3234
|
+
}
|
|
3235
|
+
return registry;
|
|
3236
|
+
}
|
|
3237
|
+
/**
|
|
3238
|
+
* Parse a tile URL into its components: layer config and coordinates
|
|
3239
|
+
* @param {string} url - Tile URL to parse
|
|
3240
|
+
* @returns {{ layerConfig: LayerConfig, coords: { z: number, x: number, y: number } } | null}
|
|
3241
|
+
*/
|
|
3242
|
+
parseTileUrl(url) {
|
|
3243
|
+
const layerConfig = this.detectFromTileUrls([url]);
|
|
3244
|
+
if (!layerConfig) return null;
|
|
3245
|
+
const coords = layerConfig.extractCoords(url);
|
|
3246
|
+
if (!coords) return null;
|
|
3247
|
+
return { layerConfig, coords };
|
|
3248
|
+
}
|
|
3249
|
+
};
|
|
3250
|
+
var layerConfigs2 = new LayerConfigRegistry2();
|
|
3251
|
+
for (const configData of configs_default2) {
|
|
3252
|
+
layerConfigs2.register(new LayerConfig2(configData));
|
|
3253
|
+
}
|
|
2771
3254
|
var TileFetchError = class _TileFetchError extends Error {
|
|
2772
3255
|
/**
|
|
2773
3256
|
* @param {number} status - HTTP status code
|
|
@@ -2795,7 +3278,7 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
2795
3278
|
return new _TileFetchError(response.status, response.url, body);
|
|
2796
3279
|
}
|
|
2797
3280
|
};
|
|
2798
|
-
var MIN_LINE_WIDTH = 0.
|
|
3281
|
+
var MIN_LINE_WIDTH = 0.1;
|
|
2799
3282
|
var DEFAULT_TILE_EXTENT = 4096;
|
|
2800
3283
|
var DEFAULT_LINE_WIDTH = 1;
|
|
2801
3284
|
function getLineWidth(zoom, lineWidthStops) {
|
|
@@ -3091,29 +3574,22 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
3091
3574
|
* @returns {Promise<ArrayBuffer>} The corrected tile as ArrayBuffer (PNG)
|
|
3092
3575
|
*/
|
|
3093
3576
|
async fixTile(corrections, rasterTile, layerConfig, zoom) {
|
|
3094
|
-
const {
|
|
3095
|
-
startZoom = 0,
|
|
3096
|
-
zoomThreshold,
|
|
3097
|
-
lineWidthStops,
|
|
3098
|
-
delWidthFactor
|
|
3099
|
-
} = layerConfig;
|
|
3100
|
-
if (zoom < startZoom) {
|
|
3101
|
-
return rasterTile;
|
|
3102
|
-
}
|
|
3577
|
+
const { lineWidthStops } = layerConfig;
|
|
3103
3578
|
let activeLineStyles;
|
|
3104
3579
|
if (layerConfig.getLineStylesForZoom) {
|
|
3105
3580
|
activeLineStyles = layerConfig.getLineStylesForZoom(zoom);
|
|
3106
3581
|
} else {
|
|
3107
3582
|
const allStyles = layerConfig.lineStyles || [];
|
|
3108
3583
|
activeLineStyles = allStyles.filter((style) => {
|
|
3109
|
-
const styleStart = style.startZoom ??
|
|
3110
|
-
const styleEnd = style.endZoom ??
|
|
3111
|
-
return zoom >= styleStart && zoom <= styleEnd;
|
|
3584
|
+
const styleStart = style.startZoom ?? 0;
|
|
3585
|
+
const styleEnd = style.endZoom ?? INFINITY2;
|
|
3586
|
+
return zoom >= styleStart && (styleEnd === INFINITY2 || zoom <= styleEnd);
|
|
3112
3587
|
});
|
|
3113
3588
|
}
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3589
|
+
if (activeLineStyles.length === 0) {
|
|
3590
|
+
return rasterTile;
|
|
3591
|
+
}
|
|
3592
|
+
const layerSuffixes = [...new Set(activeLineStyles.map((s) => s.layerSuffix))];
|
|
3117
3593
|
const blob = new Blob([rasterTile]);
|
|
3118
3594
|
const imageBitmap = await createImageBitmap(blob);
|
|
3119
3595
|
const tileSize = imageBitmap.width;
|
|
@@ -3124,22 +3600,33 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
3124
3600
|
const ctx = canvas.getContext("2d", { willReadFrequently: true });
|
|
3125
3601
|
ctx.drawImage(imageBitmap, 0, 0, tileSize, tileSize);
|
|
3126
3602
|
const baseLineWidth = getLineWidth(zoom, lineWidthStops);
|
|
3127
|
-
const
|
|
3128
|
-
const
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3603
|
+
const delLineWidthBySuffix = {};
|
|
3604
|
+
for (const suffix of layerSuffixes) {
|
|
3605
|
+
const stylesForSuffix = activeLineStyles.filter((s) => s.layerSuffix === suffix);
|
|
3606
|
+
const maxProduct = Math.max(...stylesForSuffix.map((s) => s.widthFraction * s.delWidthFactor));
|
|
3607
|
+
delLineWidthBySuffix[suffix] = baseLineWidth * maxProduct;
|
|
3608
|
+
}
|
|
3609
|
+
for (const suffix of layerSuffixes) {
|
|
3610
|
+
const delLineWidth = delLineWidthBySuffix[suffix];
|
|
3611
|
+
if (delLineWidth === 0) continue;
|
|
3612
|
+
const delLayerName = `to-del-${suffix}`;
|
|
3613
|
+
const delFeatures = corrections[delLayerName] || [];
|
|
3138
3614
|
if (delFeatures.length > 0) {
|
|
3139
|
-
|
|
3615
|
+
if (!this._maskCanvas || this._maskCanvas.width !== tileSize) {
|
|
3616
|
+
this._maskCanvas = new OffscreenCanvas(tileSize, tileSize);
|
|
3617
|
+
}
|
|
3618
|
+
applyMedianBlurAlongPath(ctx, delFeatures, delLineWidth, tileSize, this._maskCanvas);
|
|
3140
3619
|
}
|
|
3141
|
-
|
|
3142
|
-
|
|
3620
|
+
}
|
|
3621
|
+
for (const style of activeLineStyles) {
|
|
3622
|
+
const { color, layerSuffix, widthFraction, dashArray, alpha, lineExtensionFactor } = style;
|
|
3623
|
+
const addLayerName = `to-add-${layerSuffix}`;
|
|
3624
|
+
let addFeatures = corrections[addLayerName] || [];
|
|
3625
|
+
if (addFeatures.length > 0) {
|
|
3626
|
+
const delLineWidth = delLineWidthBySuffix[layerSuffix];
|
|
3627
|
+
if (lineExtensionFactor > 0) {
|
|
3628
|
+
addFeatures = extendFeaturesByFactor(addFeatures, lineExtensionFactor, delLineWidth, tileSize);
|
|
3629
|
+
}
|
|
3143
3630
|
const lineWidth = baseLineWidth * widthFraction;
|
|
3144
3631
|
drawFeatures(ctx, addFeatures, color, lineWidth, tileSize, dashArray, alpha);
|
|
3145
3632
|
}
|