isard 2.1.1 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
Binary file
@@ -21,8 +21,9 @@ export interface QualitySettings {
21
21
  /** The most workers cutting the vector tiles, and decoding the 3D Tiles: each one its own heap, its decoded tiles,
22
22
  * its modules (a phone's page grows with them as the map moves) */
23
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;
24
+ /** The decoded vector tiles the workers keep, all of them together, in megabytes of their heaps (a tile of a city's
25
+ * middle some 5, of a village under 1) */
26
+ cachedMegabytes: number;
26
27
  }
27
28
  export declare const QUALITY: Readonly<Record<Quality, QualitySettings>>;
28
29
  /** The level a map starts at: its option's ('auto' starts high) */
@@ -14,10 +14,10 @@ export const QUALITY = {
14
14
  errorScale: 1,
15
15
  reach: Number.POSITIVE_INFINITY,
16
16
  workers: 4,
17
- cachedTiles: 96,
17
+ cachedMegabytes: 192,
18
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 },
19
+ medium: { pixelRatio: 1.5, shadows: true, errorScale: 1.5, reach: 3, workers: 2, cachedMegabytes: 64 },
20
+ low: { pixelRatio: 1, shadows: false, errorScale: 2.5, reach: 3, workers: 1, cachedMegabytes: 32 },
21
21
  };
22
22
  /** The level a map starts at: its option's ('auto' starts high) */
23
23
  export const startLevel = (quality) => quality === 'auto' || quality === undefined ? 'high' : quality;
@@ -1 +1 @@
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"]}
1
+ {"version":3,"file":"quality.js","sourceRoot":"","sources":["../../src/map/quality.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAsBH,MAAM,CAAC,MAAM,OAAO,GAA+C;IACjE,IAAI,EAAE;QACJ,UAAU,EAAE,MAAM,CAAC,iBAAiB;QACpC,OAAO,EAAE,IAAI;QACb,UAAU,EAAE,CAAC;QACb,KAAK,EAAE,MAAM,CAAC,iBAAiB;QAC/B,OAAO,EAAE,CAAC;QACV,eAAe,EAAE,GAAG;KACrB;IACD,MAAM,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE;IACtG,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE;CACnG,CAAC;AAEF,mEAAmE;AACnE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAAqC,EAAW,EAAE,CAC3E,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;AAEjE,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 /** 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, in megabytes of their heaps (a tile of a city's\n * middle some 5, of a village under 1) */\n cachedMegabytes: 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 cachedMegabytes: 192,\n },\n medium: { pixelRatio: 1.5, shadows: true, errorScale: 1.5, reach: 3, workers: 2, cachedMegabytes: 64 },\n low: { pixelRatio: 1, shadows: false, errorScale: 2.5, reach: 3, workers: 1, cachedMegabytes: 32 },\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"]}
@@ -1,11 +1,16 @@
1
1
  /**
2
2
  * A cache keeping its most recently used entries (the decoded tiles and images of the workers, the source tiles of a
3
3
  * reprojection, the labels of the vector tiles): a `Map` in order of use, the least recent dropped past `capacity`.
4
+ * Each entry weighs 1 unless weighed otherwise (`weigh`: the decoded tiles by their bytes), the capacity then a total
5
+ * weight; the most recent entry is kept whatever it weighs.
4
6
  */
5
7
  export declare class Lru<K, V> {
6
8
  capacity: number;
7
9
  private readonly evict?;
8
10
  private readonly entries;
11
+ /** The weights other than 1 */
12
+ private readonly weights;
13
+ private total;
9
14
  /** `evict`: told of each entry dropped for room (not of those deleted) */
10
15
  constructor(capacity: number, evict?: ((value: V, key: K) => void) | undefined);
11
16
  get size(): number;
@@ -15,7 +20,11 @@ export declare class Lru<K, V> {
15
20
  has(key: K): boolean;
16
21
  /** Adds or replaces a value, the most recently used; drops the least recent ones past the capacity */
17
22
  set(key: K, value: V): void;
23
+ /** Weighs a kept entry (its place in the order of use kept); drops the least recent ones past the capacity */
24
+ weigh(key: K, weight: number): void;
18
25
  delete(key: K): boolean;
26
+ /** Drops the least recent entries past the capacity, the most recent kept */
27
+ private trim;
19
28
  /** The values, least recently used first */
20
29
  values(): IterableIterator<V>;
21
30
  clear(): void;
package/dist/util/lru.js CHANGED
@@ -1,11 +1,16 @@
1
1
  /**
2
2
  * A cache keeping its most recently used entries (the decoded tiles and images of the workers, the source tiles of a
3
3
  * reprojection, the labels of the vector tiles): a `Map` in order of use, the least recent dropped past `capacity`.
4
+ * Each entry weighs 1 unless weighed otherwise (`weigh`: the decoded tiles by their bytes), the capacity then a total
5
+ * weight; the most recent entry is kept whatever it weighs.
4
6
  */
5
7
  export class Lru {
6
8
  capacity;
7
9
  evict;
8
10
  entries = new Map();
11
+ /** The weights other than 1 */
12
+ weights = new Map();
13
+ total = 0;
9
14
  /** `evict`: told of each entry dropped for room (not of those deleted) */
10
15
  constructor(capacity, evict) {
11
16
  this.capacity = capacity;
@@ -29,24 +34,43 @@ export class Lru {
29
34
  }
30
35
  /** Adds or replaces a value, the most recently used; drops the least recent ones past the capacity */
31
36
  set(key, value) {
32
- this.entries.delete(key);
37
+ this.delete(key);
33
38
  this.entries.set(key, value);
39
+ this.total += 1;
40
+ this.trim();
41
+ }
42
+ /** Weighs a kept entry (its place in the order of use kept); drops the least recent ones past the capacity */
43
+ weigh(key, weight) {
44
+ if (!this.entries.has(key))
45
+ return;
46
+ this.total += weight - (this.weights.get(key) ?? 1);
47
+ this.weights.set(key, weight);
48
+ this.trim();
49
+ }
50
+ delete(key) {
51
+ if (!this.entries.has(key))
52
+ return false;
53
+ this.total -= this.weights.get(key) ?? 1;
54
+ this.weights.delete(key);
55
+ return this.entries.delete(key);
56
+ }
57
+ /** Drops the least recent entries past the capacity, the most recent kept */
58
+ trim() {
34
59
  for (const [oldest, old] of this.entries) {
35
- if (this.entries.size <= this.capacity)
60
+ if (this.total <= this.capacity || this.entries.size <= 1)
36
61
  break;
37
- this.entries.delete(oldest);
62
+ this.delete(oldest);
38
63
  this.evict?.(old, oldest);
39
64
  }
40
65
  }
41
- delete(key) {
42
- return this.entries.delete(key);
43
- }
44
66
  /** The values, least recently used first */
45
67
  values() {
46
68
  return this.entries.values();
47
69
  }
48
70
  clear() {
49
71
  this.entries.clear();
72
+ this.weights.clear();
73
+ this.total = 0;
50
74
  }
51
75
  }
52
76
  //# sourceMappingURL=lru.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lru.js","sourceRoot":"","sources":["../../src/util/lru.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,OAAO,GAAG;IAKL;IACU;IALF,OAAO,GAAG,IAAI,GAAG,EAAQ,CAAC;IAE3C,0EAA0E;IAC1E,YACS,QAAgB,EACN,KAAkC;QAD5C,aAAQ,GAAR,QAAQ,CAAQ;QACN,UAAK,GAAL,KAAK,CAA6B;IAClD,CAAC;IAEJ,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED,0EAA0E;IAC1E,GAAG,CAAC,GAAM;QACR,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEpC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED,8CAA8C;IAC9C,GAAG,CAAC,GAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAED,sGAAsG;IACtG,GAAG,CAAC,GAAM,EAAE,KAAQ;QAClB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7B,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACzC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ;gBAAE,MAAM;YAC9C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC5B,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,MAAM,CAAC,GAAM;QACX,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAED,4CAA4C;IAC5C,MAAM;QACJ,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;IAC/B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;CACF","sourcesContent":["/**\n * A cache keeping its most recently used entries (the decoded tiles and images of the workers, the source tiles of a\n * reprojection, the labels of the vector tiles): a `Map` in order of use, the least recent dropped past `capacity`.\n */\nexport class Lru<K, V> {\n private readonly entries = new Map<K, V>();\n\n /** `evict`: told of each entry dropped for room (not of those deleted) */\n constructor(\n public capacity: number,\n private readonly evict?: (value: V, key: K) => void,\n ) {}\n\n get size(): number {\n return this.entries.size;\n }\n\n /** The value of a key, now the most recently used; undefined if absent */\n get(key: K): V | undefined {\n const value = this.entries.get(key);\n\n if (value !== undefined) {\n this.entries.delete(key);\n this.entries.set(key, value);\n }\n\n return value;\n }\n\n /** Whether a key is kept, without using it */\n has(key: K): boolean {\n return this.entries.has(key);\n }\n\n /** Adds or replaces a value, the most recently used; drops the least recent ones past the capacity */\n set(key: K, value: V): void {\n this.entries.delete(key);\n this.entries.set(key, value);\n for (const [oldest, old] of this.entries) {\n if (this.entries.size <= this.capacity) break;\n this.entries.delete(oldest);\n this.evict?.(old, oldest);\n }\n }\n\n delete(key: K): boolean {\n return this.entries.delete(key);\n }\n\n /** The values, least recently used first */\n values(): IterableIterator<V> {\n return this.entries.values();\n }\n\n clear(): void {\n this.entries.clear();\n }\n}\n"]}
1
+ {"version":3,"file":"lru.js","sourceRoot":"","sources":["../../src/util/lru.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A cache keeping its most recently used entries (the decoded tiles and images of the workers, the source tiles of a\n * reprojection, the labels of the vector tiles): a `Map` in order of use, the least recent dropped past `capacity`.\n * Each entry weighs 1 unless weighed otherwise (`weigh`: the decoded tiles by their bytes), the capacity then a total\n * weight; the most recent entry is kept whatever it weighs.\n */\nexport class Lru<K, V> {\n private readonly entries = new Map<K, V>();\n /** The weights other than 1 */\n private readonly weights = new Map<K, number>();\n private total = 0;\n\n /** `evict`: told of each entry dropped for room (not of those deleted) */\n constructor(\n public capacity: number,\n private readonly evict?: (value: V, key: K) => void,\n ) {}\n\n get size(): number {\n return this.entries.size;\n }\n\n /** The value of a key, now the most recently used; undefined if absent */\n get(key: K): V | undefined {\n const value = this.entries.get(key);\n\n if (value !== undefined) {\n this.entries.delete(key);\n this.entries.set(key, value);\n }\n\n return value;\n }\n\n /** Whether a key is kept, without using it */\n has(key: K): boolean {\n return this.entries.has(key);\n }\n\n /** Adds or replaces a value, the most recently used; drops the least recent ones past the capacity */\n set(key: K, value: V): void {\n this.delete(key);\n this.entries.set(key, value);\n this.total += 1;\n this.trim();\n }\n\n /** Weighs a kept entry (its place in the order of use kept); drops the least recent ones past the capacity */\n weigh(key: K, weight: number): void {\n if (!this.entries.has(key)) return;\n this.total += weight - (this.weights.get(key) ?? 1);\n this.weights.set(key, weight);\n this.trim();\n }\n\n delete(key: K): boolean {\n if (!this.entries.has(key)) return false;\n this.total -= this.weights.get(key) ?? 1;\n this.weights.delete(key);\n\n return this.entries.delete(key);\n }\n\n /** Drops the least recent entries past the capacity, the most recent kept */\n private trim(): void {\n for (const [oldest, old] of this.entries) {\n if (this.total <= this.capacity || this.entries.size <= 1) break;\n this.delete(oldest);\n this.evict?.(old, oldest);\n }\n }\n\n /** The values, least recently used first */\n values(): IterableIterator<V> {\n return this.entries.values();\n }\n\n clear(): void {\n this.entries.clear();\n this.weights.clear();\n this.total = 0;\n }\n}\n"]}
@@ -24,7 +24,7 @@ export declare const landmarksOf: (layers: Map<string, {
24
24
  features: TileFeature[];
25
25
  }> | undefined) => number[];
26
26
  /** Whether a building's rings (tile units) hold one of the landmarks' points */
27
- export declare const holdsLandmark: (rings: readonly (readonly number[])[], points: readonly number[]) => boolean;
27
+ export declare const holdsLandmark: (rings: readonly ArrayLike<number>[], points: readonly number[]) => boolean;
28
28
  /**
29
29
  * The buildings of a layer that are landmarks: those holding a landmark's point (`holdsLandmark`), and the parts of
30
30
  * those (a building whose middle is inside one of them, or that holds one's middle: the stage tower, the dome). Their
@@ -45,15 +45,15 @@ export declare const filterZooms: (layer: StyleLayer, feature: TileFeature, z: n
45
45
  * A ring cut to the square [0, `extent`] (Sutherland–Hodgman), its points interleaved, unclosed: a polygon lying
46
46
  * across the tile's edge keeps its part in the tile, along the edge
47
47
  */
48
- export declare const clipRing: (ring: readonly number[], extent: number) => number[];
48
+ export declare const clipRing: (ring: ArrayLike<number>, extent: number) => number[];
49
49
  /**
50
50
  * A line with the points dropped that lie within `tolerance` of the line through their neighbours kept (Douglas–
51
51
  * Peucker): a sequence of photos every few metres (Panoramax's) drawn as many pieces under a pixel, each as wide as the
52
52
  * line, covered a pixel ten times over
53
53
  */
54
- export declare const simplifyLine: (line: readonly number[], tolerance: number) => number[];
54
+ export declare const simplifyLine: (line: ArrayLike<number>, tolerance: number) => number[];
55
55
  /** A line cut to the square [0, `extent`] (Liang–Barsky per segment): its runs inside, each two points at least */
56
- export declare const clipLine: (line: readonly number[], extent: number) => number[][];
56
+ export declare const clipLine: (line: ArrayLike<number>, extent: number) => number[][];
57
57
  /** The styles alone of a tile's features in the renderer's layers, as `tileVectors` gives them (its paint changed:
58
58
  * the same features, in the same order) */
59
59
  export declare const tileStyles: (r: Renderer, work: WorkOf<"vectors">) => Promise<TileStyles | undefined>;
@@ -146,7 +146,7 @@ export type BasemapRequest =
146
146
  sprites?: Sprite[];
147
147
  /** Workers of the pool: each keeps its share of the decoded tiles */
148
148
  workers?: number;
149
- /** The decoded tiles the pool keeps, all its workers together (the map's quality) */
149
+ /** The decoded tiles the pool keeps, all its workers together, in megabytes (the map's quality) */
150
150
  cached?: number;
151
151
  } | (BasemapWork & {
152
152
  id: number;
@@ -36,9 +36,10 @@ export declare const spriteIcon: (r: Renderer, name: string) => {
36
36
  image: ImageBitmap;
37
37
  } | undefined;
38
38
  export declare const renderers: Map<string, Renderer>;
39
- /** Decoded tiles by URL; this worker's share of them, set by the renderers */
39
+ /** Decoded tiles by URL, each weighed by its bytes (`decodedBytes`) once decoded; this worker's share of them (bytes),
40
+ * set by the renderers */
40
41
  export declare const cache: Lru<string, Promise<Map<string, TileLayer> | undefined>>;
41
- /** The decoded tiles one worker of `workers` keeps, of the pool's `cached` */
42
+ /** The bytes of decoded tiles one worker of `workers` keeps, of the pool's `cached` megabytes */
42
43
  export declare const cacheShare: (workers: number, cached?: number) => number;
43
44
  /** Requests in progress, and those of them aborted (both forgotten once answered) */
44
45
  export declare const active: Set<number>;
@@ -7,14 +7,14 @@ export declare const thinned: (found: readonly number[], max: number) => Float64
7
7
  /** A number in [0, 1) from four integers, the same for the same ones: where a tree stands in its cell, its size */
8
8
  export declare const treeHash: (a: number, b: number, c: number, d: number) => number;
9
9
  /** Whether a point lies in rings (interleaved points, unclosed or closed), even-odd: the holes cut out */
10
- export declare const inRings: (rings: readonly (readonly number[])[], px: number, py: number) => boolean;
10
+ export declare const inRings: (rings: readonly ArrayLike<number>[], px: number, py: number) => boolean;
11
11
  /**
12
12
  * Points scattered over a polygon (its rings, tile units) on a jittered grid of `cell` tile units, the grid and the
13
13
  * jitter fixed by the tile (`seed`): the same trees whenever the tile is cut again, none twice across tiles (the points
14
14
  * past the tile's edge left to its neighbour). Past `maxCells` cells over the polygon (a tile of a coarse level), the
15
15
  * cells grow until they are no more. Each point with a number in [0, 1) for its size and heading
16
16
  */
17
- export declare const scatter: (rings: readonly (readonly number[])[], extent: number, spacing: number, seed: [number, number, number], maxCells?: number) => [x: number, y: number, k: number][];
17
+ export declare const scatter: (rings: readonly ArrayLike<number>[], extent: number, spacing: number, seed: [number, number, number], maxCells?: number) => [x: number, y: number, k: number][];
18
18
  /**
19
19
  * Trees over the polygons of the renderer's layers in a tile: longitude, latitude, scale (0.75 to 1.25), heading
20
20
  * (degrees), rank (in [0, 1): the page keeps the lowest far from the view) and kind (1 a conifer, as many as its wood's
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "isard",
3
- "version": "2.1.1",
3
+ "version": "2.1.2",
4
4
  "description": "A WebGL2 map engine for large, interactive data layers, labels and 3D Tiles over raster or vector basemaps (Rust core in WebAssembly)",
5
5
  "license": "MIT",
6
6
  "author": "Kevin Graff",