@sjvair/map-sdk 0.1.0-beta.6 → 0.1.0-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -135,7 +135,13 @@ default MapTiler Streets v4 variants (build on `defaultBasemaps()`, which `creat
135
135
  sjvair.com setup is `{ ...defaultBasemaps(), excludedLayers: [] }`); `config.initialView` and
136
136
  `config.cooperativeGestures` set the camera and gesture handling. `config.projection` (`"mercator"`
137
137
  by default, or `"globe"`) and `config.space` (`false` by default, or `{ preset: "milkyway" }` for a
138
- space background behind the globe) are passed to MapTiler only when set.
138
+ space background behind the globe) are passed to MapTiler only when set. `config.telemetry: false`
139
+ turns off MapTiler's telemetry (a usage report of the SDK version, API key, and session id, sent
140
+ about 2 s after each map is created) before the map is created. It is a page-wide setting in
141
+ MapTiler's SDK: once one map turns it off, it stays off for every map on the page. MapTiler's
142
+ session id (`mtsid`) stays on either way, since MapTiler bills SDK maps by session (without one,
143
+ every tile request counts on its own) and its tile cache needs it. By default (`true`) MapTiler's
144
+ own default applies.
139
145
 
140
146
  Without `createMonitorsStore`, build a `DataSource` yourself (below).
141
147
 
@@ -207,7 +213,9 @@ the legend section's title: `layerLabel` (default) or the entry type's label fro
207
213
  provider (`monitorsPlugin` uses the latter, so its section reads "PM2.5"; `layerLabel` still names
208
214
  the layer in the list, selection bar and summary). `Legend` takes `order` (`"bottom-first"`,
209
215
  default, or `"top-first"`) and `framed` (`true`, default, draws its own card; `false` draws no
210
- border, background, padding or fixed width, so a host's own card frames it). Without a frame,
216
+ border, background, padding or fixed width, so a host's own card frames it). The framed legend
217
+ and the feature list panel are 21rem wide at most, and never wider than the map less 2rem (the
218
+ window less 2rem outside a `MapView`), so they fit a small map on a wide screen. Without a frame,
211
219
  translucent swatches blend over the nearest ancestor with an opaque background (a see-through
212
220
  card is skipped), else `--background`; that color is read on mount, when `framed` changes, and on
213
221
  a theme change, but not when the card changes color through its own class or style.
@@ -254,7 +262,9 @@ source loads, fails, or is unavailable, the legend says so (a failure offers "Tr
254
262
  calls `status.retry()`). Values are shown with the metadata's display precision, except in the
255
263
  monitor, cluster, and collocation tooltips, which match monitor-map: the reading and a cluster's
256
264
  average are whole numbers, and a cluster's max and min are as reported. Fire values are cut off
257
- rather than rounded (see `truncateValues`). Times in the tooltips read like sjvair.com's map, in
265
+ rather than rounded (see `truncateValues`). On a category scale, a value that is its level's code
266
+ (smoke's `"light"`, the heat score's `2`) isn't shown: the list row, the tooltip, and the row's
267
+ accessible name give only the level label. Times in the tooltips read like sjvair.com's map, in
258
268
  Pacific time: "4:00 pm Friday Nov 06, 2026", with " PT" after them on a device in another zone.
259
269
  The monitor cluster tooltip's count line gives the area the monitors are within, "3 monitors
260
270
  within a 22.619 mi² area": the area of their convex hull, left out when it would read 0.000 (two
@@ -548,6 +558,19 @@ local sjvair.com stack at `http://localhost:8000`.
548
558
 
549
559
  ## Changes
550
560
 
561
+ ### 0.1.0-beta.7
562
+
563
+ - **Plugins come back at once after a basemap switch.** After picking another basemap, monitors,
564
+ fire, smoke and the other layers were missing until every tile of the new basemap had loaded
565
+ and drawn (4–10 s on a slow connection). They are now added as soon as the new style loads, as
566
+ sjvair.com's map does. A theme change while tiles are loading no longer waits either.
567
+ - **`config.telemetry: false`** turns off MapTiler's telemetry (its usage report) for the page,
568
+ before the map is created. Sessions stay on, so billing by session and the tile cache are
569
+ unchanged. By default nothing changes.
570
+ - **The feature list panel and the framed legend fit the map.** They were capped at the window's
571
+ width less 2rem; inside a `MapView` they are now capped at the map's width less 2rem, so a small
572
+ map on a wide screen doesn't overflow. MapView sets `--mapsdk-map-width` for this.
573
+
551
574
  ### 0.1.0-beta.6
552
575
 
553
576
  - **A category reading is shown once.** When a feature's value is its category level's code, the
@@ -32,6 +32,14 @@ export interface MapConfig {
32
32
  space?: false | {
33
33
  preset: string;
34
34
  };
35
+ /**
36
+ * Default `true`: MapTiler's own default. `false` turns off MapTiler's telemetry (a usage
37
+ * report of the SDK version, the API key, and the session id, sent about 2 s after each map is
38
+ * created) before the GL map is created. It is a page-wide setting in MapTiler's SDK, so once
39
+ * one map turns it off it stays off for every map on the page. MapTiler's session id (`mtsid`)
40
+ * stays on: MapTiler bills SDK maps by session, and its tile cache needs sessions.
41
+ */
42
+ telemetry?: boolean;
35
43
  }
36
44
  export interface CreateMapOptions {
37
45
  config: MapConfig;
@@ -381,7 +381,9 @@ class MapContextImpl {
381
381
  this.#host.attach(gl);
382
382
  this.#router.attach(gl);
383
383
  gl.on("moveend", this.#onMoveEnd);
384
- this.basemap.attach(gl, () => this.#host.restyle(), () => {
384
+ this.basemap.attach(gl,
385
+ // Called from style.load: the style is loaded, though its tiles may not be.
386
+ () => this.#host.restyle(true), () => {
385
387
  this.#ready = false;
386
388
  this.#readyRequested = false;
387
389
  this.#host.suspend();
@@ -57,11 +57,15 @@ export declare class PluginHost {
57
57
  */
58
58
  suspend(): void;
59
59
  /**
60
- * Tears down and sets up every plugin again (after a basemap change), once the style loads.
61
- * On a loaded style the setup is synchronous, so only map events and theme watching call this,
62
- * never code inside an effect: roots created there can stop (see the class comment).
60
+ * Tears down and sets up every plugin again (after a basemap or theme change), once the style
61
+ * loads. Pass `styleLoaded` from a `style.load` listener: `isStyleLoaded()` stays false there
62
+ * until every tile has loaded, and `style.load` has already fired, so waiting would last until
63
+ * `idle`. A live host's style is loaded too (`suspend` comes before every `setStyle`), so a theme
64
+ * change sets up at once as well. On a loaded style the setup is synchronous, so only map events
65
+ * and theme watching call this, never code inside an effect: roots created there can stop (see
66
+ * the class comment).
63
67
  */
64
- restyle(): void;
68
+ restyle(styleLoaded?: boolean): void;
65
69
  /** Tears down every plugin. The gl is not touched after this returns. */
66
70
  detach(): void;
67
71
  }
@@ -161,15 +161,26 @@ export class PluginHost {
161
161
  this.#teardownAll();
162
162
  }
163
163
  /**
164
- * Tears down and sets up every plugin again (after a basemap change), once the style loads.
165
- * On a loaded style the setup is synchronous, so only map events and theme watching call this,
166
- * never code inside an effect: roots created there can stop (see the class comment).
164
+ * Tears down and sets up every plugin again (after a basemap or theme change), once the style
165
+ * loads. Pass `styleLoaded` from a `style.load` listener: `isStyleLoaded()` stays false there
166
+ * until every tile has loaded, and `style.load` has already fired, so waiting would last until
167
+ * `idle`. A live host's style is loaded too (`suspend` comes before every `setStyle`), so a theme
168
+ * change sets up at once as well. On a loaded style the setup is synchronous, so only map events
169
+ * and theme watching call this, never code inside an effect: roots created there can stop (see
170
+ * the class comment).
167
171
  */
168
- restyle() {
172
+ restyle(styleLoaded = false) {
169
173
  if (!this.#gl)
170
174
  return;
175
+ const loaded = styleLoaded || this.#live;
171
176
  this.#teardownAll();
172
- this.#whenStyleLoaded(true);
177
+ if (loaded) {
178
+ this.#cancelStyleWait();
179
+ this.#setupAll();
180
+ }
181
+ else {
182
+ this.#whenStyleLoaded(true);
183
+ }
173
184
  }
174
185
  /** Tears down every plugin. The gl is not touched after this returns. */
175
186
  detach() {
@@ -381,7 +381,8 @@
381
381
  flex-direction: column;
382
382
  position: relative;
383
383
  width: 21rem;
384
- max-width: calc(100vw - 2rem);
384
+ /* The map's width inside a MapView (set there), else the window's. */
385
+ max-width: calc(var(--mapsdk-map-width, 100vw) - 2rem);
385
386
  max-height: 100%;
386
387
  box-sizing: border-box;
387
388
  border: 1px solid var(--card-border, var(--border));
@@ -143,7 +143,8 @@
143
143
  flex-direction: column;
144
144
  gap: 0.75rem;
145
145
  width: 21rem;
146
- max-width: calc(100vw - 2rem);
146
+ /* The map's width inside a MapView (set there), else the window's. */
147
+ max-width: calc(var(--mapsdk-map-width, 100vw) - 2rem);
147
148
  box-sizing: border-box;
148
149
  padding: 0.75rem 1rem;
149
150
  border: 1px solid var(--card-border, var(--border));
@@ -250,6 +250,7 @@
250
250
  role="region"
251
251
  aria-label={label ?? map.messages("mapsdk_map_label")}
252
252
  data-mapsdk-map={map.uid}
253
+ style:--mapsdk-map-width={width > 0 ? `${width}px` : undefined}
253
254
  >
254
255
  <div class="mapsdk-gl" bind:this={glContainer}></div>
255
256
  <MapTooltip {map} {project} {width} {height} mode={tooltip} gl={projector} />
@@ -128,6 +128,10 @@ function recordView(gl, ctx) {
128
128
  */
129
129
  export function createGlMap(container, ctx, engineControls = false) {
130
130
  const { camera, style } = untrack(() => ({ camera: ctx.camera, style: styleOf(ctx) }));
131
+ // Before the map exists, so its telemetry timer finds it off. Sessions stay on: MapTiler
132
+ // bills SDK maps by session, and without one every tile request counts on its own.
133
+ if (ctx.config.telemetry === false)
134
+ maptilerConfig.telemetry = false;
131
135
  const gl = new GlMap({
132
136
  container,
133
137
  style,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sjvair/map-sdk",
3
3
  "description": "Svelte 5 map components for SJVAir air-quality data",
4
- "version": "0.1.0-beta.6",
4
+ "version": "0.1.0-beta.7",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",