@india-boundary-corrector/tilefixer 0.0.3 → 0.0.5
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 +14 -9
- package/dist/index.cjs +174 -56
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +176 -56
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/corrections.js +88 -25
- package/src/index.d.ts +74 -16
- package/src/index.js +170 -37
package/README.md
CHANGED
|
@@ -13,12 +13,12 @@ npm install @india-boundary-corrector/tilefixer
|
|
|
13
13
|
## Usage
|
|
14
14
|
|
|
15
15
|
```javascript
|
|
16
|
-
import {
|
|
16
|
+
import { TileFixer } from '@india-boundary-corrector/tilefixer';
|
|
17
17
|
import { getPmtilesUrl } from '@india-boundary-corrector/data';
|
|
18
18
|
import { layerConfigs } from '@india-boundary-corrector/layer-configs';
|
|
19
19
|
|
|
20
20
|
// Create a boundary corrector
|
|
21
|
-
const corrector = new
|
|
21
|
+
const corrector = new TileFixer(getPmtilesUrl());
|
|
22
22
|
|
|
23
23
|
// Get corrections for a tile
|
|
24
24
|
const corrections = await corrector.getCorrections(z, x, y);
|
|
@@ -30,32 +30,38 @@ const fixedTileData = await corrector.fixTile(
|
|
|
30
30
|
corrections,
|
|
31
31
|
originalTileArrayBuffer,
|
|
32
32
|
layerConfig,
|
|
33
|
-
z
|
|
34
|
-
256 // tile size (optional, defaults to 256)
|
|
33
|
+
z // zoom level (tile size is derived from image)
|
|
35
34
|
);
|
|
36
35
|
```
|
|
37
36
|
|
|
38
37
|
## API
|
|
39
38
|
|
|
40
|
-
### `
|
|
39
|
+
### `TileFixer`
|
|
40
|
+
|
|
41
|
+
#### Static Methods
|
|
42
|
+
|
|
43
|
+
| Method | Returns | Description |
|
|
44
|
+
|--------|---------|-------------|
|
|
45
|
+
| `TileFixer.getOrCreate(pmtilesUrl)` | `TileFixer` | Get or create a TileFixer for a URL (reuses existing instances) |
|
|
46
|
+
| `TileFixer.setDefaultCacheMaxFeatures(count)` | `void` | Set default max features to cache for new instances (default: 25000) |
|
|
41
47
|
|
|
42
48
|
#### Constructor
|
|
43
49
|
|
|
44
50
|
```javascript
|
|
45
|
-
new
|
|
51
|
+
new TileFixer(pmtilesUrl, options?)
|
|
46
52
|
```
|
|
47
53
|
|
|
48
54
|
| Parameter | Type | Description |
|
|
49
55
|
|-----------|------|-------------|
|
|
50
56
|
| `pmtilesUrl` | string | URL to the PMTiles file |
|
|
51
|
-
| `options.
|
|
57
|
+
| `options.cacheMaxFeatures` | number | Maximum features to cache |
|
|
52
58
|
|
|
53
59
|
#### Methods
|
|
54
60
|
|
|
55
61
|
| Method | Returns | Description |
|
|
56
62
|
|--------|---------|-------------|
|
|
57
63
|
| `getCorrections(z, x, y)` | `Promise<Object>` | Get correction features for a tile. Supports overzoom beyond zoom 14. |
|
|
58
|
-
| `fixTile(corrections, rasterTile, layerConfig, zoom
|
|
64
|
+
| `fixTile(corrections, rasterTile, layerConfig, zoom)` | `Promise<ArrayBuffer>` | Apply corrections to a raster tile and return corrected PNG. Tile size is derived from the image. |
|
|
59
65
|
| `fetchAndFixTile(tileUrl, z, x, y, layerConfig, options?)` | `Promise<Object>` | Fetch a tile, apply corrections, and return result. See below. |
|
|
60
66
|
| `getSource()` | `PMTiles` | Get the underlying PMTiles source object |
|
|
61
67
|
| `clearCache()` | `void` | Clear the tile cache |
|
|
@@ -64,7 +70,6 @@ new BoundaryCorrector(pmtilesUrl, options?)
|
|
|
64
70
|
|
|
65
71
|
```javascript
|
|
66
72
|
const result = await corrector.fetchAndFixTile(tileUrl, z, x, y, layerConfig, {
|
|
67
|
-
tileSize: 256, // Tile size in pixels (default: 256)
|
|
68
73
|
signal: abortSignal, // AbortSignal for cancellation
|
|
69
74
|
mode: 'cors', // Fetch mode
|
|
70
75
|
});
|
package/dist/index.cjs
CHANGED
|
@@ -3,6 +3,7 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
7
|
var __export = (target, all) => {
|
|
7
8
|
for (var name in all)
|
|
8
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -16,12 +17,15 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
17
|
return to;
|
|
17
18
|
};
|
|
18
19
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
19
21
|
|
|
20
22
|
// src/index.js
|
|
21
23
|
var index_exports = {};
|
|
22
24
|
__export(index_exports, {
|
|
23
|
-
BoundaryCorrector: () => BoundaryCorrector,
|
|
24
25
|
MIN_LINE_WIDTH: () => MIN_LINE_WIDTH,
|
|
26
|
+
TileFetchError: () => TileFetchError,
|
|
27
|
+
TileFixer: () => TileFixer,
|
|
28
|
+
buildFetchOptions: () => buildFetchOptions,
|
|
25
29
|
getLineWidth: () => getLineWidth
|
|
26
30
|
});
|
|
27
31
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -2052,10 +2056,16 @@ function writeUtf8(buf, str, pos) {
|
|
|
2052
2056
|
}
|
|
2053
2057
|
|
|
2054
2058
|
// src/corrections.js
|
|
2055
|
-
var DEFAULT_CACHE_SIZE = 64;
|
|
2056
2059
|
function toIndex(z2, x2, y) {
|
|
2057
2060
|
return `${x2}:${y}:${z2}`;
|
|
2058
2061
|
}
|
|
2062
|
+
function countFeatures(corrections) {
|
|
2063
|
+
let count = 0;
|
|
2064
|
+
for (const features of Object.values(corrections)) {
|
|
2065
|
+
count += features.length;
|
|
2066
|
+
}
|
|
2067
|
+
return count;
|
|
2068
|
+
}
|
|
2059
2069
|
function parseTile(buffer) {
|
|
2060
2070
|
const tile = new VectorTile(new Pbf(buffer));
|
|
2061
2071
|
const result = {};
|
|
@@ -2104,16 +2114,19 @@ var CorrectionsSource = class {
|
|
|
2104
2114
|
/**
|
|
2105
2115
|
* @param {string} pmtilesUrl - URL to the PMTiles file
|
|
2106
2116
|
* @param {Object} [options] - Options
|
|
2107
|
-
* @param {number} [options.
|
|
2117
|
+
* @param {number} [options.cacheMaxFeatures=10000] - Maximum number of features to cache
|
|
2108
2118
|
* @param {number} [options.maxDataZoom] - Maximum zoom level in PMTiles (auto-detected if not provided)
|
|
2109
2119
|
*/
|
|
2110
2120
|
constructor(pmtilesUrl, options = {}) {
|
|
2111
2121
|
this.pmtilesUrl = pmtilesUrl;
|
|
2112
2122
|
this.pmtiles = new x(pmtilesUrl);
|
|
2113
|
-
this.
|
|
2123
|
+
this.cacheMaxFeatures = options.cacheMaxFeatures;
|
|
2114
2124
|
this.maxDataZoom = options.maxDataZoom;
|
|
2115
2125
|
this.cache = /* @__PURE__ */ new Map();
|
|
2116
2126
|
this.inflight = /* @__PURE__ */ new Map();
|
|
2127
|
+
this.cachedFeatureCount = 0;
|
|
2128
|
+
this.emptyKeys = /* @__PURE__ */ new Set();
|
|
2129
|
+
this.nonEmptyKeys = /* @__PURE__ */ new Set();
|
|
2117
2130
|
}
|
|
2118
2131
|
/**
|
|
2119
2132
|
* Get the PMTiles source object.
|
|
@@ -2128,6 +2141,35 @@ var CorrectionsSource = class {
|
|
|
2128
2141
|
clearCache() {
|
|
2129
2142
|
this.cache.clear();
|
|
2130
2143
|
this.inflight.clear();
|
|
2144
|
+
this.cachedFeatureCount = 0;
|
|
2145
|
+
this.emptyKeys.clear();
|
|
2146
|
+
this.nonEmptyKeys.clear();
|
|
2147
|
+
}
|
|
2148
|
+
/**
|
|
2149
|
+
* Evict cache entries to stay under the feature limit.
|
|
2150
|
+
* Empty entries are evicted first (cheap to re-fetch from PMTiles directory cache).
|
|
2151
|
+
* Within each category, evicts LRU (least recently used) entries.
|
|
2152
|
+
* @private
|
|
2153
|
+
*/
|
|
2154
|
+
_evictIfNeeded() {
|
|
2155
|
+
while (this.cachedFeatureCount > this.cacheMaxFeatures && this.cache.size > 1) {
|
|
2156
|
+
const targetSet = this.emptyKeys.size > 0 ? this.emptyKeys : this.nonEmptyKeys;
|
|
2157
|
+
if (targetSet.size === 0) break;
|
|
2158
|
+
let evictKey = void 0;
|
|
2159
|
+
let minUsed = Infinity;
|
|
2160
|
+
for (const key of targetSet) {
|
|
2161
|
+
const entry = this.cache.get(key);
|
|
2162
|
+
if (entry && entry.used < minUsed) {
|
|
2163
|
+
minUsed = entry.used;
|
|
2164
|
+
evictKey = key;
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
if (!evictKey) break;
|
|
2168
|
+
const evicted = this.cache.get(evictKey);
|
|
2169
|
+
this.cachedFeatureCount -= evicted.featureCount;
|
|
2170
|
+
targetSet.delete(evictKey);
|
|
2171
|
+
this.cache.delete(evictKey);
|
|
2172
|
+
}
|
|
2131
2173
|
}
|
|
2132
2174
|
/**
|
|
2133
2175
|
* Auto-detect max zoom from PMTiles metadata.
|
|
@@ -2148,10 +2190,11 @@ var CorrectionsSource = class {
|
|
|
2148
2190
|
* @param {number} z
|
|
2149
2191
|
* @param {number} x
|
|
2150
2192
|
* @param {number} y
|
|
2193
|
+
* @param {AbortSignal} [signal] - Optional abort signal
|
|
2151
2194
|
* @returns {Promise<Object<string, Array>>}
|
|
2152
2195
|
* @private
|
|
2153
2196
|
*/
|
|
2154
|
-
async _fetchTile(z2, x2, y) {
|
|
2197
|
+
async _fetchTile(z2, x2, y, signal) {
|
|
2155
2198
|
const idx = toIndex(z2, x2, y);
|
|
2156
2199
|
return new Promise((resolve, reject) => {
|
|
2157
2200
|
const entry = this.cache.get(idx);
|
|
@@ -2166,14 +2209,18 @@ var CorrectionsSource = class {
|
|
|
2166
2209
|
return;
|
|
2167
2210
|
}
|
|
2168
2211
|
this.inflight.set(idx, []);
|
|
2169
|
-
this.pmtiles.getZxy(z2, x2, y).then((result) => {
|
|
2212
|
+
this.pmtiles.getZxy(z2, x2, y, signal).then((result) => {
|
|
2170
2213
|
let data;
|
|
2171
2214
|
if (result) {
|
|
2172
2215
|
data = parseTile(result.data);
|
|
2173
2216
|
} else {
|
|
2174
2217
|
data = {};
|
|
2175
2218
|
}
|
|
2176
|
-
|
|
2219
|
+
const featureCount = countFeatures(data);
|
|
2220
|
+
const empty = featureCount === 0;
|
|
2221
|
+
this.cache.set(idx, { used: performance.now(), data, featureCount, empty });
|
|
2222
|
+
this.cachedFeatureCount += featureCount;
|
|
2223
|
+
(empty ? this.emptyKeys : this.nonEmptyKeys).add(idx);
|
|
2177
2224
|
const ifentry2 = this.inflight.get(idx);
|
|
2178
2225
|
if (ifentry2) {
|
|
2179
2226
|
for (const waiter of ifentry2) {
|
|
@@ -2182,19 +2229,7 @@ var CorrectionsSource = class {
|
|
|
2182
2229
|
}
|
|
2183
2230
|
this.inflight.delete(idx);
|
|
2184
2231
|
resolve(data);
|
|
2185
|
-
|
|
2186
|
-
let minUsed = Infinity;
|
|
2187
|
-
let minKey = void 0;
|
|
2188
|
-
this.cache.forEach((value, key) => {
|
|
2189
|
-
if (value.used < minUsed) {
|
|
2190
|
-
minUsed = value.used;
|
|
2191
|
-
minKey = key;
|
|
2192
|
-
}
|
|
2193
|
-
});
|
|
2194
|
-
if (minKey) {
|
|
2195
|
-
this.cache.delete(minKey);
|
|
2196
|
-
}
|
|
2197
|
-
}
|
|
2232
|
+
this._evictIfNeeded();
|
|
2198
2233
|
}).catch((e) => {
|
|
2199
2234
|
const ifentry2 = this.inflight.get(idx);
|
|
2200
2235
|
if (ifentry2) {
|
|
@@ -2213,9 +2248,10 @@ var CorrectionsSource = class {
|
|
|
2213
2248
|
* @param {number} z - Zoom level
|
|
2214
2249
|
* @param {number} x - Tile X coordinate
|
|
2215
2250
|
* @param {number} y - Tile Y coordinate
|
|
2251
|
+
* @param {AbortSignal} [signal] - Optional abort signal
|
|
2216
2252
|
* @returns {Promise<Object<string, Array>>} Map of layer name to array of features
|
|
2217
2253
|
*/
|
|
2218
|
-
async get(z2, x2, y) {
|
|
2254
|
+
async get(z2, x2, y, signal) {
|
|
2219
2255
|
const maxDataZoom = await this._getMaxDataZoom();
|
|
2220
2256
|
if (z2 > maxDataZoom) {
|
|
2221
2257
|
const zoomDiff = z2 - maxDataZoom;
|
|
@@ -2224,18 +2260,64 @@ var CorrectionsSource = class {
|
|
|
2224
2260
|
const parentY = Math.floor(y / scale);
|
|
2225
2261
|
const offsetX = x2 % scale;
|
|
2226
2262
|
const offsetY = y % scale;
|
|
2227
|
-
const corrections = await this._fetchTile(maxDataZoom, parentX, parentY);
|
|
2263
|
+
const corrections = await this._fetchTile(maxDataZoom, parentX, parentY, signal);
|
|
2228
2264
|
if (Object.keys(corrections).length > 0) {
|
|
2229
2265
|
return transformForOverzoom(corrections, scale, offsetX, offsetY);
|
|
2230
2266
|
}
|
|
2231
2267
|
return {};
|
|
2232
2268
|
}
|
|
2233
|
-
return await this._fetchTile(z2, x2, y);
|
|
2269
|
+
return await this._fetchTile(z2, x2, y, signal);
|
|
2234
2270
|
}
|
|
2235
2271
|
};
|
|
2236
2272
|
|
|
2237
2273
|
// src/index.js
|
|
2274
|
+
var TileFetchError = class _TileFetchError extends Error {
|
|
2275
|
+
/**
|
|
2276
|
+
* @param {number} status - HTTP status code
|
|
2277
|
+
* @param {string} [url] - The URL that failed
|
|
2278
|
+
* @param {string} [body] - Response body text
|
|
2279
|
+
*/
|
|
2280
|
+
constructor(status, url, body) {
|
|
2281
|
+
super(`Tile fetch failed: ${status}`);
|
|
2282
|
+
this.name = "TileFetchError";
|
|
2283
|
+
this.status = status;
|
|
2284
|
+
this.url = url;
|
|
2285
|
+
this.body = body;
|
|
2286
|
+
}
|
|
2287
|
+
/**
|
|
2288
|
+
* Create a TileFetchError from a failed Response.
|
|
2289
|
+
* @param {Response} response - The failed fetch response
|
|
2290
|
+
* @returns {Promise<TileFetchError>}
|
|
2291
|
+
*/
|
|
2292
|
+
static async fromResponse(response) {
|
|
2293
|
+
let body;
|
|
2294
|
+
try {
|
|
2295
|
+
body = await response.text();
|
|
2296
|
+
} catch {
|
|
2297
|
+
}
|
|
2298
|
+
return new _TileFetchError(response.status, response.url, body);
|
|
2299
|
+
}
|
|
2300
|
+
};
|
|
2238
2301
|
var MIN_LINE_WIDTH = 0.5;
|
|
2302
|
+
var DEFAULT_TILE_EXTENT = 4096;
|
|
2303
|
+
var DEFAULT_LINE_WIDTH = 1;
|
|
2304
|
+
function buildFetchOptions(crossOrigin, referrerPolicy) {
|
|
2305
|
+
const options = {};
|
|
2306
|
+
if (crossOrigin === "use-credentials") {
|
|
2307
|
+
options.mode = "cors";
|
|
2308
|
+
options.credentials = "include";
|
|
2309
|
+
} else if (crossOrigin === "anonymous" || crossOrigin === "" || crossOrigin === true) {
|
|
2310
|
+
options.mode = "cors";
|
|
2311
|
+
options.credentials = "omit";
|
|
2312
|
+
} else {
|
|
2313
|
+
options.mode = "cors";
|
|
2314
|
+
options.credentials = "same-origin";
|
|
2315
|
+
}
|
|
2316
|
+
if (referrerPolicy) {
|
|
2317
|
+
options.referrerPolicy = referrerPolicy;
|
|
2318
|
+
}
|
|
2319
|
+
return options;
|
|
2320
|
+
}
|
|
2239
2321
|
function getLineWidth(zoom, lineWidthStops) {
|
|
2240
2322
|
const zooms = Object.keys(lineWidthStops).map(Number).sort((a, b2) => a - b2);
|
|
2241
2323
|
if (lineWidthStops[zoom] !== void 0) {
|
|
@@ -2267,7 +2349,7 @@ function getLineWidth(zoom, lineWidthStops) {
|
|
|
2267
2349
|
return w1 + t * (w2 - w1);
|
|
2268
2350
|
}
|
|
2269
2351
|
}
|
|
2270
|
-
return
|
|
2352
|
+
return DEFAULT_LINE_WIDTH;
|
|
2271
2353
|
}
|
|
2272
2354
|
function getFeaturesBoundingBox(features, tileSize, padding = 0) {
|
|
2273
2355
|
let minX = Infinity, minY = Infinity;
|
|
@@ -2421,6 +2503,14 @@ function extendFeaturesEnds(features, extensionLength) {
|
|
|
2421
2503
|
return { ...feature, geometry: newGeometry };
|
|
2422
2504
|
});
|
|
2423
2505
|
}
|
|
2506
|
+
function extendFeaturesByFactor(features, extensionFactor, delLineWidth, tileSize) {
|
|
2507
|
+
if (!features || features.length === 0 || extensionFactor <= 0) {
|
|
2508
|
+
return features;
|
|
2509
|
+
}
|
|
2510
|
+
const extent = features[0]?.extent || DEFAULT_TILE_EXTENT;
|
|
2511
|
+
const extensionLength = delLineWidth * extensionFactor / tileSize * extent;
|
|
2512
|
+
return extendFeaturesEnds(features, extensionLength);
|
|
2513
|
+
}
|
|
2424
2514
|
function drawFeatures(ctx, features, color, lineWidth, tileSize, dashArray, alpha) {
|
|
2425
2515
|
const prevAlpha = ctx.globalAlpha;
|
|
2426
2516
|
if (alpha !== void 0) {
|
|
@@ -2452,15 +2542,39 @@ function drawFeatures(ctx, features, color, lineWidth, tileSize, dashArray, alph
|
|
|
2452
2542
|
ctx.globalAlpha = prevAlpha;
|
|
2453
2543
|
}
|
|
2454
2544
|
}
|
|
2455
|
-
var
|
|
2545
|
+
var _TileFixer = class _TileFixer {
|
|
2546
|
+
/**
|
|
2547
|
+
* Set the default maximum features to cache for new TileFixer instances.
|
|
2548
|
+
* @param {number} maxFeatures - Maximum features to cache
|
|
2549
|
+
*/
|
|
2550
|
+
static setDefaultCacheMaxFeatures(maxFeatures) {
|
|
2551
|
+
_TileFixer._defaultCacheMaxFeatures = maxFeatures;
|
|
2552
|
+
}
|
|
2553
|
+
/**
|
|
2554
|
+
* Get or create a TileFixer instance for a given PMTiles URL.
|
|
2555
|
+
* Reuses existing instances for the same URL.
|
|
2556
|
+
* @param {string} pmtilesUrl - URL to the PMTiles file
|
|
2557
|
+
* @returns {TileFixer}
|
|
2558
|
+
*/
|
|
2559
|
+
static getOrCreate(pmtilesUrl) {
|
|
2560
|
+
let instance = _TileFixer._instances.get(pmtilesUrl);
|
|
2561
|
+
if (!instance) {
|
|
2562
|
+
instance = new _TileFixer(pmtilesUrl, {
|
|
2563
|
+
cacheMaxFeatures: _TileFixer._defaultCacheMaxFeatures
|
|
2564
|
+
});
|
|
2565
|
+
_TileFixer._instances.set(pmtilesUrl, instance);
|
|
2566
|
+
}
|
|
2567
|
+
return instance;
|
|
2568
|
+
}
|
|
2456
2569
|
/**
|
|
2457
2570
|
* @param {string} pmtilesUrl - URL to the PMTiles file
|
|
2458
2571
|
* @param {Object} [options] - Options
|
|
2459
|
-
* @param {number} [options.
|
|
2572
|
+
* @param {number} [options.cacheMaxFeatures] - Maximum number of features to cache
|
|
2460
2573
|
* @param {number} [options.maxDataZoom] - Maximum zoom level in PMTiles (auto-detected if not provided)
|
|
2461
2574
|
*/
|
|
2462
2575
|
constructor(pmtilesUrl, options = {}) {
|
|
2463
2576
|
this.correctionsSource = new CorrectionsSource(pmtilesUrl, options);
|
|
2577
|
+
this._canvas = null;
|
|
2464
2578
|
this._maskCanvas = null;
|
|
2465
2579
|
}
|
|
2466
2580
|
/**
|
|
@@ -2482,10 +2596,11 @@ var BoundaryCorrector = class {
|
|
|
2482
2596
|
* @param {number} z - Zoom level
|
|
2483
2597
|
* @param {number} x - Tile X coordinate
|
|
2484
2598
|
* @param {number} y - Tile Y coordinate
|
|
2599
|
+
* @param {AbortSignal} [signal] - Optional abort signal
|
|
2485
2600
|
* @returns {Promise<Object<string, Array>>} Map of layer name to array of features
|
|
2486
2601
|
*/
|
|
2487
|
-
async getCorrections(z2, x2, y) {
|
|
2488
|
-
return await this.correctionsSource.get(z2, x2, y);
|
|
2602
|
+
async getCorrections(z2, x2, y, signal) {
|
|
2603
|
+
return await this.correctionsSource.get(z2, x2, y, signal);
|
|
2489
2604
|
}
|
|
2490
2605
|
/**
|
|
2491
2606
|
* Apply corrections to a raster tile.
|
|
@@ -2493,10 +2608,9 @@ var BoundaryCorrector = class {
|
|
|
2493
2608
|
* @param {ArrayBuffer} rasterTile - The original raster tile as ArrayBuffer
|
|
2494
2609
|
* @param {Object} layerConfig - Layer configuration with colors and styles
|
|
2495
2610
|
* @param {number} zoom - Current zoom level
|
|
2496
|
-
* @param {number} [tileSize=256] - Size of the tile in pixels
|
|
2497
2611
|
* @returns {Promise<ArrayBuffer>} The corrected tile as ArrayBuffer (PNG)
|
|
2498
2612
|
*/
|
|
2499
|
-
async fixTile(corrections, rasterTile, layerConfig, zoom
|
|
2613
|
+
async fixTile(corrections, rasterTile, layerConfig, zoom) {
|
|
2500
2614
|
const {
|
|
2501
2615
|
startZoom = 0,
|
|
2502
2616
|
zoomThreshold,
|
|
@@ -2520,16 +2634,17 @@ var BoundaryCorrector = class {
|
|
|
2520
2634
|
const useOsm = zoom >= zoomThreshold;
|
|
2521
2635
|
const addLayerName = useOsm ? "to-add-osm" : "to-add-ne";
|
|
2522
2636
|
const delLayerName = useOsm ? "to-del-osm" : "to-del-ne";
|
|
2637
|
+
const blob = new Blob([rasterTile]);
|
|
2638
|
+
const imageBitmap = await createImageBitmap(blob);
|
|
2639
|
+
const tileSize = imageBitmap.width;
|
|
2523
2640
|
if (!this._canvas || this._canvas.width !== tileSize) {
|
|
2524
2641
|
this._canvas = new OffscreenCanvas(tileSize, tileSize);
|
|
2525
2642
|
}
|
|
2526
2643
|
const canvas = this._canvas;
|
|
2527
2644
|
const ctx = canvas.getContext("2d", { willReadFrequently: true });
|
|
2528
|
-
const blob = new Blob([rasterTile]);
|
|
2529
|
-
const imageBitmap = await createImageBitmap(blob);
|
|
2530
2645
|
ctx.drawImage(imageBitmap, 0, 0, tileSize, tileSize);
|
|
2531
2646
|
const baseLineWidth = getLineWidth(zoom, lineWidthStops);
|
|
2532
|
-
const maxWidthFraction = activeLineStyles.length > 0 ? Math.max(...activeLineStyles.map((s) => s.widthFraction
|
|
2647
|
+
const maxWidthFraction = activeLineStyles.length > 0 ? Math.max(...activeLineStyles.map((s) => s.widthFraction)) : 1;
|
|
2533
2648
|
const delLineWidth = baseLineWidth * maxWidthFraction * delWidthFactor;
|
|
2534
2649
|
const delFeatures = corrections[delLayerName] || [];
|
|
2535
2650
|
if (delFeatures.length > 0) {
|
|
@@ -2540,14 +2655,11 @@ var BoundaryCorrector = class {
|
|
|
2540
2655
|
}
|
|
2541
2656
|
let addFeatures = corrections[addLayerName] || [];
|
|
2542
2657
|
if (addFeatures.length > 0 && activeLineStyles.length > 0) {
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
const extent = addFeatures[0]?.extent || 4096;
|
|
2546
|
-
const extensionLength = delLineWidth * extensionFactor / tileSize * extent;
|
|
2547
|
-
addFeatures = extendFeaturesEnds(addFeatures, extensionLength);
|
|
2658
|
+
if (delFeatures.length > 0) {
|
|
2659
|
+
addFeatures = extendFeaturesByFactor(addFeatures, layerConfig.lineExtensionFactor, delLineWidth, tileSize);
|
|
2548
2660
|
}
|
|
2549
2661
|
for (const style of activeLineStyles) {
|
|
2550
|
-
const { color, widthFraction
|
|
2662
|
+
const { color, widthFraction, dashArray, alpha } = style;
|
|
2551
2663
|
const lineWidth = baseLineWidth * widthFraction;
|
|
2552
2664
|
drawFeatures(ctx, addFeatures, color, lineWidth, tileSize, dashArray, alpha);
|
|
2553
2665
|
}
|
|
@@ -2562,45 +2674,51 @@ var BoundaryCorrector = class {
|
|
|
2562
2674
|
* @param {number} x - Tile X coordinate
|
|
2563
2675
|
* @param {number} y - Tile Y coordinate
|
|
2564
2676
|
* @param {Object} layerConfig - Layer configuration with colors and styles
|
|
2565
|
-
* @param {Object} [
|
|
2566
|
-
* @param {
|
|
2567
|
-
* @param {
|
|
2568
|
-
* @param {
|
|
2677
|
+
* @param {Object} [fetchOptions] - Fetch options passed to fetch()
|
|
2678
|
+
* @param {AbortSignal} [fetchOptions.signal] - Abort signal for fetch
|
|
2679
|
+
* @param {RequestMode} [fetchOptions.mode] - Fetch mode (e.g., 'cors')
|
|
2680
|
+
* @param {RequestCredentials} [fetchOptions.credentials] - Fetch credentials (e.g., 'omit', 'include')
|
|
2681
|
+
* @param {string} [fetchOptions.referrer] - Referrer URL or empty string for none
|
|
2682
|
+
* @param {ReferrerPolicy} [fetchOptions.referrerPolicy] - Referrer policy (e.g., 'no-referrer', 'origin')
|
|
2683
|
+
* @param {boolean} [fallbackOnCorrectionFailure=true] - Return original tile if corrections fail
|
|
2569
2684
|
* @returns {Promise<{data: ArrayBuffer, wasFixed: boolean}>}
|
|
2570
2685
|
*/
|
|
2571
|
-
async fetchAndFixTile(tileUrl, z2, x2, y, layerConfig,
|
|
2572
|
-
const {
|
|
2573
|
-
const fetchOptions = {};
|
|
2574
|
-
if (signal) fetchOptions.signal = signal;
|
|
2575
|
-
if (mode) fetchOptions.mode = mode;
|
|
2686
|
+
async fetchAndFixTile(tileUrl, z2, x2, y, layerConfig, fetchOptions = {}, fallbackOnCorrectionFailure = true) {
|
|
2687
|
+
const { signal } = fetchOptions;
|
|
2576
2688
|
if (!layerConfig) {
|
|
2577
2689
|
const response = await fetch(tileUrl, fetchOptions);
|
|
2578
|
-
if (!response.ok) throw
|
|
2690
|
+
if (!response.ok) throw await TileFetchError.fromResponse(response);
|
|
2579
2691
|
return { data: await response.arrayBuffer(), wasFixed: false };
|
|
2580
2692
|
}
|
|
2581
2693
|
const [tileResult, correctionsResult] = await Promise.allSettled([
|
|
2582
|
-
fetch(tileUrl, fetchOptions).then((r) => {
|
|
2583
|
-
if (!r.ok) throw
|
|
2694
|
+
fetch(tileUrl, fetchOptions).then(async (r) => {
|
|
2695
|
+
if (!r.ok) throw await TileFetchError.fromResponse(r);
|
|
2584
2696
|
return r.arrayBuffer();
|
|
2585
2697
|
}),
|
|
2586
|
-
this.getCorrections(z2, x2, y)
|
|
2698
|
+
this.getCorrections(z2, x2, y, signal)
|
|
2587
2699
|
]);
|
|
2588
|
-
|
|
2589
|
-
throw new DOMException("Aborted", "AbortError");
|
|
2590
|
-
}
|
|
2700
|
+
signal?.throwIfAborted();
|
|
2591
2701
|
if (tileResult.status === "rejected") {
|
|
2592
2702
|
throw tileResult.reason;
|
|
2593
2703
|
}
|
|
2594
2704
|
const tileData = tileResult.value;
|
|
2595
2705
|
const correctionsFailed = correctionsResult.status === "rejected";
|
|
2596
2706
|
const correctionsError = correctionsFailed ? correctionsResult.reason : null;
|
|
2707
|
+
if (correctionsFailed && !fallbackOnCorrectionFailure) {
|
|
2708
|
+
throw correctionsError;
|
|
2709
|
+
}
|
|
2597
2710
|
const corrections = correctionsResult.status === "fulfilled" ? correctionsResult.value : {};
|
|
2598
2711
|
const hasCorrections = Object.values(corrections).some((arr) => arr && arr.length > 0);
|
|
2599
2712
|
if (!hasCorrections) {
|
|
2600
2713
|
return { data: tileData, wasFixed: false, correctionsFailed, correctionsError };
|
|
2601
2714
|
}
|
|
2602
|
-
const fixedData = await this.fixTile(corrections, tileData, layerConfig, z2
|
|
2715
|
+
const fixedData = await this.fixTile(corrections, tileData, layerConfig, z2);
|
|
2603
2716
|
return { data: fixedData, wasFixed: true, correctionsFailed: false, correctionsError: null };
|
|
2604
2717
|
}
|
|
2605
2718
|
};
|
|
2719
|
+
/** @type {Map<string, TileFixer>} */
|
|
2720
|
+
__publicField(_TileFixer, "_instances", /* @__PURE__ */ new Map());
|
|
2721
|
+
/** @type {number} */
|
|
2722
|
+
__publicField(_TileFixer, "_defaultCacheMaxFeatures", 25e3);
|
|
2723
|
+
var TileFixer = _TileFixer;
|
|
2606
2724
|
//# sourceMappingURL=index.cjs.map
|