isard 1.11.0 → 1.12.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.
@@ -42,8 +42,8 @@ export declare const tessUrl: (options: Pick<GeoMapOptions, "tessWasmUrl" | "ass
42
42
  * option, or next to the module (absolute: the workers resolve it against their own URL otherwise) */
43
43
  export declare const gridUrl: (options: Pick<GeoMapOptions, "gridWasmUrl" | "assetsUrl">) => string;
44
44
  /** The decoding workers of 3D Tiles and point clouds, running the full engine's module, unless turned off (`workers:
45
- * false` or 0, or no workers in this environment) */
46
- export declare const startTileLoader: (module: WebAssembly.Module, options: Pick<GeoMapOptions, "workers" | "workerUrl" | "decoders" | "pointsWasmUrl" | "assetsUrl">, engine: Engine) => TileLoader | undefined;
45
+ * false` or 0, or no workers in this environment); without a count, as many as the map's starting quality allows */
46
+ export declare const startTileLoader: (module: WebAssembly.Module, options: Pick<GeoMapOptions, "workers" | "workerUrl" | "decoders" | "pointsWasmUrl" | "assetsUrl" | "quality">, engine: Engine) => TileLoader | undefined;
47
47
  /** The engine of a map that has none, destroyed or while its context is lost: every method a no-op returning
48
48
  * undefined, but the camera (the last one set: the next engine takes it) and the bounds, which late callers read */
49
49
  export declare const destroyedEngine: (camera: Camera) => Engine;
@@ -5,6 +5,7 @@
5
5
  import { defaultWorkerCount } from "./basemap/workerpool.js";
6
6
  import { DEFAULT_DECODERS } from "./decoding/decoders.js";
7
7
  import { TileLoader } from "./decoding/loader.js";
8
+ import { QUALITY, startLevel } from "./map/quality.js";
8
9
  /** The two builds of the engine, each compiled once per page: `core` without 3D Tiles (a third smaller), loaded by
9
10
  * every map; `full` with them, loaded for the first 3D Tiles layer, its module shared with the decoding workers. The
10
11
  * core engine has the same API but the 3D Tiles methods: its class is typed as the full one. */
@@ -146,10 +147,10 @@ export const gridUrl = (options) => {
146
147
  return base ? new URL(url, base).href : String(url);
147
148
  };
148
149
  /** The decoding workers of 3D Tiles and point clouds, running the full engine's module, unless turned off (`workers:
149
- * false` or 0, or no workers in this environment) */
150
+ * false` or 0, or no workers in this environment); without a count, as many as the map's starting quality allows */
150
151
  export const startTileLoader = (module, options, engine) => {
151
152
  const { workers: count, workerUrl, decoders } = options;
152
- const workers = count ?? defaultWorkerCount();
153
+ const workers = count ?? defaultWorkerCount(QUALITY[startLevel(options.quality)].workers);
153
154
  if (workers === false || workers <= 0 || typeof Worker === 'undefined')
154
155
  return undefined;
155
156
  return new TileLoader(module, assetUrl('decoder.worker.js', workerUrl, options.assetsUrl), workers, { ...DEFAULT_DECODERS, ...decoders }, engine.textureFormats(), pointsUrl(options));
@@ -1 +1 @@
1
- {"version":3,"file":"engine-loader.js","sourceRoot":"","sources":["../src/engine-loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The two builds of the engine, downloaded, compiled and instantiated once per page; the decoding workers of 3D Tiles\n * that run the full one; the engine of a destroyed map.\n */\n\nimport { defaultWorkerCount } from './basemap/workerpool.ts';\nimport { DEFAULT_DECODERS } from './decoding/decoders.ts';\nimport { TileLoader } from './decoding/loader.ts';\nimport type { GeoMapOptions } from './types.ts';\nimport type { Camera, Engine } from './wasm/isard.js';\n\n/** The class of an engine build: its constructor and its static `customMatrix` (custom layers) */\nexport type EngineClass = (new (\n canvas: HTMLCanvasElement,\n redraw: () => void,\n) => Engine) &\n Pick<typeof Engine, 'customMatrix' | 'geoidHeight'>;\n\n/** An engine loaded: its compiled module and its class */\nexport interface Bindings {\n module: WebAssembly.Module;\n Engine: EngineClass;\n}\n\n/** `core`: the engine without 3D Tiles; `full`: with them */\nexport type EngineKind = 'core' | 'full';\n\n/** The two builds of the engine, each compiled once per page: `core` without 3D Tiles (a third smaller), loaded by\n * every map; `full` with them, loaded for the first 3D Tiles layer, its module shared with the decoding workers. The\n * core engine has the same API but the 3D Tiles methods: its class is typed as the full one. */\nconst engines: { core?: Promise<Bindings>; full?: Promise<Bindings> } = {};\n/** The modules compiled (downloaded and compiled off the main thread, not instantiated): `tiles3d: 'preload'`\n * compiles the full engine ahead, its first 3D Tiles layer then only instantiates it */\nconst modules: { core?: Promise<WebAssembly.Module>; full?: Promise<WebAssembly.Module> } = {};\n\n/** @internal Forgets the engines loaded (tests) */\nexport const forgetEngines = (): void => {\n (['core', 'full'] as const).forEach((kind) => {\n delete engines[kind];\n delete modules[kind];\n });\n};\n\n/** The files a map loads at run time, next to the module unless given elsewhere */\nexport type AssetFile =\n | 'isard_bg.wasm'\n | 'isard_core_bg.wasm'\n | 'isard_points_bg.wasm'\n | 'isard_tess_bg.wasm'\n | 'isard_grid_bg.wasm'\n | 'decoder.worker.js'\n | 'basemap.worker.js';\n\n/** The folder the assets are served from for the whole page, as `isard/vite` sets it; undefined: next to the module */\nconst pageAssets = (): string | undefined => {\n const url: unknown = Reflect.get(globalThis, 'isardAssetsUrl');\n\n return typeof url === 'string' ? url : undefined;\n};\n\n/**\n * Where a file of isard is loaded from: its own option, else in the folder `assetsUrl` (the option, or the page's\n * as `isard/vite` sets it), else next to the module (`import.meta.url`)\n */\nexport const assetUrl = (\n file: AssetFile,\n explicit: string | URL | undefined,\n assetsUrl?: string | URL,\n): string | URL => {\n if (explicit) return explicit;\n\n const folder = assetsUrl ?? pageAssets();\n\n if (folder) {\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n const dir = String(folder).endsWith('/') ? String(folder) : `${String(folder)}/`;\n\n return new URL(file, base ? new URL(dir, base) : dir);\n }\n switch (file) {\n case 'isard_bg.wasm':\n return new URL('./isard_bg.wasm', import.meta.url);\n case 'isard_core_bg.wasm':\n return new URL('./isard_core_bg.wasm', import.meta.url);\n case 'isard_points_bg.wasm':\n return new URL('./isard_points_bg.wasm', import.meta.url);\n case 'isard_tess_bg.wasm':\n return new URL('./isard_tess_bg.wasm', import.meta.url);\n case 'isard_grid_bg.wasm':\n return new URL('./isard_grid_bg.wasm', import.meta.url);\n case 'decoder.worker.js':\n return new URL('./decoder.worker.js', import.meta.url);\n default:\n return new URL('./basemap.worker.js', import.meta.url);\n }\n};\n\n/** Where a build of the engine is loaded from: the option, the assets' folder, or next to the module */\nexport const engineUrl = (\n kind: EngineKind,\n options: Pick<GeoMapOptions, 'wasmUrl' | 'coreWasmUrl' | 'assetsUrl'>,\n): string | URL => {\n return kind === 'full'\n ? assetUrl('isard_bg.wasm', options.wasmUrl, options.assetsUrl)\n : assetUrl('isard_core_bg.wasm', options.coreWasmUrl, options.assetsUrl);\n};\n\n/** Downloads and compiles a build (once per page, unless it failed: a later call tries again) */\nconst compileEngine = (kind: EngineKind, url: string | URL): Promise<WebAssembly.Module> => {\n const compiled = modules[kind];\n\n if (compiled) return compiled;\n\n const compiling = compile(url).catch((error: unknown) => {\n // A later call tries again (a network error, a wrong URL fixed)\n delete modules[kind];\n throw error;\n });\n\n modules[kind] = compiling;\n\n return compiling;\n};\n\n/** A build compiled and instantiated with its bindings (once per page, unless it failed) */\nexport const loadEngine = (kind: EngineKind, url: string | URL): Promise<Bindings> => {\n const loaded = engines[kind];\n\n if (loaded) return loaded;\n\n const loading = (async () => {\n // The bindings by dynamic import: an application bundles the ones it loads only\n const [module, bindings] = await Promise.all([\n compileEngine(kind, url),\n kind === 'core' ? import('./wasm/isard_core.js') : import('./wasm/isard.js'),\n ]);\n\n await bindings.default({ module_or_path: module });\n\n return { module, Engine: bindings.Engine as unknown as EngineClass };\n })().catch((error: unknown) => {\n delete engines[kind];\n throw error;\n });\n\n engines[kind] = loading;\n\n return loading;\n};\n\n/** The full engine for a map on the core one, resolved in a task of its own, not in the one that instantiated it:\n * the map rebuilt on it there, two shorter tasks */\nexport const loadFullEngineLater = (url: string | URL): Promise<Bindings> => {\n return loadEngine('full', url).then(\n (bindings) => new Promise<Bindings>((resolve) => setTimeout(() => resolve(bindings), 0)),\n );\n};\n\n/** Downloads and compiles the full engine when the page is idle, without running it; a failure is left to the first\n * 3D Tiles layer, which tries again */\nexport const preloadFullEngine = (url: string | URL, wanted: () => boolean): void => {\n const start = () => {\n if (wanted()) compileEngine('full', url).catch(() => undefined);\n };\n\n if (typeof requestIdleCallback === 'function') requestIdleCallback(start, { timeout: 2000 });\n else setTimeout(start, 0);\n};\n\nconst compile = async (url: string | URL): Promise<WebAssembly.Module> => {\n const response = await fetch(url);\n\n // The engine named: a page fails here first\n if (!response.ok) throw new Error(`isard: failed to load the engine from ${url}: ${response.status}`);\n try {\n return await WebAssembly.compileStreaming(response.clone());\n } catch {\n // Servers that do not send application/wasm\n return WebAssembly.compile(await response.arrayBuffer());\n }\n};\n\n/** Where the workers load the point cloud module from (`isard_points_bg.wasm`, the LAZ decoder): the option, or next\n * to the module; absolute, the workers being elsewhere */\nexport const pointsUrl = (options: Pick<GeoMapOptions, 'pointsWasmUrl' | 'assetsUrl'>): string => {\n const url = assetUrl('isard_points_bg.wasm', options.pointsWasmUrl, options.assetsUrl);\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n\n return base ? new URL(url, base).href : String(url);\n};\n\n/** Where the basemap workers load the tessellation module from (`isard_tess_bg.wasm`: the vector tiles of `vectors()`\n * made ready for the GPU off the main thread): the option, or next to the module; absolute, the workers being\n * elsewhere */\nexport const tessUrl = (options: Pick<GeoMapOptions, 'tessWasmUrl' | 'assetsUrl'>): string => {\n const url = assetUrl('isard_tess_bg.wasm', options.tessWasmUrl, options.assetsUrl);\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n\n return base ? new URL(url, base).href : String(url);\n};\n\n/** Where the workers load the grid module from (`isard_grid_bg.wasm`: GRIB2 and NetCDF files read into grids): the\n * option, or next to the module (absolute: the workers resolve it against their own URL otherwise) */\nexport const gridUrl = (options: Pick<GeoMapOptions, 'gridWasmUrl' | 'assetsUrl'>): string => {\n const url = assetUrl('isard_grid_bg.wasm', options.gridWasmUrl, options.assetsUrl);\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n\n return base ? new URL(url, base).href : String(url);\n};\n\n/** The decoding workers of 3D Tiles and point clouds, running the full engine's module, unless turned off (`workers:\n * false` or 0, or no workers in this environment) */\nexport const startTileLoader = (\n module: WebAssembly.Module,\n options: Pick<GeoMapOptions, 'workers' | 'workerUrl' | 'decoders' | 'pointsWasmUrl' | 'assetsUrl'>,\n engine: Engine,\n): TileLoader | undefined => {\n const { workers: count, workerUrl, decoders } = options;\n const workers = count ?? defaultWorkerCount();\n\n if (workers === false || workers <= 0 || typeof Worker === 'undefined') return undefined;\n\n return new TileLoader(\n module,\n assetUrl('decoder.worker.js', workerUrl, options.assetsUrl),\n workers,\n { ...DEFAULT_DECODERS, ...decoders },\n engine.textureFormats(),\n pointsUrl(options),\n );\n};\n\n/** The engine of a map that has none, destroyed or while its context is lost: every method a no-op returning\n * undefined, but the camera (the last one set: the next engine takes it) and the bounds, which late callers read */\nexport const destroyedEngine = (camera: Camera): Engine => {\n const state = { camera };\n\n return new Proxy(\n {},\n {\n get: (_, name) => {\n if (name === 'camera') return () => state.camera;\n if (name === 'setCamera') {\n return (lon: number, lat: number, zoom: number, pitch: number, bearing: number) => {\n state.camera = { ...state.camera, center: [lon, lat], zoom, pitch, bearing };\n };\n }\n if (name === 'bounds') return () => Float64Array.of(-180, -85, 180, 85);\n\n return () => undefined;\n },\n },\n ) as Engine;\n};\n"]}
1
+ {"version":3,"file":"engine-loader.js","sourceRoot":"","sources":["../src/engine-loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAoBvD;;gGAEgG;AAChG,MAAM,OAAO,GAA2D,EAAE,CAAC;AAC3E;wFACwF;AACxF,MAAM,OAAO,GAA+E,EAAE,CAAC;AAE/F,mDAAmD;AACnD,MAAM,CAAC,MAAM,aAAa,GAAG,GAAS,EAAE;IACrC,CAAC,MAAM,EAAE,MAAM,CAAW,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAC3C,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;QACrB,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAYF,uHAAuH;AACvH,MAAM,UAAU,GAAG,GAAuB,EAAE;IAC1C,MAAM,GAAG,GAAY,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC;IAE/D,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AACnD,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,IAAe,EACf,QAAkC,EAClC,SAAwB,EACV,EAAE;IAChB,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,MAAM,GAAG,SAAS,IAAI,UAAU,EAAE,CAAC;IAEzC,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,IAAI,GAAG,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC5E,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC;QAEjF,OAAO,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACxD,CAAC;IACD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,eAAe;YAClB,OAAO,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrD,KAAK,oBAAoB;YACvB,OAAO,IAAI,GAAG,CAAC,sBAAsB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1D,KAAK,sBAAsB;YACzB,OAAO,IAAI,GAAG,CAAC,wBAAwB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5D,KAAK,oBAAoB;YACvB,OAAO,IAAI,GAAG,CAAC,sBAAsB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1D,KAAK,oBAAoB;YACvB,OAAO,IAAI,GAAG,CAAC,sBAAsB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1D,KAAK,mBAAmB;YACtB,OAAO,IAAI,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzD;YACE,OAAO,IAAI,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC,CAAC;AAEF,wGAAwG;AACxG,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,IAAgB,EAChB,OAAqE,EACvD,EAAE;IAChB,OAAO,IAAI,KAAK,MAAM;QACpB,CAAC,CAAC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC;QAC/D,CAAC,CAAC,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;AAC7E,CAAC,CAAC;AAEF,iGAAiG;AACjG,MAAM,aAAa,GAAG,CAAC,IAAgB,EAAE,GAAiB,EAA+B,EAAE;IACzF,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/B,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QACtD,gEAAgE;QAChE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;QACrB,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;IAE1B,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF,4FAA4F;AAC5F,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAgB,EAAE,GAAiB,EAAqB,EAAE;IACnF,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,OAAO,GAAG,CAAC,KAAK,IAAI,EAAE;QAC1B,gFAAgF;QAChF,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC3C,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC;YACxB,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC;SAC7E,CAAC,CAAC;QAEH,MAAM,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC;QAEnD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAgC,EAAE,CAAC;IACvE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAC5B,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;QACrB,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;IAExB,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF;oDACoD;AACpD,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,GAAiB,EAAqB,EAAE;IAC1E,OAAO,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,CACjC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,OAAO,CAAW,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CACzF,CAAC;AACJ,CAAC,CAAC;AAEF;uCACuC;AACvC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,GAAiB,EAAE,MAAqB,EAAQ,EAAE;IAClF,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,IAAI,MAAM,EAAE;YAAE,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAClE,CAAC,CAAC;IAEF,IAAI,OAAO,mBAAmB,KAAK,UAAU;QAAE,mBAAmB,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;;QACxF,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AAC5B,CAAC,CAAC;AAEF,MAAM,OAAO,GAAG,KAAK,EAAE,GAAiB,EAA+B,EAAE;IACvE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IAElC,4CAA4C;IAC5C,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,GAAG,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACtG,IAAI,CAAC;QACH,OAAO,MAAM,WAAW,CAAC,gBAAgB,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,4CAA4C;QAC5C,OAAO,WAAW,CAAC,OAAO,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC,CAAC;AAEF;0DAC0D;AAC1D,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,OAA2D,EAAU,EAAE;IAC/F,MAAM,GAAG,GAAG,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IACvF,MAAM,IAAI,GAAG,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;IAE5E,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC,CAAC;AAEF;;eAEe;AACf,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,OAAyD,EAAU,EAAE;IAC3F,MAAM,GAAG,GAAG,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IACnF,MAAM,IAAI,GAAG,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;IAE5E,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC,CAAC;AAEF;sGACsG;AACtG,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,OAAyD,EAAU,EAAE;IAC3F,MAAM,GAAG,GAAG,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IACnF,MAAM,IAAI,GAAG,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;IAE5E,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC,CAAC;AAEF;oHACoH;AACpH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,MAA0B,EAC1B,OAA8G,EAC9G,MAAc,EACU,EAAE;IAC1B,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IACxD,MAAM,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAE1F,IAAI,OAAO,KAAK,KAAK,IAAI,OAAO,IAAI,CAAC,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,SAAS,CAAC;IAEzF,OAAO,IAAI,UAAU,CACnB,MAAM,EACN,QAAQ,CAAC,mBAAmB,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,EAC3D,OAAO,EACP,EAAE,GAAG,gBAAgB,EAAE,GAAG,QAAQ,EAAE,EACpC,MAAM,CAAC,cAAc,EAAE,EACvB,SAAS,CAAC,OAAO,CAAC,CACnB,CAAC;AACJ,CAAC,CAAC;AAEF;oHACoH;AACpH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAc,EAAU,EAAE;IACxD,MAAM,KAAK,GAAG,EAAE,MAAM,EAAE,CAAC;IAEzB,OAAO,IAAI,KAAK,CACd,EAAE,EACF;QACE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE;YACf,IAAI,IAAI,KAAK,QAAQ;gBAAE,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;YACjD,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;gBACzB,OAAO,CAAC,GAAW,EAAE,GAAW,EAAE,IAAY,EAAE,KAAa,EAAE,OAAe,EAAE,EAAE;oBAChF,KAAK,CAAC,MAAM,GAAG,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;gBAC/E,CAAC,CAAC;YACJ,CAAC;YACD,IAAI,IAAI,KAAK,QAAQ;gBAAE,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YAExE,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC;QACzB,CAAC;KACF,CACQ,CAAC;AACd,CAAC,CAAC","sourcesContent":["/**\n * The two builds of the engine, downloaded, compiled and instantiated once per page; the decoding workers of 3D Tiles\n * that run the full one; the engine of a destroyed map.\n */\n\nimport { defaultWorkerCount } from './basemap/workerpool.ts';\nimport { DEFAULT_DECODERS } from './decoding/decoders.ts';\nimport { TileLoader } from './decoding/loader.ts';\nimport { QUALITY, startLevel } from './map/quality.ts';\nimport type { GeoMapOptions } from './types.ts';\nimport type { Camera, Engine } from './wasm/isard.js';\n\n/** The class of an engine build: its constructor and its static `customMatrix` (custom layers) */\nexport type EngineClass = (new (\n canvas: HTMLCanvasElement,\n redraw: () => void,\n) => Engine) &\n Pick<typeof Engine, 'customMatrix' | 'geoidHeight'>;\n\n/** An engine loaded: its compiled module and its class */\nexport interface Bindings {\n module: WebAssembly.Module;\n Engine: EngineClass;\n}\n\n/** `core`: the engine without 3D Tiles; `full`: with them */\nexport type EngineKind = 'core' | 'full';\n\n/** The two builds of the engine, each compiled once per page: `core` without 3D Tiles (a third smaller), loaded by\n * every map; `full` with them, loaded for the first 3D Tiles layer, its module shared with the decoding workers. The\n * core engine has the same API but the 3D Tiles methods: its class is typed as the full one. */\nconst engines: { core?: Promise<Bindings>; full?: Promise<Bindings> } = {};\n/** The modules compiled (downloaded and compiled off the main thread, not instantiated): `tiles3d: 'preload'`\n * compiles the full engine ahead, its first 3D Tiles layer then only instantiates it */\nconst modules: { core?: Promise<WebAssembly.Module>; full?: Promise<WebAssembly.Module> } = {};\n\n/** @internal Forgets the engines loaded (tests) */\nexport const forgetEngines = (): void => {\n (['core', 'full'] as const).forEach((kind) => {\n delete engines[kind];\n delete modules[kind];\n });\n};\n\n/** The files a map loads at run time, next to the module unless given elsewhere */\nexport type AssetFile =\n | 'isard_bg.wasm'\n | 'isard_core_bg.wasm'\n | 'isard_points_bg.wasm'\n | 'isard_tess_bg.wasm'\n | 'isard_grid_bg.wasm'\n | 'decoder.worker.js'\n | 'basemap.worker.js';\n\n/** The folder the assets are served from for the whole page, as `isard/vite` sets it; undefined: next to the module */\nconst pageAssets = (): string | undefined => {\n const url: unknown = Reflect.get(globalThis, 'isardAssetsUrl');\n\n return typeof url === 'string' ? url : undefined;\n};\n\n/**\n * Where a file of isard is loaded from: its own option, else in the folder `assetsUrl` (the option, or the page's\n * as `isard/vite` sets it), else next to the module (`import.meta.url`)\n */\nexport const assetUrl = (\n file: AssetFile,\n explicit: string | URL | undefined,\n assetsUrl?: string | URL,\n): string | URL => {\n if (explicit) return explicit;\n\n const folder = assetsUrl ?? pageAssets();\n\n if (folder) {\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n const dir = String(folder).endsWith('/') ? String(folder) : `${String(folder)}/`;\n\n return new URL(file, base ? new URL(dir, base) : dir);\n }\n switch (file) {\n case 'isard_bg.wasm':\n return new URL('./isard_bg.wasm', import.meta.url);\n case 'isard_core_bg.wasm':\n return new URL('./isard_core_bg.wasm', import.meta.url);\n case 'isard_points_bg.wasm':\n return new URL('./isard_points_bg.wasm', import.meta.url);\n case 'isard_tess_bg.wasm':\n return new URL('./isard_tess_bg.wasm', import.meta.url);\n case 'isard_grid_bg.wasm':\n return new URL('./isard_grid_bg.wasm', import.meta.url);\n case 'decoder.worker.js':\n return new URL('./decoder.worker.js', import.meta.url);\n default:\n return new URL('./basemap.worker.js', import.meta.url);\n }\n};\n\n/** Where a build of the engine is loaded from: the option, the assets' folder, or next to the module */\nexport const engineUrl = (\n kind: EngineKind,\n options: Pick<GeoMapOptions, 'wasmUrl' | 'coreWasmUrl' | 'assetsUrl'>,\n): string | URL => {\n return kind === 'full'\n ? assetUrl('isard_bg.wasm', options.wasmUrl, options.assetsUrl)\n : assetUrl('isard_core_bg.wasm', options.coreWasmUrl, options.assetsUrl);\n};\n\n/** Downloads and compiles a build (once per page, unless it failed: a later call tries again) */\nconst compileEngine = (kind: EngineKind, url: string | URL): Promise<WebAssembly.Module> => {\n const compiled = modules[kind];\n\n if (compiled) return compiled;\n\n const compiling = compile(url).catch((error: unknown) => {\n // A later call tries again (a network error, a wrong URL fixed)\n delete modules[kind];\n throw error;\n });\n\n modules[kind] = compiling;\n\n return compiling;\n};\n\n/** A build compiled and instantiated with its bindings (once per page, unless it failed) */\nexport const loadEngine = (kind: EngineKind, url: string | URL): Promise<Bindings> => {\n const loaded = engines[kind];\n\n if (loaded) return loaded;\n\n const loading = (async () => {\n // The bindings by dynamic import: an application bundles the ones it loads only\n const [module, bindings] = await Promise.all([\n compileEngine(kind, url),\n kind === 'core' ? import('./wasm/isard_core.js') : import('./wasm/isard.js'),\n ]);\n\n await bindings.default({ module_or_path: module });\n\n return { module, Engine: bindings.Engine as unknown as EngineClass };\n })().catch((error: unknown) => {\n delete engines[kind];\n throw error;\n });\n\n engines[kind] = loading;\n\n return loading;\n};\n\n/** The full engine for a map on the core one, resolved in a task of its own, not in the one that instantiated it:\n * the map rebuilt on it there, two shorter tasks */\nexport const loadFullEngineLater = (url: string | URL): Promise<Bindings> => {\n return loadEngine('full', url).then(\n (bindings) => new Promise<Bindings>((resolve) => setTimeout(() => resolve(bindings), 0)),\n );\n};\n\n/** Downloads and compiles the full engine when the page is idle, without running it; a failure is left to the first\n * 3D Tiles layer, which tries again */\nexport const preloadFullEngine = (url: string | URL, wanted: () => boolean): void => {\n const start = () => {\n if (wanted()) compileEngine('full', url).catch(() => undefined);\n };\n\n if (typeof requestIdleCallback === 'function') requestIdleCallback(start, { timeout: 2000 });\n else setTimeout(start, 0);\n};\n\nconst compile = async (url: string | URL): Promise<WebAssembly.Module> => {\n const response = await fetch(url);\n\n // The engine named: a page fails here first\n if (!response.ok) throw new Error(`isard: failed to load the engine from ${url}: ${response.status}`);\n try {\n return await WebAssembly.compileStreaming(response.clone());\n } catch {\n // Servers that do not send application/wasm\n return WebAssembly.compile(await response.arrayBuffer());\n }\n};\n\n/** Where the workers load the point cloud module from (`isard_points_bg.wasm`, the LAZ decoder): the option, or next\n * to the module; absolute, the workers being elsewhere */\nexport const pointsUrl = (options: Pick<GeoMapOptions, 'pointsWasmUrl' | 'assetsUrl'>): string => {\n const url = assetUrl('isard_points_bg.wasm', options.pointsWasmUrl, options.assetsUrl);\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n\n return base ? new URL(url, base).href : String(url);\n};\n\n/** Where the basemap workers load the tessellation module from (`isard_tess_bg.wasm`: the vector tiles of `vectors()`\n * made ready for the GPU off the main thread): the option, or next to the module; absolute, the workers being\n * elsewhere */\nexport const tessUrl = (options: Pick<GeoMapOptions, 'tessWasmUrl' | 'assetsUrl'>): string => {\n const url = assetUrl('isard_tess_bg.wasm', options.tessWasmUrl, options.assetsUrl);\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n\n return base ? new URL(url, base).href : String(url);\n};\n\n/** Where the workers load the grid module from (`isard_grid_bg.wasm`: GRIB2 and NetCDF files read into grids): the\n * option, or next to the module (absolute: the workers resolve it against their own URL otherwise) */\nexport const gridUrl = (options: Pick<GeoMapOptions, 'gridWasmUrl' | 'assetsUrl'>): string => {\n const url = assetUrl('isard_grid_bg.wasm', options.gridWasmUrl, options.assetsUrl);\n const base = typeof document === 'undefined' ? undefined : document.baseURI;\n\n return base ? new URL(url, base).href : String(url);\n};\n\n/** The decoding workers of 3D Tiles and point clouds, running the full engine's module, unless turned off (`workers:\n * false` or 0, or no workers in this environment); without a count, as many as the map's starting quality allows */\nexport const startTileLoader = (\n module: WebAssembly.Module,\n options: Pick<GeoMapOptions, 'workers' | 'workerUrl' | 'decoders' | 'pointsWasmUrl' | 'assetsUrl' | 'quality'>,\n engine: Engine,\n): TileLoader | undefined => {\n const { workers: count, workerUrl, decoders } = options;\n const workers = count ?? defaultWorkerCount(QUALITY[startLevel(options.quality)].workers);\n\n if (workers === false || workers <= 0 || typeof Worker === 'undefined') return undefined;\n\n return new TileLoader(\n module,\n assetUrl('decoder.worker.js', workerUrl, options.assetsUrl),\n workers,\n { ...DEFAULT_DECODERS, ...decoders },\n engine.textureFormats(),\n pointsUrl(options),\n );\n};\n\n/** The engine of a map that has none, destroyed or while its context is lost: every method a no-op returning\n * undefined, but the camera (the last one set: the next engine takes it) and the bounds, which late callers read */\nexport const destroyedEngine = (camera: Camera): Engine => {\n const state = { camera };\n\n return new Proxy(\n {},\n {\n get: (_, name) => {\n if (name === 'camera') return () => state.camera;\n if (name === 'setCamera') {\n return (lon: number, lat: number, zoom: number, pitch: number, bearing: number) => {\n state.camera = { ...state.camera, center: [lon, lat], zoom, pitch, bearing };\n };\n }\n if (name === 'bounds') return () => Float64Array.of(-180, -85, 180, 85);\n\n return () => undefined;\n },\n },\n ) as Engine;\n};\n"]}
Binary file
Binary file
Binary file
Binary file
@@ -28,12 +28,18 @@ export class VectorLayer extends Layer {
28
28
  restyle;
29
29
  /** @internal Asks the workers for the tiles in view again (set by its `VectorTiles`): an engine made anew has none */
30
30
  recut;
31
+ /** @internal Asks for the tiles in view (set by its `VectorTiles`): those of a new quality */
32
+ refresh;
31
33
  /** The 3D buildings drawn in place of its raised ones (`vectors({ buildings3d })`), for `map.pickFeature` */
32
34
  buildings3d;
33
35
  /** @internal */
34
36
  constructor(map) {
35
37
  super(map);
36
38
  }
39
+ /** @internal Its tiles as far as the map's quality reaches */
40
+ qualityChanged() {
41
+ this.refresh?.();
42
+ }
37
43
  /** Resolves once the style is loaded, its layers drawn known (`layers`), and the map has drawn the layer; rejected
38
44
  * if the style fails */
39
45
  get ready() {
@@ -1 +1 @@
1
- {"version":3,"file":"vectors.js","sourceRoot":"","sources":["../../src/layers/vectors.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The fills and lines of a MapLibre style drawn as geometry, tile by tile (`VectorTiles.vectors`), instead of into the\n * images of a raster layer: sharp at any zoom and pitch, on the relief, picked by feature, restyled without cutting the\n * tiles again. The workers cut each vector tile into polygons and lines and style its features; the engine draws the\n * style's layers in their order, each over its zoom range.\n */\n\nimport type { LayerHost } from '../types.ts';\nimport { FLOATS } from '../util/style-floats.ts';\nimport type { Engine } from '../wasm/isard.js';\nimport type { TileVectors } from '../workers/basemap/protocol.ts';\nimport { type Feature, type Size, stops } from './features.ts';\nimport { Layer } from './layers.ts';\nimport type { Tiles3dLayer } from './tiles3d.ts';\n\n/** A style layer as the engine draws it: its kind, zoom range, visibility and dashes (dash, gap, dash, gap, in line\n * widths; zeros: solid) */\nexport interface VectorSublayer {\n /** The style layer's id */\n id: string;\n /** Its source layer, if any (not for a background) */\n sourceLayer: string | undefined;\n kind: 'fill' | 'line' | 'extrusion' | 'circle';\n minZoom: number;\n maxZoom: number;\n visible: boolean;\n /** Its opacity when it depends on the zoom only, evaluated at the camera's zoom (else 1: the features' colors hold\n * it) */\n opacity: Size;\n dash: [number, number, number, number];\n /** The caps of its lines' ends (`line-cap`) */\n cap: 'butt' | 'round' | 'square';\n /** The joins of its lines' pieces (`line-join`), a miter longer than `miterLimit` line widths bevelled\n * (`line-miter-limit`); round and 2 if left out */\n join?: 'miter' | 'bevel' | 'round';\n miterLimit?: number;\n /** How far its fills or lines move on screen (`fill-translate`, `line-translate`: CSS pixels, x right, y down),\n * turning with the map or staying on the screen (`*-translate-anchor`); none and `map` if left out */\n translate?: [number, number];\n translateAnchor?: 'map' | 'viewport';\n /** Its fills have patterns (`fill-pattern`, `background-pattern`): over the relief, the engine finds the ground under\n * them */\n patterned?: boolean;\n /** Its lines glow at night (the streets: its id names a road, not its casing; `setSun`) */\n lit: boolean;\n}\n\n/** The properties of a picked feature, with the style layer that drew it */\nexport type VectorFeature = Feature<Record<string, unknown>> & { layer: string; sourceLayer: string | undefined };\n\n/** The main thread's time a frame gives to uploading tiles (ms): tiles arriving together are uploaded over several\n * frames, not all in the one (copying a tile's buffers to the GPU takes milliseconds) */\nconst UPLOAD_MS = 4;\n\ninterface Tile {\n /** Its number in the engine: tiles are numbered for picking in this order */\n key: number;\n /** What picking needs (its geometry and styles are the engine's only: an engine made anew asks the tiles again) */\n vectors: Pick<TileVectors, 'properties' | 'sublayer'>;\n}\n\nexport class VectorLayer extends Layer {\n private readonly tiles = new Map<string, Tile>();\n /** The tiles waiting for their upload (`UPLOAD_MS` a frame), each with what resolves its `setTile`; `sent`: in the\n * engine already, its blocks still uploading */\n private readonly queue = new Map<string, { vectors: TileVectors; uploaded: () => void; sent?: number }>();\n private flushing = false;\n private sublayers: VectorSublayer[] = [];\n private nextKey = 0;\n /** The whole layer shown (`setVisible`), over each style layer's visibility */\n private shown = true;\n /** Its buildings' walls show their windows (`setFacades`) */\n private facades = false;\n /** @internal Resolved once the style is loaded and its layers drawn known (set by its `VectorTiles`) */\n styled: Promise<void> = Promise.resolve();\n /** @internal Changes a property of a style layer drawn (set by its `VectorTiles`) */\n restyle: ((layer: string, group: 'paint' | 'layout', name: string, value: unknown) => void) | undefined;\n /** @internal Asks the workers for the tiles in view again (set by its `VectorTiles`): an engine made anew has none */\n recut: (() => void) | undefined;\n /** The 3D buildings drawn in place of its raised ones (`vectors({ buildings3d })`), for `map.pickFeature` */\n buildings3d: Tiles3dLayer | undefined;\n\n /** @internal */\n constructor(map: LayerHost) {\n super(map);\n }\n\n /** Resolves once the style is loaded, its layers drawn known (`layers`), and the map has drawn the layer; rejected\n * if the style fails */\n override get ready(): Promise<void> {\n return this.styled.then(() => super.ready);\n }\n\n /** The style layers drawn, in order */\n get layers(): readonly VectorSublayer[] {\n return this.sublayers;\n }\n\n /** Keys of the tiles held (`z/x/y`) */\n get tileKeys(): string[] {\n return [...this.tiles.keys()];\n }\n\n /** @internal Sets the style layers drawn, in order (the tiles' sublayers) */\n setSublayers(sublayers: VectorSublayer[]): void {\n this.sublayers = sublayers;\n this.sendSublayers(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n /** @internal Adds or replaces a tile, cut by the workers (and made ready for the GPU there, with its mesh): uploaded\n * on a coming frame, within its share of the frame (`UPLOAD_MS`); resolves once it is (or once dropped meanwhile) */\n setTile(tile: string, vectors: TileVectors): Promise<void> {\n if (this.removed) return Promise.resolve();\n // The map not idle until it is uploaded\n return this.map.track(\n new Promise((uploaded) => {\n // A newer cut of a tile still waiting takes its place\n this.queue.get(tile)?.uploaded();\n this.queue.set(tile, { vectors, uploaded });\n this.flushSoon();\n }),\n );\n }\n\n /** Uploads the waiting tiles on the next frame */\n private flushSoon(): void {\n if (this.flushing) return;\n this.flushing = true;\n requestAnimationFrame(() => {\n this.flushing = false;\n this.flush();\n });\n }\n\n /** Uploads waiting tiles for `UPLOAD_MS` at most (one at least, or a part of its blocks), the rest on the next\n * frames; a tile's `setTile` resolves once its blocks are all there */\n private flush(): void {\n // Removed meanwhile, or between two engines (the new one asks for the tiles again)\n if (this.id < 0) return;\n\n const start = performance.now();\n const within = () => performance.now() - start <= UPLOAD_MS;\n\n for (const [tile, waiting] of this.queue) {\n waiting.sent ??= this.upload(tile, waiting.vectors);\n\n // A large tile's blocks (a pitched view's far tiles of a city: 10 MB and more), a part at a time\n let left = this.map.engine.uploadVectorTile(this.id, waiting.sent);\n\n while (left && within()) left = this.map.engine.uploadVectorTile(this.id, waiting.sent);\n if (left) break;\n this.queue.delete(tile);\n waiting.uploaded();\n if (!within()) break;\n }\n if (this.queue.size > 0) this.flushSoon();\n this.map.requestRender();\n }\n\n /** Sends a tile to the engine (its blocks' first part); its key */\n private upload(tile: string, vectors: TileVectors): number {\n const key = this.tiles.get(tile)?.key ?? this.nextKey++;\n const { properties, sublayer } = vectors;\n\n this.tiles.set(tile, { key, vectors: { properties, sublayer } });\n this.sendTile(this.map.engine, this.id, key, vectors);\n\n return key;\n }\n\n /** @internal New styles of a tile's features, as the workers evaluated them (the same features) */\n setTileStyles(tile: string, styles: Float32Array): void {\n const waiting = this.queue.get(tile);\n\n // Not uploaded yet: uploaded with them\n if (waiting && waiting.sent === undefined) {\n if (styles.length === waiting.vectors.properties.length * FLOATS) waiting.vectors.styles = styles;\n\n return;\n }\n\n const t = this.tiles.get(tile);\n\n if (!t || styles.length !== t.vectors.properties.length * FLOATS) return;\n this.map.engine.setFeatureStyle(this.id, styles, t.key);\n this.map.requestRender();\n }\n\n override remove(): void {\n super.remove();\n this.dispose();\n }\n\n /** @internal The tiles waiting resolved (dropped), none held */\n override dispose(): void {\n this.queue.forEach((waiting) => {\n waiting.uploaded();\n });\n this.queue.clear();\n this.tiles.clear();\n }\n\n /** @internal */\n removeTile(tile: string): void {\n this.queue.get(tile)?.uploaded();\n this.queue.delete(tile);\n\n const t = this.tiles.get(tile);\n\n if (!t) return;\n this.tiles.delete(tile);\n this.map.engine.removeVectorTile(this.id, t.key);\n this.map.requestRender();\n }\n\n /** The feature of a picked index (no geometry: the tiles hold it cut), its properties and style layer. Tiles are\n * numbered one after the other, in the order they were first added */\n featureAt(index: number): VectorFeature | undefined {\n const tiles = [...this.tiles.values()].sort((a, b) => a.key - b.key);\n // The tile holding the index, and the index among its features (one pass, the features of the tiles before\n // taken off)\n const { tile, rest } = tiles.reduce<{ tile?: Tile; rest: number }>(\n (found, t) => {\n if (found.tile) return found;\n\n const count = t.vectors.properties.length;\n\n return found.rest < count ? { tile: t, rest: found.rest } : { rest: found.rest - count };\n },\n { rest: index },\n );\n\n if (!tile) return undefined;\n\n const properties = tile.vectors.properties[rest];\n const sublayer = this.sublayers[tile.vectors.sublayer[rest] ?? -1];\n\n if (properties === undefined || !sublayer) return undefined;\n\n return { type: 'Feature', properties, geometry: null, layer: sublayer.id, sourceLayer: sublayer.sourceLayer };\n }\n\n /** Changes a paint property of a style layer drawn, as MapLibre's `setPaintProperty`: the tiles are restyled, not cut\n * again */\n setPaintProperty(layer: string, name: string, value: unknown): void {\n this.restyle?.(layer, 'paint', name, value);\n }\n\n /** Changes a layout property of a style layer drawn (`visibility`: shown or hidden at once), as MapLibre's\n * `setLayoutProperty` */\n setLayoutProperty(layer: string, name: string, value: unknown): void {\n this.restyle?.(layer, 'layout', name, value);\n }\n\n /** Whether its buildings' walls show their windows: glass by day, some lit at night (only the lit ones without) */\n setFacades(facades: boolean): void {\n this.facades = facades;\n this.map.engine.setFacades(this.id, facades);\n // Its 3D buildings' walls too\n this.buildings3d?.setFacades(facades);\n this.map.requestRender();\n }\n\n setVisible(visible: boolean): void {\n this.shown = visible;\n this.sendSublayers(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n private sendSublayers(engine: Engine, id: number): void {\n const s = this.sublayers;\n\n engine.setVectorSublayers(\n id,\n Uint8Array.from(s, (l) => ({ fill: 0, line: 1, extrusion: 2, circle: 3 })[l.kind]),\n Float64Array.from(s.flatMap((l) => [l.minZoom, l.maxZoom])),\n Uint8Array.from(s, (l) => (l.visible && this.shown ? 1 : 0)),\n Float32Array.from(s.flatMap((l) => l.dash)),\n Float32Array.from(s.flatMap((l) => stops(l.opacity))),\n Uint8Array.from(s, (l) => ({ butt: 0, round: 1, square: 2 })[l.cap]),\n Uint8Array.from(s, (l) => (l.lit ? 1 : 0)),\n Float32Array.from(s.flatMap((l) => [{ round: 0, miter: 1, bevel: 2 }[l.join ?? 'round'], l.miterLimit ?? 2])),\n Float32Array.from(s.flatMap((l) => [...(l.translate ?? [0, 0]), l.translateAnchor === 'viewport' ? 1 : 0])),\n Uint8Array.from(s, (l) => (l.patterned ? 1 : 0)),\n );\n }\n\n /** A tile to the engine: its mesh uploaded as it is, or without one its geometry, which the engine makes ready */\n private sendTile(engine: Engine, id: number, key: number, vectors: TileVectors): void {\n const { fills, lines, circles, styles, properties, mesh } = vectors;\n\n if (mesh) {\n engine.setVectorTileMesh(\n id,\n key,\n fills.points,\n fills.ringStart,\n fills.polygonStart,\n fills.feature,\n fills.fillStart,\n mesh.vertices,\n mesh.indices,\n mesh.fillRanges,\n mesh.prism,\n mesh.pieces,\n mesh.lineTable,\n mesh.lineRanges,\n mesh.blocks,\n mesh.blockIndices,\n mesh.blockRanges,\n mesh.bounds,\n properties.length,\n );\n } else {\n engine.setVectorTile(\n id,\n key,\n fills.points,\n fills.ringStart,\n fills.polygonStart,\n fills.feature,\n fills.fillStart,\n lines.points,\n lines.start,\n lines.feature,\n lines.lineStart,\n properties.length,\n vectors.tile ?? new Float64Array(),\n fills.roofs ?? new Uint8Array(),\n fills.roofHeights ?? new Float32Array(),\n fills.roofOutlines ?? new Float64Array(),\n fills.roofOutlineStart ?? new Uint32Array(),\n fills.roofMetres ?? 0,\n );\n }\n // The circles' points, once the tile is there\n if (circles) engine.setVectorTilePoints(id, key, circles.points, circles.feature, circles.circleStart);\n engine.setFeatureStyle(id, styles, key);\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const id = engine.addVectorTiles();\n\n this.sendSublayers(engine, id);\n engine.setFacades(id, this.facades);\n // An engine made anew (after a context loss, or the one with 3D Tiles): its tiles cut again by the workers, once\n // the layer has its id there. Keeping their geometry here would double the memory they take\n this.dispose();\n queueMicrotask(() => this.recut?.());\n\n return id;\n }\n}\n"]}
1
+ {"version":3,"file":"vectors.js","sourceRoot":"","sources":["../../src/layers/vectors.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The fills and lines of a MapLibre style drawn as geometry, tile by tile (`VectorTiles.vectors`), instead of into the\n * images of a raster layer: sharp at any zoom and pitch, on the relief, picked by feature, restyled without cutting the\n * tiles again. The workers cut each vector tile into polygons and lines and style its features; the engine draws the\n * style's layers in their order, each over its zoom range.\n */\n\nimport type { LayerHost } from '../types.ts';\nimport { FLOATS } from '../util/style-floats.ts';\nimport type { Engine } from '../wasm/isard.js';\nimport type { TileVectors } from '../workers/basemap/protocol.ts';\nimport { type Feature, type Size, stops } from './features.ts';\nimport { Layer } from './layers.ts';\nimport type { Tiles3dLayer } from './tiles3d.ts';\n\n/** A style layer as the engine draws it: its kind, zoom range, visibility and dashes (dash, gap, dash, gap, in line\n * widths; zeros: solid) */\nexport interface VectorSublayer {\n /** The style layer's id */\n id: string;\n /** Its source layer, if any (not for a background) */\n sourceLayer: string | undefined;\n kind: 'fill' | 'line' | 'extrusion' | 'circle';\n minZoom: number;\n maxZoom: number;\n visible: boolean;\n /** Its opacity when it depends on the zoom only, evaluated at the camera's zoom (else 1: the features' colors hold\n * it) */\n opacity: Size;\n dash: [number, number, number, number];\n /** The caps of its lines' ends (`line-cap`) */\n cap: 'butt' | 'round' | 'square';\n /** The joins of its lines' pieces (`line-join`), a miter longer than `miterLimit` line widths bevelled\n * (`line-miter-limit`); round and 2 if left out */\n join?: 'miter' | 'bevel' | 'round';\n miterLimit?: number;\n /** How far its fills or lines move on screen (`fill-translate`, `line-translate`: CSS pixels, x right, y down),\n * turning with the map or staying on the screen (`*-translate-anchor`); none and `map` if left out */\n translate?: [number, number];\n translateAnchor?: 'map' | 'viewport';\n /** Its fills have patterns (`fill-pattern`, `background-pattern`): over the relief, the engine finds the ground under\n * them */\n patterned?: boolean;\n /** Its lines glow at night (the streets: its id names a road, not its casing; `setSun`) */\n lit: boolean;\n}\n\n/** The properties of a picked feature, with the style layer that drew it */\nexport type VectorFeature = Feature<Record<string, unknown>> & { layer: string; sourceLayer: string | undefined };\n\n/** The main thread's time a frame gives to uploading tiles (ms): tiles arriving together are uploaded over several\n * frames, not all in the one (copying a tile's buffers to the GPU takes milliseconds) */\nconst UPLOAD_MS = 4;\n\ninterface Tile {\n /** Its number in the engine: tiles are numbered for picking in this order */\n key: number;\n /** What picking needs (its geometry and styles are the engine's only: an engine made anew asks the tiles again) */\n vectors: Pick<TileVectors, 'properties' | 'sublayer'>;\n}\n\nexport class VectorLayer extends Layer {\n private readonly tiles = new Map<string, Tile>();\n /** The tiles waiting for their upload (`UPLOAD_MS` a frame), each with what resolves its `setTile`; `sent`: in the\n * engine already, its blocks still uploading */\n private readonly queue = new Map<string, { vectors: TileVectors; uploaded: () => void; sent?: number }>();\n private flushing = false;\n private sublayers: VectorSublayer[] = [];\n private nextKey = 0;\n /** The whole layer shown (`setVisible`), over each style layer's visibility */\n private shown = true;\n /** Its buildings' walls show their windows (`setFacades`) */\n private facades = false;\n /** @internal Resolved once the style is loaded and its layers drawn known (set by its `VectorTiles`) */\n styled: Promise<void> = Promise.resolve();\n /** @internal Changes a property of a style layer drawn (set by its `VectorTiles`) */\n restyle: ((layer: string, group: 'paint' | 'layout', name: string, value: unknown) => void) | undefined;\n /** @internal Asks the workers for the tiles in view again (set by its `VectorTiles`): an engine made anew has none */\n recut: (() => void) | undefined;\n /** @internal Asks for the tiles in view (set by its `VectorTiles`): those of a new quality */\n refresh: (() => void) | undefined;\n /** The 3D buildings drawn in place of its raised ones (`vectors({ buildings3d })`), for `map.pickFeature` */\n buildings3d: Tiles3dLayer | undefined;\n\n /** @internal */\n constructor(map: LayerHost) {\n super(map);\n }\n\n /** @internal Its tiles as far as the map's quality reaches */\n override qualityChanged(): void {\n this.refresh?.();\n }\n\n /** Resolves once the style is loaded, its layers drawn known (`layers`), and the map has drawn the layer; rejected\n * if the style fails */\n override get ready(): Promise<void> {\n return this.styled.then(() => super.ready);\n }\n\n /** The style layers drawn, in order */\n get layers(): readonly VectorSublayer[] {\n return this.sublayers;\n }\n\n /** Keys of the tiles held (`z/x/y`) */\n get tileKeys(): string[] {\n return [...this.tiles.keys()];\n }\n\n /** @internal Sets the style layers drawn, in order (the tiles' sublayers) */\n setSublayers(sublayers: VectorSublayer[]): void {\n this.sublayers = sublayers;\n this.sendSublayers(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n /** @internal Adds or replaces a tile, cut by the workers (and made ready for the GPU there, with its mesh): uploaded\n * on a coming frame, within its share of the frame (`UPLOAD_MS`); resolves once it is (or once dropped meanwhile) */\n setTile(tile: string, vectors: TileVectors): Promise<void> {\n if (this.removed) return Promise.resolve();\n // The map not idle until it is uploaded\n return this.map.track(\n new Promise((uploaded) => {\n // A newer cut of a tile still waiting takes its place\n this.queue.get(tile)?.uploaded();\n this.queue.set(tile, { vectors, uploaded });\n this.flushSoon();\n }),\n );\n }\n\n /** Uploads the waiting tiles on the next frame */\n private flushSoon(): void {\n if (this.flushing) return;\n this.flushing = true;\n requestAnimationFrame(() => {\n this.flushing = false;\n this.flush();\n });\n }\n\n /** Uploads waiting tiles for `UPLOAD_MS` at most (one at least, or a part of its blocks), the rest on the next\n * frames; a tile's `setTile` resolves once its blocks are all there */\n private flush(): void {\n // Removed meanwhile, or between two engines (the new one asks for the tiles again)\n if (this.id < 0) return;\n\n const start = performance.now();\n const within = () => performance.now() - start <= UPLOAD_MS;\n\n for (const [tile, waiting] of this.queue) {\n waiting.sent ??= this.upload(tile, waiting.vectors);\n\n // A large tile's blocks (a pitched view's far tiles of a city: 10 MB and more), a part at a time\n let left = this.map.engine.uploadVectorTile(this.id, waiting.sent);\n\n while (left && within()) left = this.map.engine.uploadVectorTile(this.id, waiting.sent);\n if (left) break;\n this.queue.delete(tile);\n waiting.uploaded();\n if (!within()) break;\n }\n if (this.queue.size > 0) this.flushSoon();\n this.map.requestRender();\n }\n\n /** Sends a tile to the engine (its blocks' first part); its key */\n private upload(tile: string, vectors: TileVectors): number {\n const key = this.tiles.get(tile)?.key ?? this.nextKey++;\n const { properties, sublayer } = vectors;\n\n this.tiles.set(tile, { key, vectors: { properties, sublayer } });\n this.sendTile(this.map.engine, this.id, key, vectors);\n\n return key;\n }\n\n /** @internal New styles of a tile's features, as the workers evaluated them (the same features) */\n setTileStyles(tile: string, styles: Float32Array): void {\n const waiting = this.queue.get(tile);\n\n // Not uploaded yet: uploaded with them\n if (waiting && waiting.sent === undefined) {\n if (styles.length === waiting.vectors.properties.length * FLOATS) waiting.vectors.styles = styles;\n\n return;\n }\n\n const t = this.tiles.get(tile);\n\n if (!t || styles.length !== t.vectors.properties.length * FLOATS) return;\n this.map.engine.setFeatureStyle(this.id, styles, t.key);\n this.map.requestRender();\n }\n\n override remove(): void {\n super.remove();\n this.dispose();\n }\n\n /** @internal The tiles waiting resolved (dropped), none held */\n override dispose(): void {\n this.queue.forEach((waiting) => {\n waiting.uploaded();\n });\n this.queue.clear();\n this.tiles.clear();\n }\n\n /** @internal */\n removeTile(tile: string): void {\n this.queue.get(tile)?.uploaded();\n this.queue.delete(tile);\n\n const t = this.tiles.get(tile);\n\n if (!t) return;\n this.tiles.delete(tile);\n this.map.engine.removeVectorTile(this.id, t.key);\n this.map.requestRender();\n }\n\n /** The feature of a picked index (no geometry: the tiles hold it cut), its properties and style layer. Tiles are\n * numbered one after the other, in the order they were first added */\n featureAt(index: number): VectorFeature | undefined {\n const tiles = [...this.tiles.values()].sort((a, b) => a.key - b.key);\n // The tile holding the index, and the index among its features (one pass, the features of the tiles before\n // taken off)\n const { tile, rest } = tiles.reduce<{ tile?: Tile; rest: number }>(\n (found, t) => {\n if (found.tile) return found;\n\n const count = t.vectors.properties.length;\n\n return found.rest < count ? { tile: t, rest: found.rest } : { rest: found.rest - count };\n },\n { rest: index },\n );\n\n if (!tile) return undefined;\n\n const properties = tile.vectors.properties[rest];\n const sublayer = this.sublayers[tile.vectors.sublayer[rest] ?? -1];\n\n if (properties === undefined || !sublayer) return undefined;\n\n return { type: 'Feature', properties, geometry: null, layer: sublayer.id, sourceLayer: sublayer.sourceLayer };\n }\n\n /** Changes a paint property of a style layer drawn, as MapLibre's `setPaintProperty`: the tiles are restyled, not cut\n * again */\n setPaintProperty(layer: string, name: string, value: unknown): void {\n this.restyle?.(layer, 'paint', name, value);\n }\n\n /** Changes a layout property of a style layer drawn (`visibility`: shown or hidden at once), as MapLibre's\n * `setLayoutProperty` */\n setLayoutProperty(layer: string, name: string, value: unknown): void {\n this.restyle?.(layer, 'layout', name, value);\n }\n\n /** Whether its buildings' walls show their windows: glass by day, some lit at night (only the lit ones without) */\n setFacades(facades: boolean): void {\n this.facades = facades;\n this.map.engine.setFacades(this.id, facades);\n // Its 3D buildings' walls too\n this.buildings3d?.setFacades(facades);\n this.map.requestRender();\n }\n\n setVisible(visible: boolean): void {\n this.shown = visible;\n this.sendSublayers(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n private sendSublayers(engine: Engine, id: number): void {\n const s = this.sublayers;\n\n engine.setVectorSublayers(\n id,\n Uint8Array.from(s, (l) => ({ fill: 0, line: 1, extrusion: 2, circle: 3 })[l.kind]),\n Float64Array.from(s.flatMap((l) => [l.minZoom, l.maxZoom])),\n Uint8Array.from(s, (l) => (l.visible && this.shown ? 1 : 0)),\n Float32Array.from(s.flatMap((l) => l.dash)),\n Float32Array.from(s.flatMap((l) => stops(l.opacity))),\n Uint8Array.from(s, (l) => ({ butt: 0, round: 1, square: 2 })[l.cap]),\n Uint8Array.from(s, (l) => (l.lit ? 1 : 0)),\n Float32Array.from(s.flatMap((l) => [{ round: 0, miter: 1, bevel: 2 }[l.join ?? 'round'], l.miterLimit ?? 2])),\n Float32Array.from(s.flatMap((l) => [...(l.translate ?? [0, 0]), l.translateAnchor === 'viewport' ? 1 : 0])),\n Uint8Array.from(s, (l) => (l.patterned ? 1 : 0)),\n );\n }\n\n /** A tile to the engine: its mesh uploaded as it is, or without one its geometry, which the engine makes ready */\n private sendTile(engine: Engine, id: number, key: number, vectors: TileVectors): void {\n const { fills, lines, circles, styles, properties, mesh } = vectors;\n\n if (mesh) {\n engine.setVectorTileMesh(\n id,\n key,\n fills.points,\n fills.ringStart,\n fills.polygonStart,\n fills.feature,\n fills.fillStart,\n mesh.vertices,\n mesh.indices,\n mesh.fillRanges,\n mesh.prism,\n mesh.pieces,\n mesh.lineTable,\n mesh.lineRanges,\n mesh.blocks,\n mesh.blockIndices,\n mesh.blockRanges,\n mesh.bounds,\n properties.length,\n );\n } else {\n engine.setVectorTile(\n id,\n key,\n fills.points,\n fills.ringStart,\n fills.polygonStart,\n fills.feature,\n fills.fillStart,\n lines.points,\n lines.start,\n lines.feature,\n lines.lineStart,\n properties.length,\n vectors.tile ?? new Float64Array(),\n fills.roofs ?? new Uint8Array(),\n fills.roofHeights ?? new Float32Array(),\n fills.roofOutlines ?? new Float64Array(),\n fills.roofOutlineStart ?? new Uint32Array(),\n fills.roofMetres ?? 0,\n );\n }\n // The circles' points, once the tile is there\n if (circles) engine.setVectorTilePoints(id, key, circles.points, circles.feature, circles.circleStart);\n engine.setFeatureStyle(id, styles, key);\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const id = engine.addVectorTiles();\n\n this.sendSublayers(engine, id);\n engine.setFacades(id, this.facades);\n // An engine made anew (after a context loss, or the one with 3D Tiles): its tiles cut again by the workers, once\n // the layer has its id there. Keeping their geometry here would double the memory they take\n this.dispose();\n queueMicrotask(() => this.recut?.());\n\n return id;\n }\n}\n"]}
@@ -7,7 +7,7 @@ import type { Settings } from '../settings.ts';
7
7
  import type { GeoMapOptions } from '../types.ts';
8
8
  import type { Engine } from '../wasm/isard.js';
9
9
  /** What loading the engine with 3D Tiles and its workers needs */
10
- export type Tiles3dEngineOptions = Pick<GeoMapOptions, 'wasmUrl' | 'workers' | 'workerUrl' | 'decoders' | 'pointsWasmUrl' | 'assetsUrl'>;
10
+ export type Tiles3dEngineOptions = Pick<GeoMapOptions, 'wasmUrl' | 'workers' | 'workerUrl' | 'decoders' | 'pointsWasmUrl' | 'assetsUrl' | 'quality'>;
11
11
  /** The engine class of a map, and the engine with 3D Tiles loaded when needed */
12
12
  export declare class MapEngines {
13
13
  #private;
@@ -1 +1 @@
1
- {"version":3,"file":"engines.js","sourceRoot":"","sources":["../../src/map/engines.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Which engine a map runs: the core one, or the one with 3D Tiles, from the start or loaded once a layer needs it\n * (the map is rebuilt on it then); and the workers decoding its 3D Tiles, started with the first engine that has them.\n */\n\nimport type { TileLoader } from '../decoding/loader.ts';\nimport {\n type EngineClass,\n engineUrl,\n loadFullEngineLater,\n preloadFullEngine,\n startTileLoader,\n} from '../engine-loader.ts';\nimport type { Settings } from '../settings.ts';\nimport type { GeoMapOptions } from '../types.ts';\nimport type { Engine } from '../wasm/isard.js';\nimport { applySettings } from './engine-settings.ts';\n\n/** What loading the engine with 3D Tiles and its workers needs */\nexport type Tiles3dEngineOptions = Pick<\n GeoMapOptions,\n 'wasmUrl' | 'workers' | 'workerUrl' | 'decoders' | 'pointsWasmUrl' | 'assetsUrl'\n>;\n\n/** The engine class of a map, and the engine with 3D Tiles loaded when needed */\nexport class MapEngines {\n /** The class of the engine: without 3D Tiles until a 3D Tiles layer is added, unless asked for from the start */\n private engineClass: EngineClass;\n /** The module of the engine with 3D Tiles once it runs the map (the decoding workers run it too) */\n private module: WebAssembly.Module | undefined;\n #upgrading: Promise<void> | undefined;\n private loader: TileLoader | undefined;\n private readonly options: Tiles3dEngineOptions;\n /** The map is destroyed: a loaded engine is not used */\n private readonly gone: () => boolean;\n\n /** `module`: the module of the engine with 3D Tiles if `engineClass` is that engine */\n constructor(\n engineClass: EngineClass,\n module: WebAssembly.Module | undefined,\n options: Tiles3dEngineOptions,\n gone: () => boolean,\n ) {\n this.engineClass = engineClass;\n this.module = module;\n this.options = { ...options };\n this.gone = gone;\n }\n\n /** The engine with 3D Tiles runs the map */\n get tiles3d(): boolean {\n return this.module !== undefined;\n }\n\n /** The engine with 3D Tiles is loading, for the 3D Tiles layers added on the core engine */\n get upgrading(): Promise<void> | undefined {\n return this.#upgrading;\n }\n\n /** A new engine drawing on `canvas`, with the settings and the decoding workers of 3D Tiles if it has them */\n create(canvas: HTMLCanvasElement, redraw: () => void, settings: Settings): Engine {\n const engine = new this.engineClass(canvas, redraw);\n\n applySettings(engine, settings);\n // The decoding workers of 3D Tiles, with the engine that has them (they run its module) and unless turned off\n this.loader ??= this.module && startTileLoader(this.module, this.options, engine);\n if (this.loader) engine.setTileLoader(this.loader);\n\n return engine;\n }\n\n /** Height of the geoid above the ellipsoid at a position, in metres */\n geoidHeight(lon: number, lat: number): number {\n return this.engineClass.geoidHeight(lon, lat);\n }\n\n /** The matrix of a custom layer's model at a position */\n customMatrix(lon: number, lat: number, altitude: number): Float32Array | undefined {\n return this.engineClass.customMatrix(lon, lat, altitude);\n }\n\n /** Loads the engine with 3D Tiles, once at a time: `loaded` once it is the map's class, `failed` with the error;\n * neither if the map is gone by then */\n upgrade(loaded: () => void, failed: (error: unknown) => void): void {\n this.#upgrading ??= loadFullEngineLater(engineUrl('full', this.options)).then(\n ({ module, Engine }) => {\n this.#upgrading = undefined;\n if (this.gone()) return;\n this.engineClass = Engine;\n this.module = module;\n loaded();\n },\n (error: unknown) => {\n this.#upgrading = undefined;\n if (this.gone()) return;\n failed(error);\n },\n );\n }\n\n /** Downloads and compiles the engine with 3D Tiles without running it, unless the map is gone or has it by then */\n preload(): void {\n preloadFullEngine(engineUrl('full', this.options), () => !this.gone() && !this.module);\n }\n\n /** Stops the decoding workers */\n destroy(): void {\n this.loader?.destroy();\n }\n}\n"]}
1
+ {"version":3,"file":"engines.js","sourceRoot":"","sources":["../../src/map/engines.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Which engine a map runs: the core one, or the one with 3D Tiles, from the start or loaded once a layer needs it\n * (the map is rebuilt on it then); and the workers decoding its 3D Tiles, started with the first engine that has them.\n */\n\nimport type { TileLoader } from '../decoding/loader.ts';\nimport {\n type EngineClass,\n engineUrl,\n loadFullEngineLater,\n preloadFullEngine,\n startTileLoader,\n} from '../engine-loader.ts';\nimport type { Settings } from '../settings.ts';\nimport type { GeoMapOptions } from '../types.ts';\nimport type { Engine } from '../wasm/isard.js';\nimport { applySettings } from './engine-settings.ts';\n\n/** What loading the engine with 3D Tiles and its workers needs */\nexport type Tiles3dEngineOptions = Pick<\n GeoMapOptions,\n 'wasmUrl' | 'workers' | 'workerUrl' | 'decoders' | 'pointsWasmUrl' | 'assetsUrl' | 'quality'\n>;\n\n/** The engine class of a map, and the engine with 3D Tiles loaded when needed */\nexport class MapEngines {\n /** The class of the engine: without 3D Tiles until a 3D Tiles layer is added, unless asked for from the start */\n private engineClass: EngineClass;\n /** The module of the engine with 3D Tiles once it runs the map (the decoding workers run it too) */\n private module: WebAssembly.Module | undefined;\n #upgrading: Promise<void> | undefined;\n private loader: TileLoader | undefined;\n private readonly options: Tiles3dEngineOptions;\n /** The map is destroyed: a loaded engine is not used */\n private readonly gone: () => boolean;\n\n /** `module`: the module of the engine with 3D Tiles if `engineClass` is that engine */\n constructor(\n engineClass: EngineClass,\n module: WebAssembly.Module | undefined,\n options: Tiles3dEngineOptions,\n gone: () => boolean,\n ) {\n this.engineClass = engineClass;\n this.module = module;\n this.options = { ...options };\n this.gone = gone;\n }\n\n /** The engine with 3D Tiles runs the map */\n get tiles3d(): boolean {\n return this.module !== undefined;\n }\n\n /** The engine with 3D Tiles is loading, for the 3D Tiles layers added on the core engine */\n get upgrading(): Promise<void> | undefined {\n return this.#upgrading;\n }\n\n /** A new engine drawing on `canvas`, with the settings and the decoding workers of 3D Tiles if it has them */\n create(canvas: HTMLCanvasElement, redraw: () => void, settings: Settings): Engine {\n const engine = new this.engineClass(canvas, redraw);\n\n applySettings(engine, settings);\n // The decoding workers of 3D Tiles, with the engine that has them (they run its module) and unless turned off\n this.loader ??= this.module && startTileLoader(this.module, this.options, engine);\n if (this.loader) engine.setTileLoader(this.loader);\n\n return engine;\n }\n\n /** Height of the geoid above the ellipsoid at a position, in metres */\n geoidHeight(lon: number, lat: number): number {\n return this.engineClass.geoidHeight(lon, lat);\n }\n\n /** The matrix of a custom layer's model at a position */\n customMatrix(lon: number, lat: number, altitude: number): Float32Array | undefined {\n return this.engineClass.customMatrix(lon, lat, altitude);\n }\n\n /** Loads the engine with 3D Tiles, once at a time: `loaded` once it is the map's class, `failed` with the error;\n * neither if the map is gone by then */\n upgrade(loaded: () => void, failed: (error: unknown) => void): void {\n this.#upgrading ??= loadFullEngineLater(engineUrl('full', this.options)).then(\n ({ module, Engine }) => {\n this.#upgrading = undefined;\n if (this.gone()) return;\n this.engineClass = Engine;\n this.module = module;\n loaded();\n },\n (error: unknown) => {\n this.#upgrading = undefined;\n if (this.gone()) return;\n failed(error);\n },\n );\n }\n\n /** Downloads and compiles the engine with 3D Tiles without running it, unless the map is gone or has it by then */\n preload(): void {\n preloadFullEngine(engineUrl('full', this.options), () => !this.gone() && !this.module);\n }\n\n /** Stops the decoding workers */\n destroy(): void {\n this.loader?.destroy();\n }\n}\n"]}
@@ -1,9 +1,11 @@
1
1
  /**
2
2
  * The map's quality: what it draws less of on a device that cannot keep up. Each level a ceiling on the pixels drawn
3
3
  * (the device's pixel ratio capped: a high-density screen draws four times the pixels of its CSS size), the sun's
4
- * shadows (the solid scene drawn twice more for them: the sun's map, the camera's depth) and how far the 3D Tiles are
5
- * refined (their screen-space error multiplied: fewer, coarser tiles far away). 'auto' starts high and steps down
6
- * when the frames stay slow while the map moves.
4
+ * shadows (the solid scene drawn twice more for them: the sun's map, the camera's depth), how far the 3D Tiles are
5
+ * refined (their screen-space error multiplied: fewer, coarser tiles far away) and how far toward the horizon the
6
+ * vector tiles go (a city's tiles there carry its whole detail over square kilometres, mostly above the screen's top
7
+ * edge: Paris tilted 65° on a phone, 940 MB of a page against 720 without them, the view the same). 'auto' starts high
8
+ * and steps down when the frames stay slow while the map moves.
7
9
  */
8
10
  import type { Quality } from '../types.ts';
9
11
  /** What a level draws */
@@ -14,8 +16,17 @@ export interface QualitySettings {
14
16
  shadows: boolean;
15
17
  /** Multiplies the 3D Tiles' screen-space error */
16
18
  errorScale: number;
19
+ /** How far toward the horizon the vector tiles go, in distances of the screen center */
20
+ reach: number;
21
+ /** The most workers cutting the vector tiles, and decoding the 3D Tiles: each one its own heap, its decoded tiles,
22
+ * its modules (a phone's page grows with them as the map moves) */
23
+ workers: number;
24
+ /** The decoded vector tiles the workers keep, all of them together (some 2 MB each, a city's more) */
25
+ cachedTiles: number;
17
26
  }
18
27
  export declare const QUALITY: Readonly<Record<Quality, QualitySettings>>;
28
+ /** The level a map starts at: its option's ('auto' starts high) */
29
+ export declare const startLevel: (quality: Quality | "auto" | undefined) => Quality;
19
30
  /**
20
31
  * 'auto': the intervals between the frames drawn while the map moves; once a window of them (`WINDOW`) has a median
21
32
  * past `SLOW_MS`, `step` is called with the level under the current one. It never steps up: at the display's rate a fast
@@ -1,15 +1,26 @@
1
1
  /**
2
2
  * The map's quality: what it draws less of on a device that cannot keep up. Each level a ceiling on the pixels drawn
3
3
  * (the device's pixel ratio capped: a high-density screen draws four times the pixels of its CSS size), the sun's
4
- * shadows (the solid scene drawn twice more for them: the sun's map, the camera's depth) and how far the 3D Tiles are
5
- * refined (their screen-space error multiplied: fewer, coarser tiles far away). 'auto' starts high and steps down
6
- * when the frames stay slow while the map moves.
4
+ * shadows (the solid scene drawn twice more for them: the sun's map, the camera's depth), how far the 3D Tiles are
5
+ * refined (their screen-space error multiplied: fewer, coarser tiles far away) and how far toward the horizon the
6
+ * vector tiles go (a city's tiles there carry its whole detail over square kilometres, mostly above the screen's top
7
+ * edge: Paris tilted 65° on a phone, 940 MB of a page against 720 without them, the view the same). 'auto' starts high
8
+ * and steps down when the frames stay slow while the map moves.
7
9
  */
8
10
  export const QUALITY = {
9
- high: { pixelRatio: Number.POSITIVE_INFINITY, shadows: true, errorScale: 1 },
10
- medium: { pixelRatio: 1.5, shadows: true, errorScale: 1.5 },
11
- low: { pixelRatio: 1, shadows: false, errorScale: 2.5 },
11
+ high: {
12
+ pixelRatio: Number.POSITIVE_INFINITY,
13
+ shadows: true,
14
+ errorScale: 1,
15
+ reach: Number.POSITIVE_INFINITY,
16
+ workers: 4,
17
+ cachedTiles: 96,
18
+ },
19
+ medium: { pixelRatio: 1.5, shadows: true, errorScale: 1.5, reach: 3, workers: 2, cachedTiles: 32 },
20
+ low: { pixelRatio: 1, shadows: false, errorScale: 2.5, reach: 3, workers: 1, cachedTiles: 16 },
12
21
  };
22
+ /** The level a map starts at: its option's ('auto' starts high) */
23
+ export const startLevel = (quality) => quality === 'auto' || quality === undefined ? 'high' : quality;
13
24
  /** The level under each, for 'auto' */
14
25
  const LOWER = { high: 'medium', medium: 'low', low: undefined };
15
26
  /** A move measured before it is judged: `WINDOW` frames, or `WINDOW_MS` of them on a slow device (at least
@@ -1 +1 @@
1
- {"version":3,"file":"quality.js","sourceRoot":"","sources":["../../src/map/quality.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH,MAAM,CAAC,MAAM,OAAO,GAA+C;IACjE,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE;IAC5E,MAAM,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE;IAC3D,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE;CACxD,CAAC;AAEF,uCAAuC;AACvC,MAAM,KAAK,GAAmD,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;AAEhH;0FAC0F;AAC1F,MAAM,MAAM,GAAG,EAAE,CAAC;AAClB,MAAM,SAAS,GAAG,IAAI,CAAC;AACvB,MAAM,UAAU,GAAG,EAAE,CAAC;AACtB,MAAM,MAAM,GAAG,GAAG,CAAC;AAEnB,+GAA+G;AAC/G,MAAM,OAAO,GAAG,EAAE,CAAC;AAEnB,6EAA6E;AAC7E,MAAM,SAAS,GAAG,IAAI,CAAC;AAEvB;;;;GAIG;AACH,MAAM,OAAO,YAAY;IAMb;IACS;IANF,SAAS,GAAa,EAAE,CAAC;IAClC,IAAI,GAAG,CAAC,CAAC;IACT,OAAO,GAAG,CAAC,CAAC;IAEpB,YACU,KAAc,EACL,IAA8B;QADvC,UAAK,GAAL,KAAK,CAAS;QACL,SAAI,GAAJ,IAAI,CAA0B;IAC9C,CAAC;IAEJ,yDAAyD;IACzD,KAAK,CAAC,GAAW,EAAE,MAAe;QAChC,MAAM,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC;QAE5B,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;QAChB,IAAI,CAAC,MAAM,IAAI,GAAG,GAAG,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEzB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QAE5D,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,GAAG,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,UAAU,CAAC;YAAE,OAAO;QAExG,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC1D,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEhC,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;QAC1B,IAAI,MAAM,IAAI,OAAO,IAAI,CAAC,KAAK;YAAE,OAAO;QACxC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,GAAG,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC;CACF","sourcesContent":["/**\n * The map's quality: what it draws less of on a device that cannot keep up. Each level a ceiling on the pixels drawn\n * (the device's pixel ratio capped: a high-density screen draws four times the pixels of its CSS size), the sun's\n * shadows (the solid scene drawn twice more for them: the sun's map, the camera's depth) and how far the 3D Tiles are\n * refined (their screen-space error multiplied: fewer, coarser tiles far away). 'auto' starts high and steps down\n * when the frames stay slow while the map moves.\n */\n\nimport type { Quality } from '../types.ts';\n\n/** What a level draws */\nexport interface QualitySettings {\n /** The highest pixel ratio drawn */\n pixelRatio: number;\n /** The sun casts its shadows (its light and the night stay without) */\n shadows: boolean;\n /** Multiplies the 3D Tiles' screen-space error */\n errorScale: number;\n}\n\nexport const QUALITY: Readonly<Record<Quality, QualitySettings>> = {\n high: { pixelRatio: Number.POSITIVE_INFINITY, shadows: true, errorScale: 1 },\n medium: { pixelRatio: 1.5, shadows: true, errorScale: 1.5 },\n low: { pixelRatio: 1, shadows: false, errorScale: 2.5 },\n};\n\n/** The level under each, for 'auto' */\nconst LOWER: Readonly<Record<Quality, Quality | undefined>> = { high: 'medium', medium: 'low', low: undefined };\n\n/** A move measured before it is judged: `WINDOW` frames, or `WINDOW_MS` of them on a slow device (at least\n * `MIN_FRAMES`); a gap past `GAP_MS` between two frames is no move (the map was still) */\nconst WINDOW = 60;\nconst WINDOW_MS = 2000;\nconst MIN_FRAMES = 10;\nconst GAP_MS = 500;\n\n/** The median interval between the frames of a move past which the map steps down (some 40 frames a second) */\nconst SLOW_MS = 25;\n\n/** After a step down, the time the new level is given before it is judged */\nconst SETTLE_MS = 3000;\n\n/**\n * 'auto': the intervals between the frames drawn while the map moves; once a window of them (`WINDOW`) has a median\n * past `SLOW_MS`, `step` is called with the level under the current one. It never steps up: at the display's rate a fast\n * frame tells nothing of what a finer level would cost\n */\nexport class QualityWatch {\n private readonly intervals: number[] = [];\n private last = 0;\n private settled = 0;\n\n constructor(\n private level: Quality,\n private readonly step: (level: Quality) => void,\n ) {}\n\n /** A frame drawn at `now` (ms), the map moving or not */\n frame(now: number, moving: boolean): void {\n const gap = now - this.last;\n\n this.last = now;\n if (!moving || gap > GAP_MS || now < this.settled) return;\n this.intervals.push(gap);\n\n const spent = this.intervals.reduce((sum, i) => sum + i, 0);\n\n if (this.intervals.length < WINDOW && (spent < WINDOW_MS || this.intervals.length < MIN_FRAMES)) return;\n\n const sorted = [...this.intervals].sort((a, b) => a - b);\n const median = sorted[Math.floor(sorted.length / 2)] ?? 0;\n const lower = LOWER[this.level];\n\n this.intervals.length = 0;\n if (median <= SLOW_MS || !lower) return;\n this.level = lower;\n this.settled = now + SETTLE_MS;\n this.step(lower);\n }\n}\n"]}
1
+ {"version":3,"file":"quality.js","sourceRoot":"","sources":["../../src/map/quality.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The map's quality: what it draws less of on a device that cannot keep up. Each level a ceiling on the pixels drawn\n * (the device's pixel ratio capped: a high-density screen draws four times the pixels of its CSS size), the sun's\n * shadows (the solid scene drawn twice more for them: the sun's map, the camera's depth), how far the 3D Tiles are\n * refined (their screen-space error multiplied: fewer, coarser tiles far away) and how far toward the horizon the\n * vector tiles go (a city's tiles there carry its whole detail over square kilometres, mostly above the screen's top\n * edge: Paris tilted 65° on a phone, 940 MB of a page against 720 without them, the view the same). 'auto' starts high\n * and steps down when the frames stay slow while the map moves.\n */\n\nimport type { Quality } from '../types.ts';\n\n/** What a level draws */\nexport interface QualitySettings {\n /** The highest pixel ratio drawn */\n pixelRatio: number;\n /** The sun casts its shadows (its light and the night stay without) */\n shadows: boolean;\n /** Multiplies the 3D Tiles' screen-space error */\n errorScale: number;\n /** How far toward the horizon the vector tiles go, in distances of the screen center */\n reach: number;\n /** The most workers cutting the vector tiles, and decoding the 3D Tiles: each one its own heap, its decoded tiles,\n * its modules (a phone's page grows with them as the map moves) */\n workers: number;\n /** The decoded vector tiles the workers keep, all of them together (some 2 MB each, a city's more) */\n cachedTiles: number;\n}\n\nexport const QUALITY: Readonly<Record<Quality, QualitySettings>> = {\n high: {\n pixelRatio: Number.POSITIVE_INFINITY,\n shadows: true,\n errorScale: 1,\n reach: Number.POSITIVE_INFINITY,\n workers: 4,\n cachedTiles: 96,\n },\n medium: { pixelRatio: 1.5, shadows: true, errorScale: 1.5, reach: 3, workers: 2, cachedTiles: 32 },\n low: { pixelRatio: 1, shadows: false, errorScale: 2.5, reach: 3, workers: 1, cachedTiles: 16 },\n};\n\n/** The level a map starts at: its option's ('auto' starts high) */\nexport const startLevel = (quality: Quality | 'auto' | undefined): Quality =>\n quality === 'auto' || quality === undefined ? 'high' : quality;\n\n/** The level under each, for 'auto' */\nconst LOWER: Readonly<Record<Quality, Quality | undefined>> = { high: 'medium', medium: 'low', low: undefined };\n\n/** A move measured before it is judged: `WINDOW` frames, or `WINDOW_MS` of them on a slow device (at least\n * `MIN_FRAMES`); a gap past `GAP_MS` between two frames is no move (the map was still) */\nconst WINDOW = 60;\nconst WINDOW_MS = 2000;\nconst MIN_FRAMES = 10;\nconst GAP_MS = 500;\n\n/** The median interval between the frames of a move past which the map steps down (some 40 frames a second) */\nconst SLOW_MS = 25;\n\n/** After a step down, the time the new level is given before it is judged */\nconst SETTLE_MS = 3000;\n\n/**\n * 'auto': the intervals between the frames drawn while the map moves; once a window of them (`WINDOW`) has a median\n * past `SLOW_MS`, `step` is called with the level under the current one. It never steps up: at the display's rate a fast\n * frame tells nothing of what a finer level would cost\n */\nexport class QualityWatch {\n private readonly intervals: number[] = [];\n private last = 0;\n private settled = 0;\n\n constructor(\n private level: Quality,\n private readonly step: (level: Quality) => void,\n ) {}\n\n /** A frame drawn at `now` (ms), the map moving or not */\n frame(now: number, moving: boolean): void {\n const gap = now - this.last;\n\n this.last = now;\n if (!moving || gap > GAP_MS || now < this.settled) return;\n this.intervals.push(gap);\n\n const spent = this.intervals.reduce((sum, i) => sum + i, 0);\n\n if (this.intervals.length < WINDOW && (spent < WINDOW_MS || this.intervals.length < MIN_FRAMES)) return;\n\n const sorted = [...this.intervals].sort((a, b) => a - b);\n const median = sorted[Math.floor(sorted.length / 2)] ?? 0;\n const lower = LOWER[this.level];\n\n this.intervals.length = 0;\n if (median <= SLOW_MS || !lower) return;\n this.level = lower;\n this.settled = now + SETTLE_MS;\n this.step(lower);\n }\n}\n"]}
@@ -22,8 +22,10 @@ export declare class MapWorkers {
22
22
  /** The loaders of the relief by encoding, URL and floor: the same loader for the same tiles (the engine keeps its
23
23
  * tiles when only the exaggeration changes) */
24
24
  private readonly terrainLoaders;
25
- /** `workers`: the map's option (false or 0, no worker); `owner`: the map */
26
- constructor(url: string | URL, workers: GeoMapOptions['workers'], gone: () => boolean, owner: object);
25
+ /** The most workers of the shared pool, at the map's quality when it starts */
26
+ private readonly most;
27
+ /** `workers`: the map's option (false or 0, no worker); `owner`: the map; `most`: the most workers of its quality */
28
+ constructor(url: string | URL, workers: GeoMapOptions['workers'], gone: () => boolean, owner: object, most?: () => number);
27
29
  /**
28
30
  * The workers for a `VectorTiles`: the shared pool, or a pool of its own (`own`, to stop with it) when it asks for
29
31
  * another count or URL
@@ -22,12 +22,15 @@ export class MapWorkers {
22
22
  /** The loaders of the relief by encoding, URL and floor: the same loader for the same tiles (the engine keeps its
23
23
  * tiles when only the exaggeration changes) */
24
24
  terrainLoaders = new Map();
25
- /** `workers`: the map's option (false or 0, no worker); `owner`: the map */
26
- constructor(url, workers, gone, owner) {
25
+ /** The most workers of the shared pool, at the map's quality when it starts */
26
+ most;
27
+ /** `workers`: the map's option (false or 0, no worker); `owner`: the map; `most`: the most workers of its quality */
28
+ constructor(url, workers, gone, owner, most = () => 4) {
27
29
  this.url = url;
28
30
  this.workers = workers;
29
31
  this.gone = gone;
30
32
  this.owner = owner;
33
+ this.most = most;
31
34
  }
32
35
  /**
33
36
  * The workers for a `VectorTiles`: the shared pool, or a pool of its own (`own`, to stop with it) when it asks for
@@ -37,7 +40,7 @@ export class MapWorkers {
37
40
  // Workers started after the map went would never be stopped
38
41
  if (this.gone())
39
42
  throw new Error('isard: the map was destroyed');
40
- const shared = defaultWorkerCount();
43
+ const shared = defaultWorkerCount(this.most());
41
44
  const workers = Math.max(1, count ?? shared);
42
45
  const workerUrl = url ?? this.url;
43
46
  if (workers === shared && String(workerUrl) === String(this.url)) {
@@ -1 +1 @@
1
- {"version":3,"file":"workers.js","sourceRoot":"","sources":["../../src/map/workers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A map's workers: the pool drawing vector tiles, shared by the map's `VectorTiles`, which also decodes the relief and\n * reprojects rasters off the page; and the loaders of the relief, one per tile source.\n */\n\nimport type { RemoteReprojection } from '../basemap/grid.ts';\nimport { encodedTerrainLoader, type PngEncoding, type RemoteHeights } from '../basemap/terrain.ts';\nimport { BasemapWorkers, defaultWorkerCount } from '../basemap/workerpool.ts';\nimport { decodeGrids } from '../grid-module.ts';\nimport { type Grid, gridOf } from '../grids.ts';\nimport type { TerrainLoader } from '../settings.ts';\nimport type { GeoMapOptions } from '../types.ts';\nimport { fetchOk } from '../util/fetch.ts';\nimport { withHeaders } from '../util/requests.ts';\n\n/** The workers of a map, created on first use */\nexport class MapWorkers {\n /** URL of the workers' script */\n readonly url: string | URL;\n private readonly workers: GeoMapOptions['workers'];\n /** The map is destroyed: nothing more is sent to the workers */\n private readonly gone: () => boolean;\n /** Whose requests the workers' answer (cancelled together) */\n private readonly owner: object;\n /** The shared pool, created on first use */\n private shared: BasemapWorkers | undefined;\n /** The loaders of the relief by encoding, URL and floor: the same loader for the same tiles (the engine keeps its\n * tiles when only the exaggeration changes) */\n private readonly terrainLoaders = new Map<string, TerrainLoader>();\n\n /** `workers`: the map's option (false or 0, no worker); `owner`: the map */\n constructor(url: string | URL, workers: GeoMapOptions['workers'], gone: () => boolean, owner: object) {\n this.url = url;\n this.workers = workers;\n this.gone = gone;\n this.owner = owner;\n }\n\n /**\n * The workers for a `VectorTiles`: the shared pool, or a pool of its own (`own`, to stop with it) when it asks for\n * another count or URL\n */\n pool(count?: number, url?: string | URL): { pool: BasemapWorkers; own: boolean } {\n // Workers started after the map went would never be stopped\n if (this.gone()) throw new Error('isard: the map was destroyed');\n\n const shared = defaultWorkerCount();\n const workers = Math.max(1, count ?? shared);\n const workerUrl = url ?? this.url;\n\n if (workers === shared && String(workerUrl) === String(this.url)) {\n this.shared ??= new BasemapWorkers(shared, this.url);\n\n return { pool: this.shared, own: false };\n }\n\n return { pool: new BasemapWorkers(workers, workerUrl), own: true };\n }\n\n /** Stops the shared pool */\n terminate(): void {\n this.shared?.terminate();\n this.shared = undefined;\n }\n\n /** Rasters reprojected by the workers (in the page without them) */\n readonly remoteReprojection: RemoteReprojection = (job, tile, signal) =>\n this.decodingPool()?.reproject(job, tile, signal, this.owner);\n\n /** The loader of the relief tiles of `url` in a PNG encoding (one per URL, encoding and floor) */\n readonly terrainLoader = (url: string, encoding: PngEncoding, floor?: number): TerrainLoader => {\n const key = `${encoding} ${floor ?? ''} ${url}`;\n const cached = this.terrainLoaders.get(key);\n\n if (cached) return cached;\n\n const loader = encodedTerrainLoader(url, encoding, floor, this.remoteHeights);\n\n this.terrainLoaders.set(key, loader);\n\n return loader;\n };\n\n private readonly remoteHeights: RemoteHeights = (url, encoding, floor, tile, signal) =>\n this.decodingPool()?.heights(url, encoding, floor, tile, signal, this.owner);\n\n /** A GRIB2 or NetCDF file read into grids by the grid module (`module`), in a worker (in the page without them, or if\n * the worker fails) */\n async readGrids(\n source: string | URL | ArrayBuffer | Uint8Array,\n module: string,\n signal?: AbortSignal,\n ): Promise<Grid[]> {\n const pool = this.decodingPool();\n const url = typeof source === 'string' || source instanceof URL ? String(source) : undefined;\n const copy = source instanceof Uint8Array ? source.slice().buffer : undefined;\n const bytes = copy ?? (source instanceof ArrayBuffer ? source : undefined);\n // Against the page: the workers fetch it, and a relative URL would be theirs\n const absolute = url && typeof document !== 'undefined' ? new URL(url, document.baseURI).href : url;\n const fetchFile = async (at: string) => {\n const response = await fetchOk(at, withHeaders(at, signal ? { signal } : {}));\n\n return response.arrayBuffer();\n };\n const inPage = async () => decodeGrids(new Uint8Array(bytes ?? (await fetchFile(absolute ?? ''))), module);\n const read = async () => {\n if (!pool) return inPage();\n\n return pool\n .grids(absolute ? { url: absolute } : { bytes: bytes ?? new ArrayBuffer(0) }, module, signal, this.owner)\n .catch((error: unknown) => {\n // A worker's failure (the module not fetched, a worker of an older build): read again in the page, unless\n // cancelled or its bytes handed over\n if (signal?.aborted || bytes?.byteLength === 0) throw error;\n\n return inPage();\n });\n };\n const { grids, values } = await read();\n\n return grids.map((g, i) => gridOf(g, values[i] ?? new Float32Array()));\n }\n\n /**\n * The workers decoding the relief and reprojecting rasters: the shared pool, unless the map has no workers\n * (`workers: false` or 0, or none in this browser): that is done in the page then\n */\n private decodingPool(): BasemapWorkers | undefined {\n const workers = this.workers;\n\n if (this.gone() || workers === false || (workers !== undefined && workers <= 0)) return undefined;\n if (typeof Worker === 'undefined' || typeof OffscreenCanvas === 'undefined') return undefined;\n\n return this.pool().pool;\n }\n}\n"]}
1
+ {"version":3,"file":"workers.js","sourceRoot":"","sources":["../../src/map/workers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A map's workers: the pool drawing vector tiles, shared by the map's `VectorTiles`, which also decodes the relief and\n * reprojects rasters off the page; and the loaders of the relief, one per tile source.\n */\n\nimport type { RemoteReprojection } from '../basemap/grid.ts';\nimport { encodedTerrainLoader, type PngEncoding, type RemoteHeights } from '../basemap/terrain.ts';\nimport { BasemapWorkers, defaultWorkerCount } from '../basemap/workerpool.ts';\nimport { decodeGrids } from '../grid-module.ts';\nimport { type Grid, gridOf } from '../grids.ts';\nimport type { TerrainLoader } from '../settings.ts';\nimport type { GeoMapOptions } from '../types.ts';\nimport { fetchOk } from '../util/fetch.ts';\nimport { withHeaders } from '../util/requests.ts';\n\n/** The workers of a map, created on first use */\nexport class MapWorkers {\n /** URL of the workers' script */\n readonly url: string | URL;\n private readonly workers: GeoMapOptions['workers'];\n /** The map is destroyed: nothing more is sent to the workers */\n private readonly gone: () => boolean;\n /** Whose requests the workers' answer (cancelled together) */\n private readonly owner: object;\n /** The shared pool, created on first use */\n private shared: BasemapWorkers | undefined;\n /** The loaders of the relief by encoding, URL and floor: the same loader for the same tiles (the engine keeps its\n * tiles when only the exaggeration changes) */\n private readonly terrainLoaders = new Map<string, TerrainLoader>();\n\n /** The most workers of the shared pool, at the map's quality when it starts */\n private readonly most: () => number;\n\n /** `workers`: the map's option (false or 0, no worker); `owner`: the map; `most`: the most workers of its quality */\n constructor(\n url: string | URL,\n workers: GeoMapOptions['workers'],\n gone: () => boolean,\n owner: object,\n most: () => number = () => 4,\n ) {\n this.url = url;\n this.workers = workers;\n this.gone = gone;\n this.owner = owner;\n this.most = most;\n }\n\n /**\n * The workers for a `VectorTiles`: the shared pool, or a pool of its own (`own`, to stop with it) when it asks for\n * another count or URL\n */\n pool(count?: number, url?: string | URL): { pool: BasemapWorkers; own: boolean } {\n // Workers started after the map went would never be stopped\n if (this.gone()) throw new Error('isard: the map was destroyed');\n\n const shared = defaultWorkerCount(this.most());\n const workers = Math.max(1, count ?? shared);\n const workerUrl = url ?? this.url;\n\n if (workers === shared && String(workerUrl) === String(this.url)) {\n this.shared ??= new BasemapWorkers(shared, this.url);\n\n return { pool: this.shared, own: false };\n }\n\n return { pool: new BasemapWorkers(workers, workerUrl), own: true };\n }\n\n /** Stops the shared pool */\n terminate(): void {\n this.shared?.terminate();\n this.shared = undefined;\n }\n\n /** Rasters reprojected by the workers (in the page without them) */\n readonly remoteReprojection: RemoteReprojection = (job, tile, signal) =>\n this.decodingPool()?.reproject(job, tile, signal, this.owner);\n\n /** The loader of the relief tiles of `url` in a PNG encoding (one per URL, encoding and floor) */\n readonly terrainLoader = (url: string, encoding: PngEncoding, floor?: number): TerrainLoader => {\n const key = `${encoding} ${floor ?? ''} ${url}`;\n const cached = this.terrainLoaders.get(key);\n\n if (cached) return cached;\n\n const loader = encodedTerrainLoader(url, encoding, floor, this.remoteHeights);\n\n this.terrainLoaders.set(key, loader);\n\n return loader;\n };\n\n private readonly remoteHeights: RemoteHeights = (url, encoding, floor, tile, signal) =>\n this.decodingPool()?.heights(url, encoding, floor, tile, signal, this.owner);\n\n /** A GRIB2 or NetCDF file read into grids by the grid module (`module`), in a worker (in the page without them, or if\n * the worker fails) */\n async readGrids(\n source: string | URL | ArrayBuffer | Uint8Array,\n module: string,\n signal?: AbortSignal,\n ): Promise<Grid[]> {\n const pool = this.decodingPool();\n const url = typeof source === 'string' || source instanceof URL ? String(source) : undefined;\n const copy = source instanceof Uint8Array ? source.slice().buffer : undefined;\n const bytes = copy ?? (source instanceof ArrayBuffer ? source : undefined);\n // Against the page: the workers fetch it, and a relative URL would be theirs\n const absolute = url && typeof document !== 'undefined' ? new URL(url, document.baseURI).href : url;\n const fetchFile = async (at: string) => {\n const response = await fetchOk(at, withHeaders(at, signal ? { signal } : {}));\n\n return response.arrayBuffer();\n };\n const inPage = async () => decodeGrids(new Uint8Array(bytes ?? (await fetchFile(absolute ?? ''))), module);\n const read = async () => {\n if (!pool) return inPage();\n\n return pool\n .grids(absolute ? { url: absolute } : { bytes: bytes ?? new ArrayBuffer(0) }, module, signal, this.owner)\n .catch((error: unknown) => {\n // A worker's failure (the module not fetched, a worker of an older build): read again in the page, unless\n // cancelled or its bytes handed over\n if (signal?.aborted || bytes?.byteLength === 0) throw error;\n\n return inPage();\n });\n };\n const { grids, values } = await read();\n\n return grids.map((g, i) => gridOf(g, values[i] ?? new Float32Array()));\n }\n\n /**\n * The workers decoding the relief and reprojecting rasters: the shared pool, unless the map has no workers\n * (`workers: false` or 0, or none in this browser): that is done in the page then\n */\n private decodingPool(): BasemapWorkers | undefined {\n const workers = this.workers;\n\n if (this.gone() || workers === false || (workers !== undefined && workers <= 0)) return undefined;\n if (typeof Worker === 'undefined' || typeof OffscreenCanvas === 'undefined') return undefined;\n\n return this.pool().pool;\n }\n}\n"]}
package/dist/map.js CHANGED
@@ -39,7 +39,7 @@ import { addSpec } from "./map/layer-spec.js";
39
39
  import { LayerStack } from "./map/layer-stack.js";
40
40
  import { OverlayHost } from "./map/overlay-host.js";
41
41
  import { panoramaHost } from "./map/panorama-host.js";
42
- import { QUALITY, QualityWatch } from "./map/quality.js";
42
+ import { QUALITY, QualityWatch, startLevel } from "./map/quality.js";
43
43
  import { rasterSource } from "./map/raster-source.js";
44
44
  import { SymbolAtlases } from "./map/symbol-atlases.js";
45
45
  import { applyViewshed } from "./map/viewshed.js";
@@ -141,7 +141,7 @@ export class GeoMap {
141
141
  const workerUrl = options.basemapWorkerUrl ?? defaultWorkerUrl(options.assetsUrl);
142
142
  this.tessUrl = tessUrl(options);
143
143
  this.gridUrl = gridUrl(options);
144
- this.workers = new MapWorkers(workerUrl, options.workers, () => this.gone, this);
144
+ this.workers = new MapWorkers(workerUrl, options.workers, () => this.gone, this, () => this.quality.workers);
145
145
  this.basemaps = new BasemapLayers(this, this.stack, workerUrl, options.basemapTileSize);
146
146
  this.container = container;
147
147
  this.canvas = createCanvas();
@@ -183,7 +183,7 @@ export class GeoMap {
183
183
  this.setSun(options.sun);
184
184
  this.resizeObserver = new ResizeObserver(() => this.resize());
185
185
  this.resizeObserver.observe(container);
186
- this.#quality = options.quality === 'auto' || options.quality === undefined ? 'high' : options.quality;
186
+ this.#quality = startLevel(options.quality);
187
187
  if (options.quality === 'auto') {
188
188
  this.qualityWatch = new QualityWatch('high', (level) => this.applyQuality(level));
189
189
  // The frames measured are those of a move