@india-boundary-corrector/service-worker 0.0.4 → 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 +16 -3
- package/dist/index.global.js +219 -99
- 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 +788 -158
- package/dist/worker.global.js.map +1 -1
- package/package.json +4 -4
- package/src/worker.js +18 -4
package/README.md
CHANGED
|
@@ -75,8 +75,9 @@ await sw.addLayerConfig(new LayerConfig({
|
|
|
75
75
|
tileUrlTemplates: ['https://tile.openstreetmap.de/{z}/{x}/{y}.png'],
|
|
76
76
|
lineWidthStops: { 1: 0.5, 2: 0.6, 3: 0.7, 4: 1.0, 10: 3.75 },
|
|
77
77
|
lineStyles: [
|
|
78
|
-
|
|
79
|
-
{ color: 'rgb(
|
|
78
|
+
// layerSuffix determines which PMTiles layer to use
|
|
79
|
+
{ color: 'rgb(180, 200, 180)', layerSuffix: 'osm' },
|
|
80
|
+
{ color: 'rgb(121, 146, 127)', layerSuffix: 'osm', widthFraction: 1/3, dashArray: [30, 2, 8, 2] },
|
|
80
81
|
],
|
|
81
82
|
}));
|
|
82
83
|
```
|
|
@@ -126,7 +127,7 @@ importScripts('https://cdn.jsdelivr.net/npm/@india-boundary-corrector/service-wo
|
|
|
126
127
|
await sw.addLayerConfig(new LayerConfig({
|
|
127
128
|
id: 'my-tiles',
|
|
128
129
|
tileUrlTemplates: ['https://mytiles.example.com/{z}/{x}/{y}.png'],
|
|
129
|
-
lineStyles: [{ color: 'rgb(165, 180, 165)' }],
|
|
130
|
+
lineStyles: [{ color: 'rgb(165, 180, 165)', layerSuffix: 'osm' }],
|
|
130
131
|
}));
|
|
131
132
|
});
|
|
132
133
|
</script>
|
|
@@ -148,6 +149,18 @@ Register the service worker and wait for it to take control.
|
|
|
148
149
|
|
|
149
150
|
Returns: `Promise<CorrectionServiceWorker>`
|
|
150
151
|
|
|
152
|
+
#### PMTiles URL
|
|
153
|
+
|
|
154
|
+
**Important:** The service worker cannot auto-detect the PMTiles URL from `import.meta.url` or `document.currentScript` since it runs in a worker context. If you don't specify `pmtilesUrl`, it will default to fetching from the jsDelivr CDN.
|
|
155
|
+
|
|
156
|
+
For local development or self-hosted deployments, always specify the PMTiles URL:
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
const sw = await registerCorrectionServiceWorker('./sw.js', {
|
|
160
|
+
pmtilesUrl: '/path/to/india_boundary_corrections.pmtiles'
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
151
164
|
#### Development Mode
|
|
152
165
|
|
|
153
166
|
Use `forceReinstall: true` during development to ensure you always get a fresh service worker:
|
package/dist/index.global.js
CHANGED
|
@@ -33,7 +33,6 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
33
33
|
var configs_default = [
|
|
34
34
|
{
|
|
35
35
|
id: "cartodb-dark",
|
|
36
|
-
zoomThreshold: 5,
|
|
37
36
|
tileUrlTemplates: [
|
|
38
37
|
"https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
|
|
39
38
|
"https://basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
|
|
@@ -42,15 +41,17 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
42
41
|
"https://basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}{r}.png",
|
|
43
42
|
"https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_nolabels/{z}/{x}/{y}{r}.png"
|
|
44
43
|
],
|
|
45
|
-
lineWidthStops: { "1":
|
|
44
|
+
lineWidthStops: { "0": 1, "2": 1, "3": 1, "10": 2.5 },
|
|
46
45
|
lineStyles: [
|
|
47
|
-
{ color: "rgb(40, 40, 40)" }
|
|
46
|
+
{ color: "rgb(40, 40, 40)", layerSuffix: "ne", endZoom: 4 },
|
|
47
|
+
{ color: "rgb(40, 40, 40)", layerSuffix: "ne-disp", endZoom: 4 },
|
|
48
|
+
{ color: "rgb(40, 40, 40)", layerSuffix: "osm", startZoom: 5 },
|
|
49
|
+
{ color: "rgb(40, 40, 40)", layerSuffix: "osm-disp", startZoom: 5 },
|
|
50
|
+
{ color: "rgb(40, 40, 40)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.3, dashArray: [2, 2] }
|
|
48
51
|
]
|
|
49
52
|
},
|
|
50
53
|
{
|
|
51
54
|
id: "cartodb-light",
|
|
52
|
-
startZoom: 0,
|
|
53
|
-
zoomThreshold: 5,
|
|
54
55
|
tileUrlTemplates: [
|
|
55
56
|
"https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
|
|
56
57
|
"https://basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
|
|
@@ -65,56 +66,62 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
65
66
|
"https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png",
|
|
66
67
|
"https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png"
|
|
67
68
|
],
|
|
68
|
-
lineWidthStops: { "1": 0.
|
|
69
|
+
lineWidthStops: { "1": 0.5, "2": 0.5, "3": 0.5, "4": 1, "5": 1.25, "7": 1.5, "16": 2.5 },
|
|
69
70
|
lineStyles: [
|
|
70
|
-
{ color: "rgb(235, 214, 214)",
|
|
71
|
-
{ color: "rgb(235, 214, 214)" }
|
|
71
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "ne", endZoom: 4, lineExtensionFactor: 0.1, delWidthFactor: 2 },
|
|
72
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "ne-disp", endZoom: 4, lineExtensionFactor: 0 },
|
|
73
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "osm", alpha: 0.2, startZoom: 6, widthFraction: 3, lineExtensionFactor: 0.1 },
|
|
74
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "osm", startZoom: 5, lineExtensionFactor: 0.1 },
|
|
75
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", alpha: 0.2, startZoom: 6, widthFraction: 3, lineExtensionFactor: 0 },
|
|
76
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "osm-disp", startZoom: 5, lineExtensionFactor: 0 },
|
|
77
|
+
{ color: "rgb(235, 214, 214)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.75, dashArray: [2, 2], delWidthFactor: 2 }
|
|
72
78
|
]
|
|
73
79
|
},
|
|
74
80
|
{
|
|
75
81
|
id: "open-topo",
|
|
76
|
-
startZoom: 4,
|
|
77
|
-
zoomThreshold: 4,
|
|
78
82
|
tileUrlTemplates: [
|
|
79
83
|
"https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
|
|
80
84
|
"https://tile.opentopomap.org/{z}/{x}/{y}.png"
|
|
81
85
|
],
|
|
82
86
|
lineWidthStops: { "4": 0.75, "5": 1, "6": 1.25, "7": 1.5, "8": 1.75, "9": 1.25, "10": 1.25, "13": 1.5 },
|
|
83
87
|
lineStyles: [
|
|
84
|
-
{ color: "rgb(83, 83, 83)",
|
|
85
|
-
{ color: "rgb(
|
|
86
|
-
{ color: "rgb(
|
|
87
|
-
{ color: "rgb(
|
|
88
|
+
{ color: "rgb(83, 83, 83)", layerSuffix: "ne", startZoom: 4, endZoom: 6 },
|
|
89
|
+
{ color: "rgb(173, 173, 173)", layerSuffix: "osm", startZoom: 7, endZoom: 8, alpha: 0.5, widthFraction: 4 },
|
|
90
|
+
{ color: "rgb(83, 83, 83)", layerSuffix: "osm", startZoom: 7, endZoom: 8 },
|
|
91
|
+
{ color: "rgb(199, 158, 204)", layerSuffix: "osm", startZoom: 9, widthFraction: 7, alpha: 0.6, lineExtensionFactor: 0.2 },
|
|
92
|
+
{ color: "rgb(175, 41, 203)", layerSuffix: "osm", startZoom: 9, lineExtensionFactor: 0.2 }
|
|
88
93
|
]
|
|
89
94
|
},
|
|
90
95
|
{
|
|
91
96
|
id: "osm-carto",
|
|
92
|
-
startZoom: 1,
|
|
93
|
-
zoomThreshold: 1,
|
|
94
97
|
tileUrlTemplates: [
|
|
95
98
|
"https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
|
96
99
|
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
|
97
100
|
],
|
|
98
101
|
lineWidthStops: { "1": 0.5, "2": 0.6, "3": 0.7, "4": 1, "10": 3.75 },
|
|
99
102
|
lineStyles: [
|
|
100
|
-
{ color: "rgb(200, 180, 200)" },
|
|
101
|
-
{ color: "rgb(
|
|
103
|
+
{ color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 1, endZoom: 3, delWidthFactor: 2.5, widthFraction: 1.5 },
|
|
104
|
+
{ color: "rgb(200, 180, 200)", layerSuffix: "osm", startZoom: 4 },
|
|
105
|
+
{ color: "rgb(160, 120, 160)", layerSuffix: "osm", startZoom: 4, widthFraction: 0.333, dashArray: [30, 2, 8, 2] },
|
|
106
|
+
{ color: "rgb(200, 180, 200)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.45 },
|
|
107
|
+
{ color: "rgb(160, 120, 160)", layerSuffix: "osm-internal", startZoom: 4, widthFraction: 0.15, dashArray: [4, 2, 10] }
|
|
102
108
|
]
|
|
103
109
|
},
|
|
104
110
|
{
|
|
105
111
|
id: "osm-hot",
|
|
106
|
-
startZoom: 2,
|
|
107
|
-
zoomThreshold: 2,
|
|
108
112
|
tileUrlTemplates: [
|
|
109
|
-
"https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png"
|
|
113
|
+
"https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png",
|
|
114
|
+
"https://tile.openstreetmap.fr/hot/{z}/{x}/{y}.png"
|
|
110
115
|
],
|
|
111
116
|
lineWidthStops: { "2": 3, "3": 3, "7": 3, "8": 3.5, "9": 3.5 },
|
|
112
117
|
lineStyles: [
|
|
113
|
-
{ color: "rgb(149, 175, 180)" },
|
|
114
|
-
{ color: "rgb(89, 117, 123)", widthFraction: 0.33 }
|
|
118
|
+
{ color: "rgb(149, 175, 180)", layerSuffix: "osm", lineExtensionFactor: 0.25, startZoom: 2 },
|
|
119
|
+
{ color: "rgb(89, 117, 123)", layerSuffix: "osm", widthFraction: 0.33, lineExtensionFactor: 0.25, startZoom: 2 },
|
|
120
|
+
{ color: "rgb(172, 163, 163)", layerSuffix: "osm-internal", widthFraction: 0.33, startZoom: 4, dashArray: [7, 7, 7] }
|
|
115
121
|
]
|
|
116
122
|
}
|
|
117
123
|
];
|
|
124
|
+
var INFINITY = -1;
|
|
118
125
|
function templateToRegex(template) {
|
|
119
126
|
const groups = [];
|
|
120
127
|
let pattern = template.replace(/[.*+?^${}()|[\]\\]/g, (char) => {
|
|
@@ -152,89 +159,201 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
152
159
|
});
|
|
153
160
|
return new RegExp("^" + pattern + "(\\?.*)?$", "i");
|
|
154
161
|
}
|
|
162
|
+
function isValidColor(color) {
|
|
163
|
+
if (typeof color !== "string" || !color.trim()) return false;
|
|
164
|
+
if (typeof CSS !== "undefined" && CSS.supports) {
|
|
165
|
+
return CSS.supports("color", color);
|
|
166
|
+
}
|
|
167
|
+
const trimmed = color.trim().toLowerCase();
|
|
168
|
+
if (/^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/.test(trimmed)) return true;
|
|
169
|
+
if (/^(rgb|hsl)a?\(/.test(trimmed)) return true;
|
|
170
|
+
if (/^[a-z]+$/.test(trimmed)) return true;
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
var LineStyle = class _LineStyle {
|
|
174
|
+
/**
|
|
175
|
+
* Validate a LineStyle configuration object.
|
|
176
|
+
* @param {Object} obj - The object to validate
|
|
177
|
+
* @param {number} [index] - Optional index for error messages (when validating in an array)
|
|
178
|
+
* @throws {Error} If validation fails
|
|
179
|
+
*/
|
|
180
|
+
static validateJSON(obj, index) {
|
|
181
|
+
const prefix = index !== void 0 ? `lineStyles[${index}]` : "LineStyle";
|
|
182
|
+
if (!obj || typeof obj !== "object") {
|
|
183
|
+
throw new Error(`${prefix}: must be an object`);
|
|
184
|
+
}
|
|
185
|
+
if (!obj.color || typeof obj.color !== "string") {
|
|
186
|
+
throw new Error(`${prefix}: color must be a non-empty string`);
|
|
187
|
+
}
|
|
188
|
+
if (!isValidColor(obj.color)) {
|
|
189
|
+
throw new Error(`${prefix}: color "${obj.color}" is not a valid CSS color`);
|
|
190
|
+
}
|
|
191
|
+
if (!obj.layerSuffix || typeof obj.layerSuffix !== "string") {
|
|
192
|
+
throw new Error(`${prefix}: layerSuffix must be a non-empty string`);
|
|
193
|
+
}
|
|
194
|
+
if (obj.widthFraction !== void 0 && (typeof obj.widthFraction !== "number" || obj.widthFraction <= 0)) {
|
|
195
|
+
throw new Error(`${prefix}: widthFraction must be a positive number`);
|
|
196
|
+
}
|
|
197
|
+
if (obj.dashArray !== void 0 && !Array.isArray(obj.dashArray)) {
|
|
198
|
+
throw new Error(`${prefix}: dashArray must be an array`);
|
|
199
|
+
}
|
|
200
|
+
if (obj.alpha !== void 0 && (typeof obj.alpha !== "number" || obj.alpha < 0 || obj.alpha > 1)) {
|
|
201
|
+
throw new Error(`${prefix}: alpha must be a number between 0 and 1`);
|
|
202
|
+
}
|
|
203
|
+
if (obj.startZoom !== void 0 && (typeof obj.startZoom !== "number" || obj.startZoom < 0)) {
|
|
204
|
+
throw new Error(`${prefix}: startZoom must be a non-negative number`);
|
|
205
|
+
}
|
|
206
|
+
if (obj.endZoom !== void 0 && (typeof obj.endZoom !== "number" || obj.endZoom < 0 && obj.endZoom !== INFINITY)) {
|
|
207
|
+
throw new Error(`${prefix}: endZoom must be a non-negative number or INFINITY (${INFINITY})`);
|
|
208
|
+
}
|
|
209
|
+
if (obj.lineExtensionFactor !== void 0 && (typeof obj.lineExtensionFactor !== "number" || obj.lineExtensionFactor < 0)) {
|
|
210
|
+
throw new Error(`${prefix}: lineExtensionFactor must be a non-negative number`);
|
|
211
|
+
}
|
|
212
|
+
if (obj.delWidthFactor !== void 0 && (typeof obj.delWidthFactor !== "number" || obj.delWidthFactor < 0)) {
|
|
213
|
+
throw new Error(`${prefix}: delWidthFactor must be a non-negative number`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* @param {Object} options
|
|
218
|
+
* @param {string} options.color - CSS color string
|
|
219
|
+
* @param {string} options.layerSuffix - Layer suffix (e.g., 'osm', 'ne', 'osm-disp')
|
|
220
|
+
* @param {number} [options.widthFraction=1.0] - Multiplier for base line width
|
|
221
|
+
* @param {number[]} [options.dashArray] - Dash pattern for dashed lines
|
|
222
|
+
* @param {number} [options.alpha=1.0] - Opacity (0-1)
|
|
223
|
+
* @param {number} [options.startZoom=0] - Minimum zoom level for this style
|
|
224
|
+
* @param {number} [options.endZoom=INFINITY] - Maximum zoom level for this style (INFINITY means no limit)
|
|
225
|
+
* @param {number} [options.lineExtensionFactor=0.5] - Factor to extend lines by (multiplied by deletion line width)
|
|
226
|
+
* @param {number} [options.delWidthFactor=1.5] - Factor to multiply line width for deletion blur
|
|
227
|
+
*/
|
|
228
|
+
constructor({ color, layerSuffix, widthFraction = 1, dashArray, alpha = 1, startZoom = 0, endZoom = INFINITY, lineExtensionFactor = 0.5, delWidthFactor = 1.5 }) {
|
|
229
|
+
this.color = color;
|
|
230
|
+
this.layerSuffix = layerSuffix;
|
|
231
|
+
this.widthFraction = widthFraction;
|
|
232
|
+
this.dashArray = dashArray;
|
|
233
|
+
this.alpha = alpha;
|
|
234
|
+
this.startZoom = startZoom;
|
|
235
|
+
this.endZoom = endZoom;
|
|
236
|
+
this.lineExtensionFactor = lineExtensionFactor;
|
|
237
|
+
this.delWidthFactor = delWidthFactor;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Check if this style is active at the given zoom level.
|
|
241
|
+
* @param {number} z - Zoom level
|
|
242
|
+
* @returns {boolean}
|
|
243
|
+
*/
|
|
244
|
+
isActiveAtZoom(z) {
|
|
245
|
+
return z >= this.startZoom && (this.endZoom === INFINITY || z <= this.endZoom);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Serialize to plain object.
|
|
249
|
+
* @returns {Object}
|
|
250
|
+
*/
|
|
251
|
+
toJSON() {
|
|
252
|
+
return {
|
|
253
|
+
color: this.color,
|
|
254
|
+
layerSuffix: this.layerSuffix,
|
|
255
|
+
widthFraction: this.widthFraction,
|
|
256
|
+
dashArray: this.dashArray,
|
|
257
|
+
alpha: this.alpha,
|
|
258
|
+
startZoom: this.startZoom,
|
|
259
|
+
endZoom: this.endZoom,
|
|
260
|
+
lineExtensionFactor: this.lineExtensionFactor,
|
|
261
|
+
delWidthFactor: this.delWidthFactor
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Create from plain object with validation.
|
|
266
|
+
* @param {Object} obj
|
|
267
|
+
* @param {number} [index] - Optional index for error messages
|
|
268
|
+
* @returns {LineStyle}
|
|
269
|
+
*/
|
|
270
|
+
static fromJSON(obj, index) {
|
|
271
|
+
_LineStyle.validateJSON(obj, index);
|
|
272
|
+
return new _LineStyle(obj);
|
|
273
|
+
}
|
|
274
|
+
};
|
|
155
275
|
var LayerConfig = class _LayerConfig {
|
|
276
|
+
/**
|
|
277
|
+
* Validate a LayerConfig configuration object.
|
|
278
|
+
* Also validates all lineStyles within the config.
|
|
279
|
+
* @param {Object} obj - The object to validate
|
|
280
|
+
* @throws {Error} If validation fails
|
|
281
|
+
*/
|
|
282
|
+
static validateJSON(obj) {
|
|
283
|
+
if (!obj || typeof obj !== "object") {
|
|
284
|
+
throw new Error("LayerConfig: must be an object");
|
|
285
|
+
}
|
|
286
|
+
if (!obj.id || typeof obj.id !== "string") {
|
|
287
|
+
throw new Error("LayerConfig: id must be a non-empty string");
|
|
288
|
+
}
|
|
289
|
+
if (obj.id.includes("/")) {
|
|
290
|
+
throw new Error(`LayerConfig: id cannot contain slashes: "${obj.id}"`);
|
|
291
|
+
}
|
|
292
|
+
const id = obj.id;
|
|
293
|
+
if (obj.lineWidthStops !== void 0) {
|
|
294
|
+
if (!obj.lineWidthStops || typeof obj.lineWidthStops !== "object" || Array.isArray(obj.lineWidthStops)) {
|
|
295
|
+
throw new Error(`LayerConfig "${id}": lineWidthStops must be an object`);
|
|
296
|
+
}
|
|
297
|
+
const stopKeys = Object.keys(obj.lineWidthStops);
|
|
298
|
+
if (stopKeys.length < 2) {
|
|
299
|
+
throw new Error(`LayerConfig "${id}": lineWidthStops must have at least 2 entries`);
|
|
300
|
+
}
|
|
301
|
+
for (const key of stopKeys) {
|
|
302
|
+
const zoom = Number(key);
|
|
303
|
+
if (!Number.isInteger(zoom) || zoom < 0) {
|
|
304
|
+
throw new Error(`LayerConfig "${id}": lineWidthStops keys must be non-negative integers, got "${key}"`);
|
|
305
|
+
}
|
|
306
|
+
if (typeof obj.lineWidthStops[key] !== "number" || obj.lineWidthStops[key] <= 0) {
|
|
307
|
+
throw new Error(`LayerConfig "${id}": lineWidthStops values must be positive numbers`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (!Array.isArray(obj.lineStyles) || obj.lineStyles.length === 0) {
|
|
312
|
+
throw new Error(`LayerConfig "${id}": lineStyles must be a non-empty array`);
|
|
313
|
+
}
|
|
314
|
+
for (let i = 0; i < obj.lineStyles.length; i++) {
|
|
315
|
+
LineStyle.validateJSON(obj.lineStyles[i], i);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
156
318
|
constructor({
|
|
157
319
|
id,
|
|
158
|
-
startZoom = 0,
|
|
159
|
-
zoomThreshold = 5,
|
|
160
320
|
// Tile URL templates for matching (e.g., "https://{s}.tile.example.com/{z}/{x}/{y}.png")
|
|
161
321
|
tileUrlTemplates = [],
|
|
162
322
|
// Line width stops: map of zoom level to line width (at least 2 entries)
|
|
163
323
|
// Note: interpolated/extrapolated line width is capped at a minimum of 0.5
|
|
164
324
|
lineWidthStops = { 1: 0.5, 10: 2.5 },
|
|
165
|
-
// Line styles array - each element describes a line to draw
|
|
166
|
-
// { color: string, widthFraction?: number, dashArray?: number[],
|
|
167
|
-
//
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
// Higher values leave gaps where wiped lines meet existing lines
|
|
171
|
-
// Lower values mean wiped lines show through
|
|
172
|
-
delWidthFactor = 1.5,
|
|
173
|
-
// Factor to extend add lines by (multiplied by deletion line width)
|
|
174
|
-
// Helps cover gaps where deleted lines meet the new boundary
|
|
175
|
-
// Set to 0 to disable extension
|
|
176
|
-
lineExtensionFactor = 0.5
|
|
325
|
+
// Line styles array - each element describes a line to draw from a specific layer
|
|
326
|
+
// { color: string, layerSuffix: string, widthFraction?: number, dashArray?: number[],
|
|
327
|
+
// startZoom?: number, endZoom?: number, lineExtensionFactor?: number, delWidthFactor?: number }
|
|
328
|
+
// Lines are drawn in array order. layerSuffix determines which PMTiles layer to use.
|
|
329
|
+
lineStyles
|
|
177
330
|
}) {
|
|
178
|
-
if (!id || typeof id !== "string") {
|
|
179
|
-
throw new Error("LayerConfig requires a non-empty string id");
|
|
180
|
-
}
|
|
181
|
-
if (id.includes("/")) {
|
|
182
|
-
throw new Error(`LayerConfig id cannot contain slashes: "${id}"`);
|
|
183
|
-
}
|
|
184
331
|
this.id = id;
|
|
185
|
-
this.startZoom = startZoom;
|
|
186
|
-
this.zoomThreshold = zoomThreshold;
|
|
187
|
-
if (startZoom > zoomThreshold) {
|
|
188
|
-
throw new Error(`LayerConfig "${id}": startZoom (${startZoom}) must be <= zoomThreshold (${zoomThreshold})`);
|
|
189
|
-
}
|
|
190
332
|
const templates = Array.isArray(tileUrlTemplates) ? tileUrlTemplates : tileUrlTemplates ? [tileUrlTemplates] : [];
|
|
191
333
|
this.tileUrlTemplates = templates;
|
|
192
334
|
this._compiledPatterns = templates.map((t) => templateToRegex(t));
|
|
193
335
|
this._templatePatterns = templates.map((t) => templateToTemplateRegex(t));
|
|
194
|
-
if (!lineWidthStops || typeof lineWidthStops !== "object" || Array.isArray(lineWidthStops)) {
|
|
195
|
-
throw new Error(`LayerConfig "${id}": lineWidthStops must be an object`);
|
|
196
|
-
}
|
|
197
|
-
const stopKeys = Object.keys(lineWidthStops);
|
|
198
|
-
if (stopKeys.length < 2) {
|
|
199
|
-
throw new Error(`LayerConfig "${id}": lineWidthStops must have at least 2 entries`);
|
|
200
|
-
}
|
|
201
|
-
for (const key of stopKeys) {
|
|
202
|
-
const zoom = Number(key);
|
|
203
|
-
if (!Number.isInteger(zoom) || zoom < 0) {
|
|
204
|
-
throw new Error(`LayerConfig "${id}": lineWidthStops keys must be non-negative integers, got "${key}"`);
|
|
205
|
-
}
|
|
206
|
-
if (typeof lineWidthStops[key] !== "number" || lineWidthStops[key] <= 0) {
|
|
207
|
-
throw new Error(`LayerConfig "${id}": lineWidthStops values must be positive numbers`);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
336
|
this.lineWidthStops = lineWidthStops;
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
for (let i = 0; i < lineStyles.length; i++) {
|
|
215
|
-
const style = lineStyles[i];
|
|
216
|
-
if (!style || typeof style !== "object") {
|
|
217
|
-
throw new Error(`LayerConfig "${id}": lineStyles[${i}] must be an object`);
|
|
218
|
-
}
|
|
219
|
-
if (!style.color || typeof style.color !== "string") {
|
|
220
|
-
throw new Error(`LayerConfig "${id}": lineStyles[${i}].color must be a non-empty string`);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
this.lineStyles = lineStyles.map((style) => ({
|
|
224
|
-
...style,
|
|
225
|
-
startZoom: style.startZoom ?? startZoom,
|
|
226
|
-
endZoom: style.endZoom ?? Infinity
|
|
227
|
-
}));
|
|
228
|
-
this.delWidthFactor = delWidthFactor;
|
|
229
|
-
this.lineExtensionFactor = lineExtensionFactor;
|
|
337
|
+
this.lineStyles = lineStyles.map(
|
|
338
|
+
(style) => style instanceof LineStyle ? style : new LineStyle(style)
|
|
339
|
+
);
|
|
230
340
|
}
|
|
231
341
|
/**
|
|
232
342
|
* Get line styles active at a given zoom level
|
|
233
343
|
* @param {number} z - Zoom level
|
|
234
|
-
* @returns {
|
|
344
|
+
* @returns {LineStyle[]}
|
|
235
345
|
*/
|
|
236
346
|
getLineStylesForZoom(z) {
|
|
237
|
-
return this.lineStyles.filter((style) =>
|
|
347
|
+
return this.lineStyles.filter((style) => style.isActiveAtZoom(z));
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Get unique layer suffixes from styles active at a given zoom level
|
|
351
|
+
* @param {number} z - Zoom level
|
|
352
|
+
* @returns {string[]}
|
|
353
|
+
*/
|
|
354
|
+
getLayerSuffixesForZoom(z) {
|
|
355
|
+
const activeStyles = this.getLineStylesForZoom(z);
|
|
356
|
+
return [...new Set(activeStyles.map((s) => s.layerSuffix))];
|
|
238
357
|
}
|
|
239
358
|
/**
|
|
240
359
|
* Check if this config matches the given template URLs (with {z}/{x}/{y} placeholders)
|
|
@@ -293,21 +412,19 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
293
412
|
toJSON() {
|
|
294
413
|
return {
|
|
295
414
|
id: this.id,
|
|
296
|
-
startZoom: this.startZoom,
|
|
297
|
-
zoomThreshold: this.zoomThreshold,
|
|
298
415
|
tileUrlTemplates: this.tileUrlTemplates,
|
|
299
416
|
lineWidthStops: this.lineWidthStops,
|
|
300
|
-
lineStyles: this.lineStyles
|
|
301
|
-
delWidthFactor: this.delWidthFactor,
|
|
302
|
-
lineExtensionFactor: this.lineExtensionFactor
|
|
417
|
+
lineStyles: this.lineStyles.map((s) => s.toJSON())
|
|
303
418
|
};
|
|
304
419
|
}
|
|
305
420
|
/**
|
|
306
|
-
* Create a LayerConfig from a plain object
|
|
421
|
+
* Create a LayerConfig from a plain object with validation.
|
|
307
422
|
* @param {Object} obj
|
|
308
423
|
* @returns {LayerConfig}
|
|
424
|
+
* @throws {Error} If validation fails
|
|
309
425
|
*/
|
|
310
426
|
static fromJSON(obj) {
|
|
427
|
+
_LayerConfig.validateJSON(obj);
|
|
311
428
|
return new _LayerConfig(obj);
|
|
312
429
|
}
|
|
313
430
|
};
|
|
@@ -403,13 +520,13 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
403
520
|
}
|
|
404
521
|
|
|
405
522
|
// ../data/version.js
|
|
406
|
-
var packageVersion = "0.0
|
|
523
|
+
var packageVersion = "0.1.0";
|
|
407
524
|
|
|
408
525
|
// ../data/index.js
|
|
409
526
|
var import_meta = {};
|
|
410
527
|
var PACKAGE_NAME = "@india-boundary-corrector/data";
|
|
411
|
-
var PMTILES_FILENAME = "india_boundary_corrections.pmtiles";
|
|
412
|
-
var FALLBACK_CDNS = /* @__PURE__ */ new Set(["esm.sh", "skypack.dev", "cdn.skypack.dev"
|
|
528
|
+
var PMTILES_FILENAME = "india_boundary_corrections.pmtiles.gz";
|
|
529
|
+
var FALLBACK_CDNS = /* @__PURE__ */ new Set(["esm.sh", "skypack.dev", "cdn.skypack.dev"]);
|
|
413
530
|
var DEFAULT_CDN_URL = `https://cdn.jsdelivr.net/npm/${PACKAGE_NAME}@${packageVersion}/${PMTILES_FILENAME}`;
|
|
414
531
|
var CURRENT_SCRIPT_URL = typeof document !== "undefined" && document.currentScript && document.currentScript.src || null;
|
|
415
532
|
function detectPmtilesUrl() {
|
|
@@ -424,14 +541,17 @@ var IndiaBoundaryCorrector = (() => {
|
|
|
424
541
|
scriptUrl = CURRENT_SCRIPT_URL;
|
|
425
542
|
}
|
|
426
543
|
if (scriptUrl) {
|
|
427
|
-
|
|
428
|
-
if (FALLBACK_CDNS.has(moduleUrl.hostname)) {
|
|
429
|
-
return DEFAULT_CDN_URL;
|
|
430
|
-
}
|
|
431
|
-
return new URL(PMTILES_FILENAME, moduleUrl).href;
|
|
544
|
+
return resolvePmtilesUrl(scriptUrl);
|
|
432
545
|
}
|
|
433
546
|
return DEFAULT_CDN_URL;
|
|
434
547
|
}
|
|
548
|
+
function resolvePmtilesUrl(scriptUrl) {
|
|
549
|
+
const moduleUrl = new URL(".", scriptUrl);
|
|
550
|
+
if (FALLBACK_CDNS.has(moduleUrl.hostname)) {
|
|
551
|
+
return DEFAULT_CDN_URL;
|
|
552
|
+
}
|
|
553
|
+
return new URL(PMTILES_FILENAME, moduleUrl).href;
|
|
554
|
+
}
|
|
435
555
|
var cachedPmtilesUrl = null;
|
|
436
556
|
function getPmtilesUrl() {
|
|
437
557
|
if (cachedPmtilesUrl === null) {
|