From 41b53c2c12b590829df592cb730d3c9a1f3c56b3 Mon Sep 17 00:00:00 2001 From: Brandon Liu Date: Tue, 4 Oct 2022 23:40:38 +0800 Subject: [PATCH] js library has better organization --- js/adapters.ts | 98 ++++++++++++++++++++++ js/index.test.ts | 4 - js/{v3.ts => index.ts} | 4 +- js/{ => test/data}/empty.pmtiles | 0 js/{ => test/data}/invalid.pmtiles | 0 js/{ => test/data}/test_fixture_1.pmtiles | Bin js/{ => test/data}/test_fixture_2.pmtiles | Bin js/test/index.test.ts | 2 + js/{ => test}/v2.test.ts | 41 ++++----- js/{ => test}/v3.test.ts | 22 ++--- js/tsconfig.json | 2 +- js/v2.ts | 2 +- 12 files changed, 136 insertions(+), 39 deletions(-) create mode 100644 js/adapters.ts delete mode 100644 js/index.test.ts rename js/{v3.ts => index.ts} (99%) rename js/{ => test/data}/empty.pmtiles (100%) rename js/{ => test/data}/invalid.pmtiles (100%) rename js/{ => test/data}/test_fixture_1.pmtiles (100%) rename js/{ => test/data}/test_fixture_2.pmtiles (100%) create mode 100644 js/test/index.test.ts rename js/{ => test}/v2.test.ts (83%) rename js/{ => test}/v3.test.ts (91%) diff --git a/js/adapters.ts b/js/adapters.ts new file mode 100644 index 0000000..4b1448a --- /dev/null +++ b/js/adapters.ts @@ -0,0 +1,98 @@ +declare const L: any; +import { PMTiles, Source } from "./index"; + +export const leafletRasterLayer = (source: PMTiles, options: any) => { + const cls = L.GridLayer.extend({ + createTile: function (coord: any, done: any) { + const tile: any = document.createElement("img"); + const controller = new AbortController(); + const signal = controller.signal; + tile.cancel = () => { + controller.abort(); + }; + source.getZxy(coord.z, coord.x, coord.y).then((arr) => { + if (arr) { + const blob = new Blob([arr.data], { type: "image/png" }); + const imageUrl = window.URL.createObjectURL(blob); + tile.src = imageUrl; + tile.cancel = null; + done(null, tile); + } else { + // return an empty image + } + }); + return tile; + }, + + _removeTile: function (key: string) { + const tile = this._tiles[key]; + if (!tile) { + return; + } + + if (tile.el.cancel) tile.el.cancel(); + + tile.el.width = 0; + tile.el.height = 0; + tile.el.deleted = true; + L.DomUtil.remove(tile.el); + delete this._tiles[key]; + this.fire("tileunload", { + tile: tile.el, + coords: this._keyToTileCoords(key), + }); + }, + }); + return new cls(options); +}; + +export class Protocol { + tiles: Map; + + constructor() { + this.tiles = new Map(); + } + + add(p: PMTiles) { + this.tiles.set(p.source.getKey(), p); + } + + get(url: string) { + return this.tiles.get(url); + } + + tileFunc = (params: any, callback: any) => { + const re = new RegExp(/pmtiles:\/\/(.+)\/(\d+)\/(\d+)\/(\d+)/); + const result = params.url.match(re); + const pmtiles_url = result[1]; + + let instance = this.tiles.get(pmtiles_url); + if (!instance) { + instance = new PMTiles(pmtiles_url); + this.tiles.set(pmtiles_url, instance); + } + const z = result[2]; + const x = result[3]; + const y = result[4]; + + const controller = new AbortController(); + const signal = controller.signal; + let cancel = () => { + controller.abort(); + }; + + instance.getZxy(+z, +x, +y, signal).then((arr) => { + if (arr) { + let data = new Uint8Array(arr.data); + callback(null, data, null, null); + } else { + callback(null, new Uint8Array(), null, null); + } + }).catch((e) => { + console.log(e); + }); + return { + cancel: cancel + }; + }; +} \ No newline at end of file diff --git a/js/index.test.ts b/js/index.test.ts deleted file mode 100644 index a4ae4d9..0000000 --- a/js/index.test.ts +++ /dev/null @@ -1,4 +0,0 @@ -import './v2.test'; -import './v3.test'; - - diff --git a/js/v3.ts b/js/index.ts similarity index 99% rename from js/v3.ts rename to js/index.ts index ff3ea24..4ffd185 100644 --- a/js/v3.ts +++ b/js/index.ts @@ -133,7 +133,7 @@ export interface Entry { const ENTRY_SIZE_BYTES = 32; export enum Compression { - None = 0, + Unknown = 0, Gzip = 1, Brotli = 2, Zstd = 3, @@ -149,7 +149,7 @@ function tryDecompress(buf: ArrayBuffer, compression: Compression) { } } -enum TileType { +export enum TileType { Unknown = 0, Mvt = 1, Png = 2, diff --git a/js/empty.pmtiles b/js/test/data/empty.pmtiles similarity index 100% rename from js/empty.pmtiles rename to js/test/data/empty.pmtiles diff --git a/js/invalid.pmtiles b/js/test/data/invalid.pmtiles similarity index 100% rename from js/invalid.pmtiles rename to js/test/data/invalid.pmtiles diff --git a/js/test_fixture_1.pmtiles b/js/test/data/test_fixture_1.pmtiles similarity index 100% rename from js/test_fixture_1.pmtiles rename to js/test/data/test_fixture_1.pmtiles diff --git a/js/test_fixture_2.pmtiles b/js/test/data/test_fixture_2.pmtiles similarity index 100% rename from js/test_fixture_2.pmtiles rename to js/test/data/test_fixture_2.pmtiles diff --git a/js/test/index.test.ts b/js/test/index.test.ts new file mode 100644 index 0000000..e537865 --- /dev/null +++ b/js/test/index.test.ts @@ -0,0 +1,2 @@ +import './v2.test'; +import './v3.test'; \ No newline at end of file diff --git a/js/v2.test.ts b/js/test/v2.test.ts similarity index 83% rename from js/v2.test.ts rename to js/test/v2.test.ts index 837a4c4..d28f63f 100644 --- a/js/v2.test.ts +++ b/js/test/v2.test.ts @@ -4,16 +4,16 @@ import { unshift, getUint24, getUint48, + deriveLeaf, queryLeafdir, - queryLeafLevel, queryTile, parseEntry, - Entry, + EntryV2, createDirectory, -} from "./index"; +} from "../v2"; test("stub data", (assertion) => { - let dataview = createDirectory([ + let dataview = new DataView(createDirectory([ { z: 5, x: 1000, y: 2000, offset: 1000, length: 2000, is_dir: false }, { z: 14, @@ -23,8 +23,7 @@ test("stub data", (assertion) => { length: 999, is_dir: false, }, - ]); - + ])); var z_raw = dataview.getUint8(17 + 0); var x = getUint24(dataview, 17 + 1); var y = getUint24(dataview, 17 + 4); @@ -36,7 +35,7 @@ test("stub data", (assertion) => { }); test("get entry", (assertion) => { - let view = createDirectory([ + let view = new DataView(createDirectory([ { z: 5, x: 1000, y: 2000, offset: 1000, length: 2000, is_dir: false }, { z: 14, @@ -46,7 +45,7 @@ test("get entry", (assertion) => { length: 999, is_dir: false, }, - ]); + ])); let entry = queryTile(view, 14, 16383, 16383); assertion.ok(entry!.z === 14); assertion.ok(entry!.x === 16383); @@ -58,7 +57,7 @@ test("get entry", (assertion) => { }); test("get leafdir", (assertion) => { - let view = createDirectory([ + let view = new DataView(createDirectory([ { z: 14, x: 16383, @@ -67,7 +66,7 @@ test("get leafdir", (assertion) => { length: 999, is_dir: true, }, - ]); + ])); let entry = queryLeafdir(view, 14, 16383, 16383); assertion.ok(entry!.z === 14); assertion.ok(entry!.x === 16383); @@ -79,7 +78,7 @@ test("get leafdir", (assertion) => { }); test("derive the leaf level", (assertion) => { - let view = createDirectory([ + let view = new DataView(createDirectory([ { z: 6, x: 3, @@ -88,10 +87,12 @@ test("derive the leaf level", (assertion) => { length: 0, is_dir: true, }, - ]); - let level = queryLeafLevel(view); - assertion.ok(level === 6); - view = createDirectory([ + ])); + let leaf = deriveLeaf(view,{z:7,x:6,y:6}); + assertion.ok(leaf!.z === 6); + assertion.ok(leaf!.x === 3); + assertion.ok(leaf!.y === 3); + view = new DataView(createDirectory([ { z: 6, x: 3, @@ -100,13 +101,13 @@ test("derive the leaf level", (assertion) => { length: 0, is_dir: false, }, - ]); - level = queryLeafLevel(view); - assertion.ok(level === null); + ])); + leaf = deriveLeaf(view,{z:7,x:6,y:6}); + assertion.ok(leaf === null); }); test("convert spec v1 directory to spec v2 directory", (assertion) => { - let view = createDirectory([ + let view = new DataView(createDirectory([ { z: 7, x: 3, @@ -131,7 +132,7 @@ test("convert spec v1 directory to spec v2 directory", (assertion) => { length: 1, is_dir: false, }, - ]); + ])); let entry = queryLeafdir(view, 7, 3, 3); assertion.ok(entry!.offset === 3); entry = queryTile(view, 6, 2, 2); diff --git a/js/v3.test.ts b/js/test/v3.test.ts similarity index 91% rename from js/v3.test.ts rename to js/test/v3.test.ts index 7a5d6d4..3770853 100644 --- a/js/v3.test.ts +++ b/js/test/v3.test.ts @@ -17,7 +17,7 @@ import { RangeResponse, VersionMismatch, PMTiles, -} from "./v3"; +} from "../index"; test("varint", (assertion) => { let b: BufferPosition = { @@ -144,7 +144,7 @@ class TestNodeFileSource implements Source { // echo '{"type":"Polygon","coordinates":[[[0,0],[0,1],[1,1],[1,0],[0,0]]]}' | ./tippecanoe -zg -o test_fixture_1.pmtiles test("cache getHeader", async (assertion) => { - const source = new TestNodeFileSource("test_fixture_1.pmtiles", "1"); + const source = new TestNodeFileSource("test/data/test_fixture_1.pmtiles", "1"); const cache = new SharedPromiseCache(); const header = await cache.getHeader(source); assertion.eq(header.rootDirectoryOffset, 122); @@ -171,7 +171,7 @@ test("cache getHeader", async (assertion) => { }); test("cache check against empty", async (assertion) => { - const source = new TestNodeFileSource("empty.pmtiles", "1"); + const source = new TestNodeFileSource("test/data/empty.pmtiles", "1"); const cache = new SharedPromiseCache(); try { await cache.getHeader(source); @@ -182,7 +182,7 @@ test("cache check against empty", async (assertion) => { }); test("cache check magic number", async (assertion) => { - const source = new TestNodeFileSource("invalid.pmtiles", "1"); + const source = new TestNodeFileSource("test/data/invalid.pmtiles", "1"); const cache = new SharedPromiseCache(); try { await cache.getHeader(source); @@ -194,7 +194,7 @@ test("cache check magic number", async (assertion) => { }); test("cache getDirectory", async (assertion) => { - const source = new TestNodeFileSource("test_fixture_1.pmtiles", "1"); + const source = new TestNodeFileSource("test/data/test_fixture_1.pmtiles", "1"); let cache = new SharedPromiseCache(6400, false); let header = await cache.getHeader(source); @@ -226,8 +226,8 @@ test("cache getDirectory", async (assertion) => { test("multiple sources in a single cache", async (assertion) => { const cache = new SharedPromiseCache(); - const source1 = new TestNodeFileSource("test_fixture_1.pmtiles", "1"); - const source2 = new TestNodeFileSource("test_fixture_1.pmtiles", "2"); + const source1 = new TestNodeFileSource("test/data/test_fixture_1.pmtiles", "1"); + const source2 = new TestNodeFileSource("test/data/test_fixture_1.pmtiles", "2"); await cache.getHeader(source1); assertion.eq(cache.cache.size, 2); await cache.getHeader(source2); @@ -236,7 +236,7 @@ test("multiple sources in a single cache", async (assertion) => { test("etags are part of key", async (assertion) => { const cache = new SharedPromiseCache(6400, false); - const source = new TestNodeFileSource("test_fixture_1.pmtiles", "1"); + const source = new TestNodeFileSource("test/data/test_fixture_1.pmtiles", "1"); source.etag = "etag_1"; let header = await cache.getHeader(source); assertion.eq(header.etag, "etag_1"); @@ -278,7 +278,7 @@ test("cache pruning by byte size", async (assertion) => { }); test("pmtiles get metadata", async (assertion) => { - const source = new TestNodeFileSource("test_fixture_1.pmtiles", "1"); + const source = new TestNodeFileSource("test/data/test_fixture_1.pmtiles", "1"); const p = new PMTiles(source); const metadata = await p.getMetadata(); assertion.ok(metadata.name); @@ -286,12 +286,12 @@ test("pmtiles get metadata", async (assertion) => { // echo '{"type":"Polygon","coordinates":[[[0,0],[0,1],[1,0],[0,0]]]}' | ./tippecanoe -zg -o test_fixture_2.pmtiles test("pmtiles handle retries", async (assertion) => { - const source = new TestNodeFileSource("test_fixture_1.pmtiles", "1"); + const source = new TestNodeFileSource("test/data/test_fixture_1.pmtiles", "1"); source.etag = "1"; const p = new PMTiles(source); const metadata = await p.getMetadata(); assertion.ok(metadata.name); source.etag = "2"; - source.replaceData("test_fixture_2.pmtiles"); + source.replaceData("test/data/test_fixture_2.pmtiles"); assertion.ok(await p.getZxy(0, 0, 0)); }); diff --git a/js/tsconfig.json b/js/tsconfig.json index 4b7419c..21ddb0c 100644 --- a/js/tsconfig.json +++ b/js/tsconfig.json @@ -8,5 +8,5 @@ }, "types": [] }, - "include": ["*.ts"] + "include": ["*.ts","test/*.ts"] } \ No newline at end of file diff --git a/js/v2.ts b/js/v2.ts index 8b90d3e..5035ff7 100644 --- a/js/v2.ts +++ b/js/v2.ts @@ -1,4 +1,4 @@ -import { Source, Header, Cache, RangeResponse, Compression } from "./v3"; +import { Source, Header, Cache, RangeResponse, Compression } from "./index"; import { decompressSync } from "fflate"; export const shift = (n: number, shift: number) => {