@india-boundary-corrector/layer-configs 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,378 @@
1
+ // src/configs.json
2
+ var configs_default = [
3
+ {
4
+ id: "cartodb-dark",
5
+ zoomThreshold: 5,
6
+ tileUrlTemplates: [
7
+ "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
8
+ "https://basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
9
+ "https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}{r}.png",
10
+ "https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}{r}.png",
11
+ "https://basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}{r}.png",
12
+ "https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_nolabels/{z}/{x}/{y}{r}.png"
13
+ ],
14
+ lineWidthStops: { "1": 0.5, "10": 2.5 },
15
+ lineStyles: [
16
+ { color: "rgb(40, 40, 40)" }
17
+ ]
18
+ },
19
+ {
20
+ id: "cartodb-light",
21
+ startZoom: 0,
22
+ zoomThreshold: 5,
23
+ tileUrlTemplates: [
24
+ "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
25
+ "https://basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
26
+ "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}{r}.png",
27
+ "https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png",
28
+ "https://basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png",
29
+ "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_nolabels/{z}/{x}/{y}{r}.png",
30
+ "https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
31
+ "https://basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
32
+ "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}{r}.png",
33
+ "https://basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}{r}.png",
34
+ "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png",
35
+ "https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png"
36
+ ],
37
+ lineWidthStops: { "1": 0.25, "2": 0.25, "3": 0.5, "4": 0.75, "5": 1 },
38
+ lineStyles: [
39
+ { color: "rgb(235, 214, 214)", alpha: 0.2, startZoom: 6, widthFraction: 5 },
40
+ { color: "rgb(235, 214, 214)" }
41
+ ]
42
+ },
43
+ {
44
+ id: "open-topo",
45
+ startZoom: 4,
46
+ zoomThreshold: 4,
47
+ tileUrlTemplates: [
48
+ "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
49
+ "https://tile.opentopomap.org/{z}/{x}/{y}.png"
50
+ ],
51
+ lineWidthStops: { "4": 0.75, "5": 1, "6": 1.25, "7": 1.5, "8": 1.75, "9": 1.25, "10": 1.25, "13": 1.5 },
52
+ lineStyles: [
53
+ { color: "rgb(83, 83, 83)", startZoom: 7, endZoom: 8, alpha: 0.4, widthFraction: 4 },
54
+ { color: "rgb(83, 83, 83)", endZoom: 8 },
55
+ { color: "rgb(140, 20, 180)", startZoom: 9, widthFraction: 9, alpha: 0.2 },
56
+ { color: "rgb(140, 20, 180)", startZoom: 9 }
57
+ ]
58
+ },
59
+ {
60
+ id: "osm-carto",
61
+ startZoom: 1,
62
+ zoomThreshold: 1,
63
+ tileUrlTemplates: [
64
+ "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
65
+ "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
66
+ ],
67
+ lineWidthStops: { "1": 0.5, "2": 0.6, "3": 0.7, "4": 1, "10": 3.75 },
68
+ lineStyles: [
69
+ { color: "rgb(200, 180, 200)" },
70
+ { color: "rgb(160, 120, 160)", widthFraction: 0.333, dashArray: [30, 2, 8, 2] }
71
+ ]
72
+ },
73
+ {
74
+ id: "osm-hot",
75
+ startZoom: 2,
76
+ zoomThreshold: 2,
77
+ tileUrlTemplates: [
78
+ "https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png"
79
+ ],
80
+ lineWidthStops: { "2": 3, "3": 3, "7": 3, "8": 3.5, "9": 3.5 },
81
+ lineStyles: [
82
+ { color: "rgb(149, 175, 180)" },
83
+ { color: "rgb(89, 117, 123)", widthFraction: 0.33 }
84
+ ]
85
+ }
86
+ ];
87
+
88
+ // src/layerconfig.js
89
+ function templateToRegex(template) {
90
+ const groups = [];
91
+ let pattern = template.replace(/[.*+?^${}()|[\]\\]/g, (char) => {
92
+ if (char === "{" || char === "}") return char;
93
+ return "\\" + char;
94
+ }).replace(/^https:\/\//, "https?://").replace(/^http:\/\//, "https?://").replace(/\{[a-z0-9]-[a-z0-9]\}/gi, () => {
95
+ groups.push("s");
96
+ return "([a-z0-9]+)";
97
+ }).replace(/\{(z|x|y|s|r)\}/gi, (_, name) => {
98
+ const lowerName = name.toLowerCase();
99
+ groups.push(lowerName);
100
+ if (lowerName === "s") {
101
+ return "([a-z0-9]+)";
102
+ }
103
+ if (lowerName === "r") {
104
+ return "(@\\d+x)?";
105
+ }
106
+ return "(\\d+)";
107
+ });
108
+ return { pattern: new RegExp("^" + pattern + "(\\?.*)?$", "i"), groups };
109
+ }
110
+ function templateToTemplateRegex(template) {
111
+ let pattern = template.replace(/[.*+?^${}()|[\]\\]/g, (char) => {
112
+ if (char === "{" || char === "}") return char;
113
+ return "\\" + char;
114
+ }).replace(/^https:\/\//, "https?://").replace(/^http:\/\//, "https?://").replace(/\{([a-z0-9])-([a-z0-9])\}/gi, (_, start, end) => `(\\{${start}-${end}\\}|[a-z0-9]+)`).replace(/\{(z|x|y|s|r)\}/gi, (_, name) => {
115
+ const lowerName = name.toLowerCase();
116
+ if (lowerName === "s") {
117
+ return "(\\{s\\}|[a-z0-9]+)";
118
+ }
119
+ if (lowerName === "r") {
120
+ return "(\\{r\\}|@\\d+x)?";
121
+ }
122
+ return `\\{${lowerName}\\}`;
123
+ });
124
+ return new RegExp("^" + pattern + "(\\?.*)?$", "i");
125
+ }
126
+ var LayerConfig = class _LayerConfig {
127
+ constructor({
128
+ id,
129
+ startZoom = 0,
130
+ zoomThreshold = 5,
131
+ // Tile URL templates for matching (e.g., "https://{s}.tile.example.com/{z}/{x}/{y}.png")
132
+ tileUrlTemplates = [],
133
+ // Line width stops: map of zoom level to line width (at least 2 entries)
134
+ lineWidthStops = { 1: 0.5, 10: 2.5 },
135
+ // Line styles array - each element describes a line to draw
136
+ // { color: string, widthFraction?: number, dashArray?: number[], startZoom?: number, endZoom?: number }
137
+ // Lines are drawn in array order. startZoom defaults to layerConfig startZoom, endZoom defaults to Infinity
138
+ lineStyles = [{ color: "green", widthFraction: 1 }],
139
+ // Factor to multiply line width for deletion blur (default 1.5)
140
+ // Higher values leave gaps where wiped lines meet existing lines
141
+ // Lower values mean wiped lines show through
142
+ delWidthFactor = 1.5,
143
+ // Factor to extend add lines by (multiplied by deletion line width)
144
+ // Helps cover gaps where deleted lines meet the new boundary
145
+ // Set to 0 to disable extension
146
+ lineExtensionFactor = 0.5
147
+ }) {
148
+ if (!id || typeof id !== "string") {
149
+ throw new Error("LayerConfig requires a non-empty string id");
150
+ }
151
+ this.id = id;
152
+ this.startZoom = startZoom;
153
+ this.zoomThreshold = zoomThreshold;
154
+ if (startZoom > zoomThreshold) {
155
+ throw new Error(`LayerConfig "${id}": startZoom (${startZoom}) must be <= zoomThreshold (${zoomThreshold})`);
156
+ }
157
+ const templates = Array.isArray(tileUrlTemplates) ? tileUrlTemplates : tileUrlTemplates ? [tileUrlTemplates] : [];
158
+ this.tileUrlTemplates = templates;
159
+ this._compiledPatterns = templates.map((t) => templateToRegex(t));
160
+ this._templatePatterns = templates.map((t) => templateToTemplateRegex(t));
161
+ if (!lineWidthStops || typeof lineWidthStops !== "object" || Array.isArray(lineWidthStops)) {
162
+ throw new Error(`LayerConfig "${id}": lineWidthStops must be an object`);
163
+ }
164
+ const stopKeys = Object.keys(lineWidthStops);
165
+ if (stopKeys.length < 2) {
166
+ throw new Error(`LayerConfig "${id}": lineWidthStops must have at least 2 entries`);
167
+ }
168
+ for (const key of stopKeys) {
169
+ const zoom = Number(key);
170
+ if (!Number.isInteger(zoom) || zoom < 0) {
171
+ throw new Error(`LayerConfig "${id}": lineWidthStops keys must be non-negative integers, got "${key}"`);
172
+ }
173
+ if (typeof lineWidthStops[key] !== "number" || lineWidthStops[key] <= 0) {
174
+ throw new Error(`LayerConfig "${id}": lineWidthStops values must be positive numbers`);
175
+ }
176
+ }
177
+ this.lineWidthStops = lineWidthStops;
178
+ if (!Array.isArray(lineStyles) || lineStyles.length === 0) {
179
+ throw new Error(`LayerConfig "${id}": lineStyles must be a non-empty array`);
180
+ }
181
+ for (let i = 0; i < lineStyles.length; i++) {
182
+ const style = lineStyles[i];
183
+ if (!style || typeof style !== "object") {
184
+ throw new Error(`LayerConfig "${id}": lineStyles[${i}] must be an object`);
185
+ }
186
+ if (!style.color || typeof style.color !== "string") {
187
+ throw new Error(`LayerConfig "${id}": lineStyles[${i}].color must be a non-empty string`);
188
+ }
189
+ }
190
+ this.lineStyles = lineStyles.map((style) => ({
191
+ ...style,
192
+ startZoom: style.startZoom ?? startZoom,
193
+ endZoom: style.endZoom ?? Infinity
194
+ }));
195
+ this.delWidthFactor = delWidthFactor;
196
+ this.lineExtensionFactor = lineExtensionFactor;
197
+ }
198
+ /**
199
+ * Get line styles active at a given zoom level
200
+ * @param {number} z - Zoom level
201
+ * @returns {Array<{color: string, widthFraction?: number, dashArray?: number[]}>}
202
+ */
203
+ getLineStylesForZoom(z) {
204
+ return this.lineStyles.filter((style) => z >= style.startZoom && z <= style.endZoom);
205
+ }
206
+ /**
207
+ * Check if this config matches the given template URLs (with {z}/{x}/{y} placeholders)
208
+ * @param {string | string[]} templates - Single template URL or array of template URLs
209
+ * @returns {boolean}
210
+ */
211
+ matchTemplate(templates) {
212
+ if (this._templatePatterns.length === 0) return false;
213
+ const urls = Array.isArray(templates) ? templates : [templates];
214
+ if (urls.length === 0) return false;
215
+ return urls.some(
216
+ (url) => this._templatePatterns.some((pattern) => pattern.test(url))
217
+ );
218
+ }
219
+ /**
220
+ * Check if this config matches the given tile URLs (with actual coordinates)
221
+ * @param {string | string[]} tiles - Single tile URL or array of tile URLs
222
+ * @returns {boolean}
223
+ */
224
+ matchTileUrl(tiles) {
225
+ if (this._compiledPatterns.length === 0) return false;
226
+ const urls = Array.isArray(tiles) ? tiles : [tiles];
227
+ if (urls.length === 0) return false;
228
+ return urls.some(
229
+ (url) => this._compiledPatterns.some(({ pattern }) => pattern.test(url))
230
+ );
231
+ }
232
+ /**
233
+ * Extract tile coordinates (z, x, y) from a URL using this config's templates
234
+ * @param {string} url - Tile URL to extract coordinates from
235
+ * @returns {{ z: number, x: number, y: number } | null}
236
+ */
237
+ extractCoords(url) {
238
+ for (const { pattern, groups } of this._compiledPatterns) {
239
+ const match = url.match(pattern);
240
+ if (match) {
241
+ const result = {};
242
+ for (let i = 0; i < groups.length; i++) {
243
+ const name = groups[i];
244
+ const value = match[i + 1];
245
+ if (name === "z" || name === "x" || name === "y") {
246
+ result[name] = parseInt(value, 10);
247
+ }
248
+ }
249
+ if ("z" in result && "x" in result && "y" in result) {
250
+ return { z: result.z, x: result.x, y: result.y };
251
+ }
252
+ }
253
+ }
254
+ return null;
255
+ }
256
+ /**
257
+ * Serialize the config to a plain object for postMessage
258
+ * @returns {Object}
259
+ */
260
+ toJSON() {
261
+ return {
262
+ id: this.id,
263
+ startZoom: this.startZoom,
264
+ zoomThreshold: this.zoomThreshold,
265
+ tileUrlTemplates: this.tileUrlTemplates,
266
+ lineWidthStops: this.lineWidthStops,
267
+ lineStyles: this.lineStyles,
268
+ delWidthFactor: this.delWidthFactor,
269
+ lineExtensionFactor: this.lineExtensionFactor
270
+ };
271
+ }
272
+ /**
273
+ * Create a LayerConfig from a plain object (e.g., from postMessage)
274
+ * @param {Object} obj
275
+ * @returns {LayerConfig}
276
+ */
277
+ static fromJSON(obj) {
278
+ return new _LayerConfig(obj);
279
+ }
280
+ };
281
+
282
+ // src/index.js
283
+ var LayerConfigRegistry = class _LayerConfigRegistry {
284
+ constructor() {
285
+ this.registry = {};
286
+ }
287
+ /**
288
+ * Get a layer config by id
289
+ */
290
+ get(id) {
291
+ return this.registry[id];
292
+ }
293
+ /**
294
+ * Register a new layer config
295
+ */
296
+ register(config) {
297
+ this.registry[config.id] = config;
298
+ }
299
+ /**
300
+ * Remove a layer config by id
301
+ */
302
+ remove(id) {
303
+ if (!this.registry[id]) return false;
304
+ delete this.registry[id];
305
+ return true;
306
+ }
307
+ /**
308
+ * Detect layer config from tile URL templates (with {z}/{x}/{y} placeholders)
309
+ * @param {string | string[]} templates - Single template URL or array of template URLs
310
+ */
311
+ detectFromTemplates(templates) {
312
+ if (!templates || Array.isArray(templates) && templates.length === 0) return void 0;
313
+ for (const config of Object.values(this.registry)) {
314
+ if (config.matchTemplate(templates)) {
315
+ return config;
316
+ }
317
+ }
318
+ return void 0;
319
+ }
320
+ /**
321
+ * Detect layer config from actual tile URLs (with numeric coordinates)
322
+ * @param {string | string[]} urls - Single tile URL or array of tile URLs
323
+ */
324
+ detectFromTileUrls(urls) {
325
+ if (!urls || Array.isArray(urls) && urls.length === 0) return void 0;
326
+ for (const config of Object.values(this.registry)) {
327
+ if (config.matchTileUrl(urls)) {
328
+ return config;
329
+ }
330
+ }
331
+ return void 0;
332
+ }
333
+ /**
334
+ * Get all available layer config ids
335
+ */
336
+ getAvailableIds() {
337
+ return Object.keys(this.registry);
338
+ }
339
+ /**
340
+ * Create a new registry with all configs from this registry plus extra configs.
341
+ * @param {LayerConfig[]} extraLayerConfigs - Additional configs to add
342
+ * @returns {LayerConfigRegistry} A new registry with merged configs
343
+ */
344
+ createMergedRegistry(extraLayerConfigs) {
345
+ const registry = new _LayerConfigRegistry();
346
+ for (const id of this.getAvailableIds()) {
347
+ registry.register(this.get(id));
348
+ }
349
+ if (extraLayerConfigs && extraLayerConfigs.length > 0) {
350
+ for (const config of extraLayerConfigs) {
351
+ registry.register(config);
352
+ }
353
+ }
354
+ return registry;
355
+ }
356
+ /**
357
+ * Parse a tile URL into its components: layer config and coordinates
358
+ * @param {string} url - Tile URL to parse
359
+ * @returns {{ layerConfig: LayerConfig, coords: { z: number, x: number, y: number } } | null}
360
+ */
361
+ parseTileUrl(url) {
362
+ const layerConfig = this.detectFromTileUrls([url]);
363
+ if (!layerConfig) return null;
364
+ const coords = layerConfig.extractCoords(url);
365
+ if (!coords) return null;
366
+ return { layerConfig, coords };
367
+ }
368
+ };
369
+ var layerConfigs = new LayerConfigRegistry();
370
+ for (const configData of configs_default) {
371
+ layerConfigs.register(new LayerConfig(configData));
372
+ }
373
+ export {
374
+ LayerConfig,
375
+ LayerConfigRegistry,
376
+ layerConfigs
377
+ };
378
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/configs.json","../src/layerconfig.js","../src/index.js"],"sourcesContent":["[\n {\n \"id\": \"cartodb-dark\",\n \"zoomThreshold\": 5,\n \"tileUrlTemplates\": [\n \"https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png\",\n \"https://basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png\",\n \"https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}{r}.png\",\n \"https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}{r}.png\",\n \"https://basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}{r}.png\",\n \"https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_nolabels/{z}/{x}/{y}{r}.png\"\n ],\n \"lineWidthStops\": { \"1\": 0.5, \"10\": 2.5 },\n \"lineStyles\": [\n { \"color\": \"rgb(40, 40, 40)\" }\n ]\n },\n {\n \"id\": \"cartodb-light\",\n \"startZoom\": 0,\n \"zoomThreshold\": 5,\n \"tileUrlTemplates\": [\n \"https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png\",\n \"https://basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png\",\n \"https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}{r}.png\",\n \"https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png\",\n \"https://basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png\",\n \"https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_nolabels/{z}/{x}/{y}{r}.png\",\n \"https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png\",\n \"https://basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png\",\n \"https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}{r}.png\",\n \"https://basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}{r}.png\",\n \"https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png\",\n \"https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png\"\n ],\n \"lineWidthStops\": { \"1\": 0.25, \"2\": 0.25, \"3\": 0.5, \"4\": 0.75, \"5\": 1.0 },\n \"lineStyles\": [\n { \"color\": \"rgb(235, 214, 214)\", \"alpha\": 0.2, \"startZoom\": 6, \"widthFraction\": 5 },\n { \"color\": \"rgb(235, 214, 214)\" }\n ]\n },\n {\n \"id\": \"open-topo\",\n \"startZoom\": 4,\n \"zoomThreshold\": 4,\n \"tileUrlTemplates\": [\n \"https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png\",\n \"https://tile.opentopomap.org/{z}/{x}/{y}.png\"\n ],\n \"lineWidthStops\": { \"4\": 0.75, \"5\": 1.0, \"6\": 1.25, \"7\": 1.5, \"8\": 1.75, \"9\": 1.25, \"10\": 1.25, \"13\": 1.5 },\n \"lineStyles\": [\n { \"color\": \"rgb(83, 83, 83)\", \"startZoom\": 7, \"endZoom\": 8, \"alpha\": 0.4, \"widthFraction\": 4 },\n { \"color\": \"rgb(83, 83, 83)\", \"endZoom\": 8 },\n { \"color\": \"rgb(140, 20, 180)\", \"startZoom\": 9, \"widthFraction\": 9, \"alpha\": 0.2 },\n { \"color\": \"rgb(140, 20, 180)\", \"startZoom\": 9 }\n ]\n },\n {\n \"id\": \"osm-carto\",\n \"startZoom\": 1,\n \"zoomThreshold\": 1,\n \"tileUrlTemplates\": [\n \"https://tile.openstreetmap.org/{z}/{x}/{y}.png\",\n \"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\"\n ],\n \"lineWidthStops\": { \"1\": 0.5, \"2\": 0.6, \"3\": 0.7, \"4\": 1.0, \"10\": 3.75 },\n \"lineStyles\": [\n { \"color\": \"rgb(200, 180, 200)\" },\n { \"color\": \"rgb(160, 120, 160)\", \"widthFraction\": 0.333, \"dashArray\": [30, 2, 8, 2] }\n ]\n },\n {\n \"id\": \"osm-hot\",\n \"startZoom\": 2,\n \"zoomThreshold\": 2,\n \"tileUrlTemplates\": [\n \"https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png\"\n ],\n \"lineWidthStops\": { \"2\": 3.0, \"3\": 3.0, \"7\": 3.0, \"8\": 3.5, \"9\": 3.5 },\n \"lineStyles\": [\n { \"color\": \"rgb(149, 175, 180)\" },\n { \"color\": \"rgb(89, 117, 123)\", \"widthFraction\": 0.33 }\n ]\n }\n]\n","/**\n * Convert a tile URL template to a regex pattern and capture group names.\n * Supports {z}, {x}, {y}, {s} (Leaflet subdomain), {a-c}/{1-4} (OpenLayers subdomain), and {r} (retina) placeholders.\n * @param {string} template - URL template like \"https://{s}.tile.example.com/{z}/{x}/{y}.png\"\n * @returns {{ pattern: RegExp, groups: string[] }}\n */\nfunction templateToRegex(template) {\n const groups = [];\n // Escape regex special chars, then replace placeholders\n let pattern = template\n .replace(/[.*+?^${}()|[\\]\\\\]/g, (char) => {\n // Don't escape our placeholders\n if (char === '{' || char === '}') return char;\n return '\\\\' + char;\n })\n // Make protocol flexible (http/https)\n .replace(/^https:\\/\\//, 'https?://')\n .replace(/^http:\\/\\//, 'https?://')\n // Handle {a-c} or {1-4} etc (OpenLayers style subdomain)\n .replace(/\\{[a-z0-9]-[a-z0-9]\\}/gi, () => {\n groups.push('s');\n return '([a-z0-9]+)';\n })\n .replace(/\\{(z|x|y|s|r)\\}/gi, (_, name) => {\n const lowerName = name.toLowerCase();\n groups.push(lowerName);\n if (lowerName === 's') {\n // Subdomain: single letter or short string\n return '([a-z0-9]+)';\n }\n if (lowerName === 'r') {\n // Retina suffix: optional @2x or similar\n return '(@\\\\d+x)?';\n }\n // z, x, y: numeric\n return '(\\\\d+)';\n });\n \n // Allow optional query string at end\n return { pattern: new RegExp('^' + pattern + '(\\\\?.*)?$', 'i'), groups };\n}\n\n/**\n * Convert a tile URL template to a regex that matches the template itself.\n * @param {string} template - URL template like \"https://{s}.tile.example.com/{z}/{x}/{y}.png\"\n * @returns {RegExp}\n */\nfunction templateToTemplateRegex(template) {\n // Escape regex special chars, then replace placeholders with literal match\n let pattern = template\n .replace(/[.*+?^${}()|[\\]\\\\]/g, (char) => {\n if (char === '{' || char === '}') return char;\n return '\\\\' + char;\n })\n // Make protocol flexible (http/https)\n .replace(/^https:\\/\\//, 'https?://')\n .replace(/^http:\\/\\//, 'https?://')\n // Handle {a-c} or {1-4} (OpenLayers style subdomain)\n .replace(/\\{([a-z0-9])-([a-z0-9])\\}/gi, (_, start, end) => `(\\\\{${start}-${end}\\\\}|[a-z0-9]+)`)\n .replace(/\\{(z|x|y|s|r)\\}/gi, (_, name) => {\n const lowerName = name.toLowerCase();\n if (lowerName === 's') {\n // Match {s} placeholder or actual subdomain\n return '(\\\\{s\\\\}|[a-z0-9]+)';\n }\n if (lowerName === 'r') {\n // Match {r} placeholder or actual retina or empty\n return '(\\\\{r\\\\}|@\\\\d+x)?';\n }\n // Match {z}, {x}, {y} placeholders\n return `\\\\{${lowerName}\\\\}`;\n });\n \n // Allow optional query string at end\n return new RegExp('^' + pattern + '(\\\\?.*)?$', 'i');\n}\n\n/**\n * Base class for layer configurations\n * \n * Supports separate styling for NE (Natural Earth) data at low zoom levels\n * and OSM data at higher zoom levels, split by zoomThreshold.\n */\nexport class LayerConfig {\n constructor({\n id,\n startZoom = 0,\n zoomThreshold = 5,\n // Tile URL templates for matching (e.g., \"https://{s}.tile.example.com/{z}/{x}/{y}.png\")\n tileUrlTemplates = [],\n // Line width stops: map of zoom level to line width (at least 2 entries)\n lineWidthStops = { 1: 0.5, 10: 2.5 },\n // Line styles array - each element describes a line to draw\n // { color: string, widthFraction?: number, dashArray?: number[], startZoom?: number, endZoom?: number }\n // Lines are drawn in array order. startZoom defaults to layerConfig startZoom, endZoom defaults to Infinity\n lineStyles = [{ color: 'green', widthFraction: 1.0 }],\n // Factor to multiply line width for deletion blur (default 1.5)\n // Higher values leave gaps where wiped lines meet existing lines\n // Lower values mean wiped lines show through\n delWidthFactor = 1.5,\n // Factor to extend add lines by (multiplied by deletion line width)\n // Helps cover gaps where deleted lines meet the new boundary\n // Set to 0 to disable extension\n lineExtensionFactor = 0.5,\n }) {\n if (!id || typeof id !== 'string') {\n throw new Error('LayerConfig requires a non-empty string id');\n }\n\n this.id = id;\n this.startZoom = startZoom;\n this.zoomThreshold = zoomThreshold;\n\n if (startZoom > zoomThreshold) {\n throw new Error(`LayerConfig \"${id}\": startZoom (${startZoom}) must be <= zoomThreshold (${zoomThreshold})`);\n }\n\n // Normalize to array\n const templates = Array.isArray(tileUrlTemplates) ? tileUrlTemplates : \n (tileUrlTemplates ? [tileUrlTemplates] : []);\n this.tileUrlTemplates = templates;\n \n // Pre-compile regex patterns for matching tile URLs (with actual coords)\n this._compiledPatterns = templates.map(t => templateToRegex(t));\n \n // Pre-compile regex patterns for matching template URLs (with {z}/{x}/{y} placeholders)\n this._templatePatterns = templates.map(t => templateToTemplateRegex(t));\n\n // Validate lineWidthStops\n if (!lineWidthStops || typeof lineWidthStops !== 'object' || Array.isArray(lineWidthStops)) {\n throw new Error(`LayerConfig \"${id}\": lineWidthStops must be an object`);\n }\n const stopKeys = Object.keys(lineWidthStops);\n if (stopKeys.length < 2) {\n throw new Error(`LayerConfig \"${id}\": lineWidthStops must have at least 2 entries`);\n }\n for (const key of stopKeys) {\n const zoom = Number(key);\n if (!Number.isInteger(zoom) || zoom < 0) {\n throw new Error(`LayerConfig \"${id}\": lineWidthStops keys must be non-negative integers, got \"${key}\"`);\n }\n if (typeof lineWidthStops[key] !== 'number' || lineWidthStops[key] <= 0) {\n throw new Error(`LayerConfig \"${id}\": lineWidthStops values must be positive numbers`);\n }\n }\n this.lineWidthStops = lineWidthStops;\n\n // Validate lineStyles\n if (!Array.isArray(lineStyles) || lineStyles.length === 0) {\n throw new Error(`LayerConfig \"${id}\": lineStyles must be a non-empty array`);\n }\n for (let i = 0; i < lineStyles.length; i++) {\n const style = lineStyles[i];\n if (!style || typeof style !== 'object') {\n throw new Error(`LayerConfig \"${id}\": lineStyles[${i}] must be an object`);\n }\n if (!style.color || typeof style.color !== 'string') {\n throw new Error(`LayerConfig \"${id}\": lineStyles[${i}].color must be a non-empty string`);\n }\n }\n \n // Line styles - normalize startZoom/endZoom defaults\n this.lineStyles = lineStyles.map(style => ({\n ...style,\n startZoom: style.startZoom ?? startZoom,\n endZoom: style.endZoom ?? Infinity,\n }));\n \n // Deletion width factor\n this.delWidthFactor = delWidthFactor;\n \n // Line extension factor\n this.lineExtensionFactor = lineExtensionFactor;\n }\n\n /**\n * Get line styles active at a given zoom level\n * @param {number} z - Zoom level\n * @returns {Array<{color: string, widthFraction?: number, dashArray?: number[]}>}\n */\n getLineStylesForZoom(z) {\n return this.lineStyles.filter(style => z >= style.startZoom && z <= style.endZoom);\n }\n\n /**\n * Check if this config matches the given template URLs (with {z}/{x}/{y} placeholders)\n * @param {string | string[]} templates - Single template URL or array of template URLs\n * @returns {boolean}\n */\n matchTemplate(templates) {\n if (this._templatePatterns.length === 0) return false;\n \n const urls = Array.isArray(templates) ? templates : [templates];\n if (urls.length === 0) return false;\n \n return urls.some(url => \n this._templatePatterns.some(pattern => pattern.test(url))\n );\n }\n\n /**\n * Check if this config matches the given tile URLs (with actual coordinates)\n * @param {string | string[]} tiles - Single tile URL or array of tile URLs\n * @returns {boolean}\n */\n matchTileUrl(tiles) {\n if (this._compiledPatterns.length === 0) return false;\n \n const urls = Array.isArray(tiles) ? tiles : [tiles];\n if (urls.length === 0) return false;\n \n return urls.some(url => \n this._compiledPatterns.some(({ pattern }) => pattern.test(url))\n );\n }\n\n /**\n * Extract tile coordinates (z, x, y) from a URL using this config's templates\n * @param {string} url - Tile URL to extract coordinates from\n * @returns {{ z: number, x: number, y: number } | null}\n */\n extractCoords(url) {\n for (const { pattern, groups } of this._compiledPatterns) {\n const match = url.match(pattern);\n if (match) {\n const result = {};\n for (let i = 0; i < groups.length; i++) {\n const name = groups[i];\n const value = match[i + 1];\n if (name === 'z' || name === 'x' || name === 'y') {\n result[name] = parseInt(value, 10);\n }\n }\n if ('z' in result && 'x' in result && 'y' in result) {\n return { z: result.z, x: result.x, y: result.y };\n }\n }\n }\n return null;\n }\n\n /**\n * Serialize the config to a plain object for postMessage\n * @returns {Object}\n */\n toJSON() {\n return {\n id: this.id,\n startZoom: this.startZoom,\n zoomThreshold: this.zoomThreshold,\n tileUrlTemplates: this.tileUrlTemplates,\n lineWidthStops: this.lineWidthStops,\n lineStyles: this.lineStyles,\n delWidthFactor: this.delWidthFactor,\n lineExtensionFactor: this.lineExtensionFactor,\n };\n }\n\n /**\n * Create a LayerConfig from a plain object (e.g., from postMessage)\n * @param {Object} obj\n * @returns {LayerConfig}\n */\n static fromJSON(obj) {\n return new LayerConfig(obj);\n }\n}\n\nexport default LayerConfig;\n","import configsJson from './configs.json' with { type: 'json' };\nimport { LayerConfig } from './layerconfig.js';\n\nexport { LayerConfig } from './layerconfig.js';\n\n/**\n * Layer configuration registry\n */\nexport class LayerConfigRegistry {\n constructor() {\n this.registry = {};\n }\n\n /**\n * Get a layer config by id\n */\n get(id) {\n return this.registry[id];\n }\n\n /**\n * Register a new layer config\n */\n register(config) {\n this.registry[config.id] = config;\n }\n\n /**\n * Remove a layer config by id\n */\n remove(id) {\n if (!this.registry[id]) return false;\n delete this.registry[id];\n return true;\n }\n\n /**\n * Detect layer config from tile URL templates (with {z}/{x}/{y} placeholders)\n * @param {string | string[]} templates - Single template URL or array of template URLs\n */\n detectFromTemplates(templates) {\n if (!templates || (Array.isArray(templates) && templates.length === 0)) return undefined;\n \n for (const config of Object.values(this.registry)) {\n if (config.matchTemplate(templates)) {\n return config;\n }\n }\n \n return undefined;\n }\n\n /**\n * Detect layer config from actual tile URLs (with numeric coordinates)\n * @param {string | string[]} urls - Single tile URL or array of tile URLs\n */\n detectFromTileUrls(urls) {\n if (!urls || (Array.isArray(urls) && urls.length === 0)) return undefined;\n \n for (const config of Object.values(this.registry)) {\n if (config.matchTileUrl(urls)) {\n return config;\n }\n }\n \n return undefined;\n }\n\n /**\n * Get all available layer config ids\n */\n getAvailableIds() {\n return Object.keys(this.registry);\n }\n\n /**\n * Create a new registry with all configs from this registry plus extra configs.\n * @param {LayerConfig[]} extraLayerConfigs - Additional configs to add\n * @returns {LayerConfigRegistry} A new registry with merged configs\n */\n createMergedRegistry(extraLayerConfigs) {\n const registry = new LayerConfigRegistry();\n \n for (const id of this.getAvailableIds()) {\n registry.register(this.get(id));\n }\n \n if (extraLayerConfigs && extraLayerConfigs.length > 0) {\n for (const config of extraLayerConfigs) {\n registry.register(config);\n }\n }\n \n return registry;\n }\n\n /**\n * Parse a tile URL into its components: layer config and coordinates\n * @param {string} url - Tile URL to parse\n * @returns {{ layerConfig: LayerConfig, coords: { z: number, x: number, y: number } } | null}\n */\n parseTileUrl(url) {\n // Check if URL matches any layer config\n const layerConfig = this.detectFromTileUrls([url]);\n if (!layerConfig) return null;\n \n // Extract tile coordinates using the matched config\n const coords = layerConfig.extractCoords(url);\n if (!coords) return null;\n \n return { layerConfig, coords };\n }\n}\n\n// Default registry with built-in configs loaded from JSON\nexport const layerConfigs = new LayerConfigRegistry();\nfor (const configData of configsJson) {\n layerConfigs.register(new LayerConfig(configData));\n}\n\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@india-boundary-corrector/layer-configs",
3
+ "version": "0.0.1",
4
+ "description": "Pre-built layer configurations for India boundary corrections",
5
+ "type": "module",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.js",
8
+ "types": "src/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./src/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./src/index.d.ts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "src",
23
+ "dist"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsup"
27
+ },
28
+ "keywords": [
29
+ "india",
30
+ "boundary",
31
+ "map",
32
+ "layer-config"
33
+ ],
34
+ "author": "ramSeraph",
35
+ "license": "Unlicense",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/ramSeraph/india_boundary_corrector.git",
39
+ "directory": "packages/layer-configs"
40
+ },
41
+ "bugs": {
42
+ "url": "https://github.com/ramSeraph/india_boundary_corrector/issues"
43
+ },
44
+ "homepage": "https://github.com/ramSeraph/india_boundary_corrector#readme"
45
+ }
@@ -0,0 +1,85 @@
1
+ [
2
+ {
3
+ "id": "cartodb-dark",
4
+ "zoomThreshold": 5,
5
+ "tileUrlTemplates": [
6
+ "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
7
+ "https://basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
8
+ "https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}{r}.png",
9
+ "https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}{r}.png",
10
+ "https://basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}{r}.png",
11
+ "https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_nolabels/{z}/{x}/{y}{r}.png"
12
+ ],
13
+ "lineWidthStops": { "1": 0.5, "10": 2.5 },
14
+ "lineStyles": [
15
+ { "color": "rgb(40, 40, 40)" }
16
+ ]
17
+ },
18
+ {
19
+ "id": "cartodb-light",
20
+ "startZoom": 0,
21
+ "zoomThreshold": 5,
22
+ "tileUrlTemplates": [
23
+ "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
24
+ "https://basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
25
+ "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}{r}.png",
26
+ "https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png",
27
+ "https://basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png",
28
+ "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_nolabels/{z}/{x}/{y}{r}.png",
29
+ "https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
30
+ "https://basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
31
+ "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}{r}.png",
32
+ "https://basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}{r}.png",
33
+ "https://{s}.basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png",
34
+ "https://basemaps.cartocdn.com/rastertiles/voyager_labels_under/{z}/{x}/{y}{r}.png"
35
+ ],
36
+ "lineWidthStops": { "1": 0.25, "2": 0.25, "3": 0.5, "4": 0.75, "5": 1.0 },
37
+ "lineStyles": [
38
+ { "color": "rgb(235, 214, 214)", "alpha": 0.2, "startZoom": 6, "widthFraction": 5 },
39
+ { "color": "rgb(235, 214, 214)" }
40
+ ]
41
+ },
42
+ {
43
+ "id": "open-topo",
44
+ "startZoom": 4,
45
+ "zoomThreshold": 4,
46
+ "tileUrlTemplates": [
47
+ "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
48
+ "https://tile.opentopomap.org/{z}/{x}/{y}.png"
49
+ ],
50
+ "lineWidthStops": { "4": 0.75, "5": 1.0, "6": 1.25, "7": 1.5, "8": 1.75, "9": 1.25, "10": 1.25, "13": 1.5 },
51
+ "lineStyles": [
52
+ { "color": "rgb(83, 83, 83)", "startZoom": 7, "endZoom": 8, "alpha": 0.4, "widthFraction": 4 },
53
+ { "color": "rgb(83, 83, 83)", "endZoom": 8 },
54
+ { "color": "rgb(140, 20, 180)", "startZoom": 9, "widthFraction": 9, "alpha": 0.2 },
55
+ { "color": "rgb(140, 20, 180)", "startZoom": 9 }
56
+ ]
57
+ },
58
+ {
59
+ "id": "osm-carto",
60
+ "startZoom": 1,
61
+ "zoomThreshold": 1,
62
+ "tileUrlTemplates": [
63
+ "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
64
+ "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
65
+ ],
66
+ "lineWidthStops": { "1": 0.5, "2": 0.6, "3": 0.7, "4": 1.0, "10": 3.75 },
67
+ "lineStyles": [
68
+ { "color": "rgb(200, 180, 200)" },
69
+ { "color": "rgb(160, 120, 160)", "widthFraction": 0.333, "dashArray": [30, 2, 8, 2] }
70
+ ]
71
+ },
72
+ {
73
+ "id": "osm-hot",
74
+ "startZoom": 2,
75
+ "zoomThreshold": 2,
76
+ "tileUrlTemplates": [
77
+ "https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png"
78
+ ],
79
+ "lineWidthStops": { "2": 3.0, "3": 3.0, "7": 3.0, "8": 3.5, "9": 3.5 },
80
+ "lineStyles": [
81
+ { "color": "rgb(149, 175, 180)" },
82
+ { "color": "rgb(89, 117, 123)", "widthFraction": 0.33 }
83
+ ]
84
+ }
85
+ ]