isard 1.12.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":"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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 { 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
@@ -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"]}
@@ -18,8 +18,15 @@ export interface QualitySettings {
18
18
  errorScale: number;
19
19
  /** How far toward the horizon the vector tiles go, in distances of the screen center */
20
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;
21
26
  }
22
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;
23
30
  /**
24
31
  * 'auto': the intervals between the frames drawn while the map moves; once a window of them (`WINDOW`) has a median
25
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
@@ -8,10 +8,19 @@
8
8
  * and steps down when the frames stay slow while the map moves.
9
9
  */
10
10
  export const QUALITY = {
11
- high: { pixelRatio: Number.POSITIVE_INFINITY, shadows: true, errorScale: 1, reach: Number.POSITIVE_INFINITY },
12
- medium: { pixelRatio: 1.5, shadows: true, errorScale: 1.5, reach: 3 },
13
- low: { pixelRatio: 1, shadows: false, errorScale: 2.5, reach: 3 },
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 },
14
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;
15
24
  /** The level under each, for 'auto' */
16
25
  const LOWER = { high: 'medium', medium: 'low', low: undefined };
17
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;;;;;;;;GAQG;AAgBH,MAAM,CAAC,MAAM,OAAO,GAA+C;IACjE,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,iBAAiB,EAAE;IAC7G,MAAM,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE;IACrE,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE;CAClE,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), 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}\n\nexport const QUALITY: Readonly<Record<Quality, QualitySettings>> = {\n high: { pixelRatio: Number.POSITIVE_INFINITY, shadows: true, errorScale: 1, reach: Number.POSITIVE_INFINITY },\n medium: { pixelRatio: 1.5, shadows: true, errorScale: 1.5, reach: 3 },\n low: { pixelRatio: 1, shadows: false, errorScale: 2.5, reach: 3 },\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":"AAAA;;;GAGG;AAGH,OAAO,EAAE,oBAAoB,EAAwC,MAAM,uBAAuB,CAAC;AACnG,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAa,MAAM,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,iDAAiD;AACjD,MAAM,OAAO,UAAU;IACrB,iCAAiC;IACxB,GAAG,CAAe;IACV,OAAO,CAA2B;IACnD,gEAAgE;IAC/C,IAAI,CAAgB;IACrC,8DAA8D;IAC7C,KAAK,CAAS;IAC/B,4CAA4C;IACpC,MAAM,CAA6B;IAC3C;mDAC+C;IAC9B,cAAc,GAAG,IAAI,GAAG,EAAyB,CAAC;IAEnE,4EAA4E;IAC5E,YAAY,GAAiB,EAAE,OAAiC,EAAE,IAAmB,EAAE,KAAa;QAClG,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED;;;OAGG;IACH,IAAI,CAAC,KAAc,EAAE,GAAkB;QACrC,4DAA4D;QAC5D,IAAI,IAAI,CAAC,IAAI,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAEjE,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,IAAI,MAAM,CAAC,CAAC;QAC7C,MAAM,SAAS,GAAG,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;QAElC,IAAI,OAAO,KAAK,MAAM,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACjE,IAAI,CAAC,MAAM,KAAK,IAAI,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;YAErD,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;QAC3C,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,IAAI,cAAc,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IACrE,CAAC;IAED,4BAA4B;IAC5B,SAAS;QACP,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;IAC1B,CAAC;IAED,oEAAoE;IAC3D,kBAAkB,GAAuB,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CACtE,IAAI,CAAC,YAAY,EAAE,EAAE,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAEhE,kGAAkG;IACzF,aAAa,GAAG,CAAC,GAAW,EAAE,QAAqB,EAAE,KAAc,EAAiB,EAAE;QAC7F,MAAM,GAAG,GAAG,GAAG,QAAQ,IAAI,KAAK,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAE5C,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC;QAE1B,MAAM,MAAM,GAAG,oBAAoB,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QAE9E,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAErC,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;IAEe,aAAa,GAAkB,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CACrF,IAAI,CAAC,YAAY,EAAE,EAAE,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAE/E;2BACuB;IACvB,KAAK,CAAC,SAAS,CACb,MAA+C,EAC/C,MAAc,EACd,MAAoB;QAEpB,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,YAAY,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC7F,MAAM,IAAI,GAAG,MAAM,YAAY,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9E,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,MAAM,YAAY,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC3E,6EAA6E;QAC7E,MAAM,QAAQ,GAAG,GAAG,IAAI,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;QACpG,MAAM,SAAS,GAAG,KAAK,EAAE,EAAU,EAAE,EAAE;YACrC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAE9E,OAAO,QAAQ,CAAC,WAAW,EAAE,CAAC;QAChC,CAAC,CAAC;QACF,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC,IAAI,UAAU,CAAC,KAAK,IAAI,CAAC,MAAM,SAAS,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAC3G,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;YACtB,IAAI,CAAC,IAAI;gBAAE,OAAO,MAAM,EAAE,CAAC;YAE3B,OAAO,IAAI;iBACR,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,IAAI,IAAI,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC;iBACxG,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBACxB,0GAA0G;gBAC1G,qCAAqC;gBACrC,IAAI,MAAM,EAAE,OAAO,IAAI,KAAK,EAAE,UAAU,KAAK,CAAC;oBAAE,MAAM,KAAK,CAAC;gBAE5D,OAAO,MAAM,EAAE,CAAC;YAClB,CAAC,CAAC,CAAC;QACP,CAAC,CAAC;QACF,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;QAEvC,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,YAAY,EAAE,CAAC,CAAC,CAAC;IACzE,CAAC;IAED;;;OAGG;IACK,YAAY;QAClB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAE7B,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,OAAO,KAAK,KAAK,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,IAAI,CAAC,CAAC;YAAE,OAAO,SAAS,CAAC;QAClG,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,eAAe,KAAK,WAAW;YAAE,OAAO,SAAS,CAAC;QAE9F,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC;IAC1B,CAAC;CACF","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