maplibre-tilepackage-protocol 1.2.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/bundle.js +4314 -5342
- package/dist/bundle.js.map +1 -1
- package/dist/index.esm.js +487 -266
- package/dist/index.esm.js.map +1 -1
- package/package.json +42 -43
- package/rollup.config.mjs +0 -1
- package/src/default-decompress.js +4 -11
- package/src/get-header-and-filelist.js +5 -129
- package/src/get-json-from-file.js +1 -12
- package/src/index.js +75 -77
- package/src/maplibre-gl-js-protocol.js +0 -9
- package/src/source.js +5 -11
- package/src/zip/get-filelist.js +350 -0
- package/src/zip/get-json-from-file.js +47 -0
package/package.json
CHANGED
|
@@ -1,43 +1,42 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "maplibre-tilepackage-protocol",
|
|
3
|
-
"version": "1.2.
|
|
4
|
-
"description": "Maplibre-gl-js protocol for reading VTPK and TPKX files",
|
|
5
|
-
"homepage": "https://github.com/spatialillusions/maplibre-tilepackage-protocol#readme",
|
|
6
|
-
"bugs": {
|
|
7
|
-
"url": "https://github.com/spatialillusions/maplibre-tilepackage-protocol/issues"
|
|
8
|
-
},
|
|
9
|
-
"repository": {
|
|
10
|
-
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/spatialillusions/maplibre-tilepackage-protocol.git"
|
|
12
|
-
},
|
|
13
|
-
"license": "MIT",
|
|
14
|
-
"author": "Måns Beckman",
|
|
15
|
-
"type": "module",
|
|
16
|
-
"main": "src/index.js",
|
|
17
|
-
"scripts": {
|
|
18
|
-
"test": "echo \"Error: no test specified\" && exit 1",
|
|
19
|
-
"build": "rollup -c",
|
|
20
|
-
"build:esm": "rollup -c --configPlugin @rollup/plugin-node-resolve",
|
|
21
|
-
"demo": "npm run build"
|
|
22
|
-
},
|
|
23
|
-
"dependencies": {
|
|
24
|
-
"@mapbox/point-geometry": "^0.1.0",
|
|
25
|
-
"@mapbox/vector-tile": "^1.3.1",
|
|
26
|
-
"@maplibre/vt-pbf": "^4.1.0",
|
|
27
|
-
"fflate": "^0.8.
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"@rollup/plugin-
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "maplibre-tilepackage-protocol",
|
|
3
|
+
"version": "1.2.2",
|
|
4
|
+
"description": "Maplibre-gl-js protocol for reading VTPK and TPKX files",
|
|
5
|
+
"homepage": "https://github.com/spatialillusions/maplibre-tilepackage-protocol#readme",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/spatialillusions/maplibre-tilepackage-protocol/issues"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/spatialillusions/maplibre-tilepackage-protocol.git"
|
|
12
|
+
},
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": "Måns Beckman",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"main": "src/index.js",
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
19
|
+
"build": "rollup -c",
|
|
20
|
+
"build:esm": "rollup -c --configPlugin @rollup/plugin-node-resolve",
|
|
21
|
+
"demo": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@mapbox/point-geometry": "^0.1.0",
|
|
25
|
+
"@mapbox/vector-tile": "^1.3.1",
|
|
26
|
+
"@maplibre/vt-pbf": "^4.1.0",
|
|
27
|
+
"fflate": "^0.8.3",
|
|
28
|
+
"pbf": "^3.2.1"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@rollup/plugin-commonjs": "^26.0.3",
|
|
32
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
33
|
+
"rollup": "^4.59.0"
|
|
34
|
+
},
|
|
35
|
+
"module": "dist/index.esm.js",
|
|
36
|
+
"exports": {
|
|
37
|
+
".": {
|
|
38
|
+
"import": "./dist/index.esm.js",
|
|
39
|
+
"require": "./src/index.js"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
package/rollup.config.mjs
CHANGED
|
@@ -12,23 +12,16 @@ export default async function defaultDecompress(buf, compression) {
|
|
|
12
12
|
return buf;
|
|
13
13
|
}
|
|
14
14
|
if (compression === "gzip") {
|
|
15
|
-
|
|
16
|
-
const g =
|
|
17
|
-
typeof globalThis !== "undefined"
|
|
18
|
-
? globalThis
|
|
19
|
-
: typeof window !== "undefined"
|
|
20
|
-
? window
|
|
21
|
-
: typeof self !== "undefined"
|
|
22
|
-
? self
|
|
23
|
-
: {};
|
|
24
|
-
if (typeof g.DecompressionStream === "undefined") {
|
|
15
|
+
if (typeof globalThis.DecompressionStream === "undefined") {
|
|
25
16
|
return fflate.decompressSync(new Uint8Array(buf));
|
|
26
17
|
}
|
|
27
18
|
const stream = new Response(buf).body;
|
|
28
19
|
if (!stream) {
|
|
29
20
|
throw new Error("Failed to read response stream");
|
|
30
21
|
}
|
|
31
|
-
const result = stream.pipeThrough(
|
|
22
|
+
const result = stream.pipeThrough(
|
|
23
|
+
new globalThis.DecompressionStream("gzip"),
|
|
24
|
+
);
|
|
32
25
|
return new Response(result).arrayBuffer();
|
|
33
26
|
}
|
|
34
27
|
throw new Error("Compression method not supported");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import getJsonFromFile from "./get-json-from-file.js";
|
|
1
|
+
import getJsonFromFile from "./zip/get-json-from-file.js";
|
|
2
|
+
import getFilelistFromTilePackage from "./zip/get-filelist.js";
|
|
2
3
|
|
|
3
4
|
function xmlToJson(xmlString) {
|
|
4
5
|
const parser = new DOMParser();
|
|
@@ -71,132 +72,9 @@ export function jsonToHeader(json, files, etag) {
|
|
|
71
72
|
*/
|
|
72
73
|
export default async function getHeaderAndFileList(source) {
|
|
73
74
|
const key = source.getKey();
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
let v = new DataView(resp.data, 0, 98);
|
|
77
|
-
let entriesCentralDirectory, sizeCentralDirectory, offsetCentralDirectory;
|
|
78
|
-
//let bigZip64 = false;
|
|
79
|
-
if (v.getUint32(0, true) === 0x06064b50) {
|
|
80
|
-
// This is a ZIP64 tilepackage
|
|
81
|
-
//bigZip64 = true;
|
|
82
|
-
entriesCentralDirectory = Number(v.getBigUint64(32, true));
|
|
83
|
-
sizeCentralDirectory = Number(v.getBigUint64(40, true));
|
|
84
|
-
offsetCentralDirectory = Number(v.getBigUint64(48, true));
|
|
85
|
-
} else {
|
|
86
|
-
v = new DataView(resp.data, 98 - 22, 22);
|
|
87
|
-
if (v.getUint32(0, true) === 0x06054b50) {
|
|
88
|
-
// This is a ordinary zip archive
|
|
89
|
-
entriesCentralDirectory = Number(v.getUint16(10, true));
|
|
90
|
-
sizeCentralDirectory = Number(v.getUint32(12, true));
|
|
91
|
-
offsetCentralDirectory = Number(v.getUint32(16, true));
|
|
92
|
-
} else {
|
|
93
|
-
throw new Error("Wrong magic number for Zip archive");
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const centralDirectory = await source.getBytes(
|
|
98
|
-
offsetCentralDirectory,
|
|
99
|
-
sizeCentralDirectory,
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
v = new DataView(centralDirectory.data, 0, sizeCentralDirectory);
|
|
103
|
-
if (v.getUint32(0, true) !== 0x02014b50) {
|
|
104
|
-
throw new Error("Wrong magic number for Central Directory archive");
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
let entryStart = 0;
|
|
108
|
-
const tilePackageFiles = {};
|
|
109
|
-
for (let i = 0; i < entriesCentralDirectory; i++) {
|
|
110
|
-
if (entryStart >= sizeCentralDirectory) break;
|
|
111
|
-
/*
|
|
112
|
-
central file header signature 4 bytes (0x02014b50)
|
|
113
|
-
version made by 2 bytes
|
|
114
|
-
version needed to extract 2 bytes
|
|
115
|
-
general purpose bit flag 2 bytes
|
|
116
|
-
compression method 2 bytes
|
|
117
|
-
last mod file time 2 bytes
|
|
118
|
-
last mod file date 2 bytes
|
|
119
|
-
crc-32 4 bytes
|
|
120
|
-
compressed size 4 bytes
|
|
121
|
-
uncompressed size 4 bytes
|
|
122
|
-
file name length 2 bytes
|
|
123
|
-
extra field length 2 bytes
|
|
124
|
-
file comment length 2 bytes
|
|
125
|
-
disk number start 2 bytes
|
|
126
|
-
internal file attributes 2 bytes
|
|
127
|
-
external file attributes 4 bytes
|
|
128
|
-
relative offset of local header 4 bytes
|
|
129
|
-
|
|
130
|
-
file name (variable size)
|
|
131
|
-
extra field (variable size)
|
|
132
|
-
file comment (variable size)
|
|
133
|
-
*/
|
|
134
|
-
let sizeFile = v.getUint32(entryStart + 20, true);
|
|
135
|
-
|
|
136
|
-
const sizeFileName = v.getUint16(entryStart + 28, true);
|
|
137
|
-
|
|
138
|
-
const sizeExtraField = v.getUint16(entryStart + 30, true);
|
|
139
|
-
|
|
140
|
-
const sizeComment = v.getUint16(entryStart + 32, true);
|
|
141
|
-
|
|
142
|
-
let relativeOffset = v.getUint32(entryStart + 42, true);
|
|
143
|
-
|
|
144
|
-
const vFilename = new DataView(
|
|
145
|
-
centralDirectory.data,
|
|
146
|
-
entryStart + 46,
|
|
147
|
-
sizeFileName,
|
|
148
|
-
);
|
|
149
|
-
const decoder = new TextDecoder("utf-8");
|
|
150
|
-
const filename = decoder.decode(vFilename);
|
|
151
|
-
|
|
152
|
-
if (
|
|
153
|
-
(sizeFile == 0xffffffff || relativeOffset == 0xffffffff) &&
|
|
154
|
-
sizeExtraField > 0
|
|
155
|
-
) {
|
|
156
|
-
const vExtended = new DataView(
|
|
157
|
-
centralDirectory.data,
|
|
158
|
-
entryStart + 46 + sizeFileName,
|
|
159
|
-
32,
|
|
160
|
-
);
|
|
161
|
-
if (vExtended.getUint16(0, true) == 0x0001) {
|
|
162
|
-
/*
|
|
163
|
-
Value Size Description
|
|
164
|
-
----- ---- -----------
|
|
165
|
-
(ZIP64) 0x0001 2 bytes Tag for this "extra" block type
|
|
166
|
-
Size 2 bytes Size of this "extra" block
|
|
167
|
-
Original
|
|
168
|
-
Size 8 bytes Original uncompressed file size
|
|
169
|
-
Compressed
|
|
170
|
-
Size 8 bytes Size of compressed data
|
|
171
|
-
Relative Header
|
|
172
|
-
Offset 8 bytes Offset of local header record
|
|
173
|
-
Disk Start
|
|
174
|
-
Number 4 bytes Number of the disk on which
|
|
175
|
-
this file starts
|
|
176
|
-
*/
|
|
177
|
-
|
|
178
|
-
let j = 0;
|
|
179
|
-
if (sizeFile == 0xffffffff) {
|
|
180
|
-
sizeFile = Number(vExtended.getBigUint64(4, true));
|
|
181
|
-
j += 8;
|
|
182
|
-
}
|
|
183
|
-
if (relativeOffset == 0xffffffff) {
|
|
184
|
-
relativeOffset = Number(vExtended.getBigUint64(4 + j, true));
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
tilePackageFiles[filename] = {
|
|
190
|
-
filename: filename,
|
|
191
|
-
size: sizeFile,
|
|
192
|
-
relativeOffset: relativeOffset,
|
|
193
|
-
absoluteOffset: relativeOffset + 30 + filename.length,
|
|
194
|
-
};
|
|
195
|
-
entryStart += 46 + sizeFileName + sizeExtraField + sizeComment;
|
|
196
|
-
}
|
|
197
|
-
|
|
75
|
+
const { files: tilePackageFiles, etag } =
|
|
76
|
+
await getFilelistFromTilePackage(source);
|
|
198
77
|
let root = {};
|
|
199
|
-
|
|
200
78
|
if (key.indexOf(".tpkx") !== -1) {
|
|
201
79
|
// TPKX
|
|
202
80
|
root = await getJsonFromFile("root.json", tilePackageFiles, source);
|
|
@@ -278,11 +156,9 @@ export default async function getHeaderAndFileList(source) {
|
|
|
278
156
|
coverageMap[0][0][0] = "blob";
|
|
279
157
|
calculateCoverage(0, 0, 0, tilemap.index, coverageMap);
|
|
280
158
|
root.coverageMap = coverageMap;
|
|
281
|
-
} else {
|
|
282
|
-
// Coverage map unavailable (either disabled or missing tilemap/root.json)
|
|
283
159
|
}
|
|
284
160
|
}
|
|
285
161
|
|
|
286
|
-
const header = jsonToHeader(root, tilePackageFiles,
|
|
162
|
+
const header = jsonToHeader(root, tilePackageFiles, etag);
|
|
287
163
|
return [header, ""];
|
|
288
164
|
}
|
|
@@ -1,12 +1 @@
|
|
|
1
|
-
export default
|
|
2
|
-
const decoder = new TextDecoder("utf-8");
|
|
3
|
-
if (tilePackageFiles[file]) {
|
|
4
|
-
const fileOffset = tilePackageFiles[file].absoluteOffset;
|
|
5
|
-
const fileJSON = await source.getBytes(
|
|
6
|
-
fileOffset,
|
|
7
|
-
tilePackageFiles[file].size,
|
|
8
|
-
);
|
|
9
|
-
return JSON.parse(decoder.decode(fileJSON.data));
|
|
10
|
-
}
|
|
11
|
-
return {};
|
|
12
|
-
}
|
|
1
|
+
export { default } from "./zip/get-json-from-file.js";
|
package/src/index.js
CHANGED
|
@@ -3,26 +3,21 @@ export * from "./source.js";
|
|
|
3
3
|
import { FetchSource } from "./source.js";
|
|
4
4
|
import subdivideVectorTile from "./tilecutter/subdivide.js";
|
|
5
5
|
import defaultDecompress from "./default-decompress.js";
|
|
6
|
-
import getJsonFromFile from "./get-json-from-file.js";
|
|
6
|
+
import getJsonFromFile from "./zip/get-json-from-file.js";
|
|
7
7
|
import SharedPromiseCache from "./shared-promise-cache.js";
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* Escape literal newlines in JSON text.
|
|
11
|
-
* Replaces actual newline characters with the JSON escape sequence.
|
|
12
|
-
*/
|
|
13
|
-
function escapeJsonNewlines(text) {
|
|
14
|
-
// Replace literal newlines with JSON escape sequences
|
|
15
|
-
// This handles \r\n, \n, and \r
|
|
16
|
-
return text.replace(/\r\n/g, "\\n").replace(/[\r\n]/g, "\\n");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
9
|
function calculateFilename(z, x, y, header) {
|
|
20
10
|
const zoom = z.toString().padStart(2, "0");
|
|
21
11
|
const baseRow = Math.floor(y / 128) * 128;
|
|
22
12
|
const baseCol = Math.floor(x / 128) * 128;
|
|
23
13
|
const rowHex = baseRow.toString(16).padStart(4, "0");
|
|
24
14
|
const colHex = baseCol.toString(16).padStart(4, "0");
|
|
25
|
-
|
|
15
|
+
let basePath;
|
|
16
|
+
if (header.type === "tpkx") {
|
|
17
|
+
basePath = `tile`;
|
|
18
|
+
} else {
|
|
19
|
+
basePath = `p12/tile`;
|
|
20
|
+
}
|
|
26
21
|
return `${basePath}/L${zoom}/R${rowHex}C${colHex}.bundle`;
|
|
27
22
|
}
|
|
28
23
|
|
|
@@ -32,6 +27,10 @@ function getTileInfoFromTileIndex(tileIndex, z, x, y) {
|
|
|
32
27
|
return tileIndex[row][col];
|
|
33
28
|
}
|
|
34
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Error thrown when a response for TilePackage over HTTP does not match previous, cached parts of the archive.
|
|
32
|
+
* The default TilePackage implementation will catch this error once internally and retry a request.
|
|
33
|
+
*/
|
|
35
34
|
class EtagMismatch extends Error {
|
|
36
35
|
constructor(message) {
|
|
37
36
|
super(message);
|
|
@@ -44,25 +43,23 @@ export class TilePackage {
|
|
|
44
43
|
// Default coverageCheck enabled; disable with coverageCheck:false
|
|
45
44
|
this.coverageCheck = 1;
|
|
46
45
|
if (options && options.coverageCheck === false) this.coverageCheck = 0;
|
|
47
|
-
// Max dz guard (skip subdivision beyond this): default 8
|
|
48
|
-
this.maxDz =
|
|
49
|
-
options && typeof options.maxDz === "number" ? options.maxDz : 8;
|
|
50
46
|
if (typeof source === "string") {
|
|
51
|
-
|
|
52
|
-
? { coverageCheck: this.coverageCheck }
|
|
53
|
-
: undefined;
|
|
54
|
-
this.source = new FetchSource(source, opts);
|
|
47
|
+
this.source = new FetchSource(source, this.coverageCheck);
|
|
55
48
|
} else {
|
|
56
49
|
this.source = source;
|
|
57
|
-
// Propagate default coverageCheck to existing Source instances if undefined
|
|
58
|
-
if (this.source && this.source.coverageCheck === undefined) {
|
|
59
|
-
this.source.coverageCheck = this.coverageCheck;
|
|
60
|
-
}
|
|
61
50
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
51
|
+
|
|
52
|
+
if (options && options.decompress) {
|
|
53
|
+
this.decompress = options.decompress;
|
|
54
|
+
} else {
|
|
55
|
+
this.decompress = defaultDecompress;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (options && options.cache) {
|
|
59
|
+
this.cache = options.cache;
|
|
60
|
+
} else {
|
|
61
|
+
this.cache = new SharedPromiseCache();
|
|
62
|
+
}
|
|
66
63
|
}
|
|
67
64
|
|
|
68
65
|
async getHeader() {
|
|
@@ -179,21 +176,21 @@ export class TilePackage {
|
|
|
179
176
|
|
|
180
177
|
async getMetadataAttempt() {
|
|
181
178
|
const header = await this.cache.getHeader(this.source);
|
|
179
|
+
|
|
182
180
|
let metadata = {};
|
|
183
181
|
if (header.packageType === "vtpk") {
|
|
184
182
|
const resp = await this.source.getBytes(
|
|
185
|
-
header.
|
|
186
|
-
header.
|
|
183
|
+
header.jsonMetadataOffset,
|
|
184
|
+
header.jsonMetadataLength,
|
|
187
185
|
undefined,
|
|
188
186
|
header.etag,
|
|
189
187
|
);
|
|
188
|
+
|
|
190
189
|
const decoder = new TextDecoder("utf-8");
|
|
191
|
-
|
|
192
|
-
console.log("test", jsonText);
|
|
193
|
-
console.log("escaped text", escapeJsonNewlines(jsonText));
|
|
194
|
-
metadata = JSON.parse(escapeJsonNewlines(jsonText));
|
|
190
|
+
metadata = JSON.parse(decoder.decode(resp.data));
|
|
195
191
|
}
|
|
196
192
|
metadata.name = header.name;
|
|
193
|
+
|
|
197
194
|
return metadata;
|
|
198
195
|
}
|
|
199
196
|
|
|
@@ -211,7 +208,10 @@ export class TilePackage {
|
|
|
211
208
|
|
|
212
209
|
async getResourceAttempt(file, signal) {
|
|
213
210
|
const header = await this.cache.getHeader(this.source);
|
|
214
|
-
if (!header.files[file])
|
|
211
|
+
if (!header.files[file]) {
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
215
|
const resource = await this.cache.getResource(
|
|
216
216
|
this.source,
|
|
217
217
|
file,
|
|
@@ -251,49 +251,36 @@ export class TilePackage {
|
|
|
251
251
|
header.files,
|
|
252
252
|
this.source,
|
|
253
253
|
);
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
style.sources.esri.minzoom = header.minZoom || 0;
|
|
259
|
-
style.sources.esri.maxzoom = header.maxZoom || 22;
|
|
260
|
-
}
|
|
261
|
-
for (const k in style.sources) {
|
|
262
|
-
const src = style.sources[k];
|
|
263
|
-
if (
|
|
264
|
-
src &&
|
|
265
|
-
typeof src.url === "string" &&
|
|
266
|
-
src.url.startsWith("tilepackage://")
|
|
267
|
-
) {
|
|
268
|
-
delete src.url;
|
|
269
|
-
if (!src.tiles)
|
|
270
|
-
src.tiles = [`tilepackage://${sourceKey}/{z}/{x}/{y}`];
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
if (metadata.copyrightText)
|
|
254
|
+
style.sources.esri.url = `tilepackage://${sourceKey}`;
|
|
255
|
+
style.sources.esri.minzoom = 0; //header.maxZoom || 22;
|
|
256
|
+
style.sources.esri.maxzoom = header.maxZoom || 22;
|
|
257
|
+
if (metadata.copyrightText) {
|
|
274
258
|
style.sources.esri.attribution = metadata.copyrightText;
|
|
259
|
+
}
|
|
275
260
|
style.glyphs = `tilepackage://${sourceKey}/{fontstack}/{range}`;
|
|
276
261
|
style.sprite = `tilepackage://${sourceKey}/sprite`;
|
|
277
|
-
if (this.debug)
|
|
278
|
-
console.debug(
|
|
279
|
-
"[tilepackage style] rewritten esri source",
|
|
280
|
-
style.sources.esri,
|
|
281
|
-
);
|
|
282
262
|
return style;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
263
|
+
} else {
|
|
264
|
+
const style = {
|
|
265
|
+
version: 8,
|
|
266
|
+
sources: {
|
|
267
|
+
esri: {
|
|
268
|
+
type: "raster",
|
|
269
|
+
tileSize: header.tileSize || 256,
|
|
270
|
+
url: `tilepackage://${sourceKey}`,
|
|
271
|
+
maxzoom: header.maxZoom || 22,
|
|
272
|
+
},
|
|
293
273
|
},
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
274
|
+
layers: [
|
|
275
|
+
{
|
|
276
|
+
id: "tilepackageraster",
|
|
277
|
+
type: "raster",
|
|
278
|
+
source: "esri",
|
|
279
|
+
},
|
|
280
|
+
],
|
|
281
|
+
};
|
|
282
|
+
return style;
|
|
283
|
+
}
|
|
297
284
|
}
|
|
298
285
|
|
|
299
286
|
async getStyle() {
|
|
@@ -312,6 +299,7 @@ export class TilePackage {
|
|
|
312
299
|
const header = await this.getHeader();
|
|
313
300
|
const metadata = await this.getMetadata();
|
|
314
301
|
const ext = header.tileType;
|
|
302
|
+
|
|
315
303
|
const tileJson = {
|
|
316
304
|
tilejson: "3.0.0",
|
|
317
305
|
scheme: "xyz",
|
|
@@ -320,11 +308,21 @@ export class TilePackage {
|
|
|
320
308
|
version: header.version,
|
|
321
309
|
bounds: [header.minLon, header.minLat, header.maxLon, header.maxLat],
|
|
322
310
|
};
|
|
323
|
-
if (metadata.vector_layers)
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
if (
|
|
327
|
-
|
|
311
|
+
if (metadata.vector_layers) {
|
|
312
|
+
tileJson.vector_layers = metadata.vector_layers;
|
|
313
|
+
}
|
|
314
|
+
if (metadata.attribution) {
|
|
315
|
+
tileJson.attribution = metadata.attribution;
|
|
316
|
+
}
|
|
317
|
+
if (metadata.description) {
|
|
318
|
+
tileJson.description = metadata.description;
|
|
319
|
+
}
|
|
320
|
+
if (header.minZoom) {
|
|
321
|
+
tileJson.minzoom = header.minZoom;
|
|
322
|
+
}
|
|
323
|
+
if (header.maxZoom) {
|
|
324
|
+
tileJson.maxzoom = header.maxZoom;
|
|
325
|
+
}
|
|
328
326
|
return tileJson;
|
|
329
327
|
}
|
|
330
328
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { TilePackage } from "./index.js";
|
|
2
|
-
import protocolGlyphs from "maplibre-local-glyphs";
|
|
3
2
|
|
|
4
3
|
function stringEndsIn(string, endings) {
|
|
5
4
|
for (let i = 0; i < endings.length; i++) {
|
|
@@ -172,14 +171,6 @@ export class Protocol {
|
|
|
172
171
|
};
|
|
173
172
|
}
|
|
174
173
|
|
|
175
|
-
// Fallback to local glyphs since we couldn't load the coorect from the vtpk
|
|
176
|
-
const fallback = await protocolGlyphs({
|
|
177
|
-
url: `glyphs://${result[2]}/${result[3]}`,
|
|
178
|
-
});
|
|
179
|
-
if (fallback) {
|
|
180
|
-
return fallback;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
174
|
return { data: null };
|
|
184
175
|
}
|
|
185
176
|
}
|
package/src/source.js
CHANGED
|
@@ -21,9 +21,11 @@ export class FileSource extends Source {
|
|
|
21
21
|
constructor(file, options) {
|
|
22
22
|
super();
|
|
23
23
|
this.file = file;
|
|
24
|
+
this.coverageCheck = 1;
|
|
24
25
|
if (options && options.coverageCheck) {
|
|
25
26
|
this.coverageCheck = options.coverageCheck;
|
|
26
27
|
}
|
|
28
|
+
//console.log("Tilepackage FileSource initialized", this.file);
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
getKey() {
|
|
@@ -56,18 +58,9 @@ export class FetchSource extends Source {
|
|
|
56
58
|
this.url = url;
|
|
57
59
|
this.customHeaders = customHeaders;
|
|
58
60
|
this.mustReload = false;
|
|
59
|
-
// Safe global detection for legacy environments without globalThis
|
|
60
|
-
const g =
|
|
61
|
-
typeof globalThis !== "undefined"
|
|
62
|
-
? globalThis
|
|
63
|
-
: typeof window !== "undefined"
|
|
64
|
-
? window
|
|
65
|
-
: typeof self !== "undefined"
|
|
66
|
-
? self
|
|
67
|
-
: {};
|
|
68
61
|
let userAgent = "";
|
|
69
|
-
if (
|
|
70
|
-
userAgent =
|
|
62
|
+
if ("navigator" in globalThis) {
|
|
63
|
+
userAgent = globalThis.navigator.userAgent || "";
|
|
71
64
|
}
|
|
72
65
|
const isWindows = userAgent.indexOf("Windows") > -1;
|
|
73
66
|
const isChromiumBased = /Chrome|Chromium|Edg|OPR|Brave/.test(userAgent);
|
|
@@ -75,6 +68,7 @@ export class FetchSource extends Source {
|
|
|
75
68
|
if (isWindows && isChromiumBased) {
|
|
76
69
|
this.chromeWindowsNoCache = true;
|
|
77
70
|
}
|
|
71
|
+
this.coverageCheck = 1;
|
|
78
72
|
if (options && options.coverageCheck) {
|
|
79
73
|
this.coverageCheck = options.coverageCheck;
|
|
80
74
|
}
|