ogm-viewer 0.6.0 → 0.6.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.
Files changed (28) hide show
  1. package/dist/cjs/{lerc-XQuzL9p2.js → lerc-DQmE0Pfk.js} +1 -1
  2. package/dist/cjs/{ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-B4jkHqvr.js → ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-B_nGMI1e.js} +19 -6
  3. package/dist/cjs/ogm-alerts_11.cjs.entry.js +1 -1
  4. package/dist/collection/components/ogm-attributes/ogm-attributes.js +1 -1
  5. package/dist/collection/components/ogm-attributes/ogm-attributes.test.js +24 -0
  6. package/dist/collection/lib/previewers/cog.js +5 -1
  7. package/dist/collection/lib/previewers/cog.test.js +61 -0
  8. package/dist/collection/lib/previewers/geojson.js +6 -1
  9. package/dist/collection/lib/previewers/geojson.test.js +81 -0
  10. package/dist/collection/lib/previewers/pmtiles-raster.js +5 -1
  11. package/dist/collection/lib/previewers/pmtiles.test.js +62 -0
  12. package/dist/collection/lib/previewers/wms.js +1 -1
  13. package/dist/esm/{lerc-BxCv6y50.js → lerc-BQHa9iiK.js} +1 -1
  14. package/dist/esm/{ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-DtEO48bS.js → ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-DSguoh85.js} +19 -6
  15. package/dist/esm/ogm-alerts_11.entry.js +1 -1
  16. package/dist/ogm-viewer/ogm-viewer.esm.js +1 -1
  17. package/dist/ogm-viewer/{p-7EhN80oi.js → p-667JHO1P.js} +2 -2
  18. package/dist/ogm-viewer/{p-BO_nFj5K.js → p-9T5uP6M8.js} +1 -1
  19. package/dist/ogm-viewer/{p-c9af56a3.entry.js → p-c95acce0.entry.js} +1 -1
  20. package/dist/types/components/ogm-attributes/ogm-attributes.test.d.ts +1 -0
  21. package/dist/types/lib/previewers/cog.d.ts +1 -0
  22. package/dist/types/lib/previewers/cog.test.d.ts +1 -0
  23. package/dist/types/lib/previewers/geojson.d.ts +1 -0
  24. package/dist/types/lib/previewers/geojson.test.d.ts +1 -0
  25. package/dist/types/lib/previewers/pmtiles-raster.d.ts +1 -0
  26. package/dist/types/lib/previewers/pmtiles.test.d.ts +1 -0
  27. package/package.json +1 -1
  28. package/readme.md +1 -1
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var pako_esm = require('./pako.esm-B4B6rBoN.js');
4
- var ogmAlerts_ogmAttributes_ogmImage_ogmMap_ogmMenubar_ogmMetadata_ogmPreview_ogmPreviews_ogmSettings_ogmSidebar_ogmViewer_entry = require('./ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-B4jkHqvr.js');
4
+ var ogmAlerts_ogmAttributes_ogmImage_ogmMap_ogmMenubar_ogmMetadata_ogmPreview_ogmPreviews_ogmSettings_ogmSidebar_ogmViewer_entry = require('./ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-B_nGMI1e.js');
5
5
  var basedecoder = require('./basedecoder-CIx0DB_u.js');
6
6
  require('./index-mu9UK_Fb.js');
7
7
 
@@ -4917,7 +4917,7 @@ const OgmAttributes = class {
4917
4917
  const feature = this.features[this.currentIndex];
4918
4918
  const multiple = this.features.length > 1;
4919
4919
  const label = getFeatureLabel(feature);
4920
- return (index.h("wa-scroller", { orientation: "vertical" }, index.h("table", { class: "attribute-table" }, multiple && label ? (index.h("thead", null, index.h("tr", { class: "header" }, index.h("td", { colSpan: 2 }, index.h("div", { class: "pagination" }, index.h("wa-button", { appearance: "plain", disabled: this.currentIndex === 0, onClick: () => this.currentIndex-- }, index.h("wa-icon", { name: "arrow-left", label: "Previous feature", canvas: "auto" })), label && (index.h("div", { class: "label" }, index.h("div", null, label))), index.h("div", { class: "count" }, ' ', "(", this.currentIndex + 1, "/", this.features.length, ")"), index.h("wa-button", { appearance: "plain", disabled: this.currentIndex === this.features.length - 1, onClick: () => this.currentIndex++ }, index.h("wa-icon", { name: "arrow-right", label: "Next feature", canvas: "auto" }))))))) : (label && (index.h("thead", null, index.h("tr", { class: "header" }, index.h("td", { colSpan: 2 }, index.h("div", { class: "label" }, index.h("div", null, label))))))), index.h("tbody", null, Object.entries(feature.properties || {}).map(([key, value]) => (index.h("tr", { key: key }, index.h("td", { class: "key" }, key), index.h("td", { class: "value", innerHTML: Autolinker.link(value.toString(), { hashtag: false, mention: false, phone: false }) }))))))));
4920
+ return (index.h("wa-scroller", { orientation: "vertical" }, index.h("table", { class: "attribute-table" }, multiple && label ? (index.h("thead", null, index.h("tr", { class: "header" }, index.h("td", { colSpan: 2 }, index.h("div", { class: "pagination" }, index.h("wa-button", { appearance: "plain", disabled: this.currentIndex === 0, onClick: () => this.currentIndex-- }, index.h("wa-icon", { name: "arrow-left", label: "Previous feature", canvas: "auto" })), label && (index.h("div", { class: "label" }, index.h("div", null, label))), index.h("div", { class: "count" }, ' ', "(", this.currentIndex + 1, "/", this.features.length, ")"), index.h("wa-button", { appearance: "plain", disabled: this.currentIndex === this.features.length - 1, onClick: () => this.currentIndex++ }, index.h("wa-icon", { name: "arrow-right", label: "Next feature", canvas: "auto" }))))))) : (label && (index.h("thead", null, index.h("tr", { class: "header" }, index.h("td", { colSpan: 2 }, index.h("div", { class: "label" }, index.h("div", null, label))))))), index.h("tbody", null, Object.entries(feature.properties || {}).map(([key, value]) => (index.h("tr", { key: key }, index.h("td", { class: "key" }, key), index.h("td", { class: "value", innerHTML: Autolinker.link(value?.toString() ?? '', { hashtag: false, mention: false, phone: false }) }))))))));
4921
4921
  }
4922
4922
  static get watchers() { return {
4923
4923
  "features": [{
@@ -45578,7 +45578,7 @@ const defaultDecoderDefinitions = [
45578
45578
  // LERC
45579
45579
  {
45580
45580
  cases: 34887,
45581
- importFn: () => Promise.resolve().then(function () { return require('./lerc-XQuzL9p2.js'); })
45581
+ importFn: () => Promise.resolve().then(function () { return require('./lerc-DQmE0Pfk.js'); })
45582
45582
  .then(async (m) => {
45583
45583
  await m.zstd.init();
45584
45584
  return m;
@@ -52482,11 +52482,15 @@ class CogPreviewer extends RasterPreviewer {
52482
52482
  super(resource, map, style);
52483
52483
  maplibregl.addProtocol('cog', cogProtocol);
52484
52484
  }
52485
+ // A COG has no scheme to name it by, and the raster layer draws from this too
52486
+ getSourceId() {
52487
+ return `${this.resource.id}-cog`;
52488
+ }
52485
52489
  // COG sources use 'url' instead of 'tiles' and have no scheme
52486
52490
  async createSources() {
52487
52491
  return [
52488
52492
  {
52489
- id: `${this.resource.id}-cog`,
52493
+ id: this.getSourceId(),
52490
52494
  type: 'raster',
52491
52495
  url: await this.resource.getMapLibreSourceUrl(),
52492
52496
  tileSize: this.resource.getTileSize(),
@@ -52682,10 +52686,15 @@ class VectorPreviewer extends MapPreviewer {
52682
52686
  }
52683
52687
 
52684
52688
  class GeoJsonPreviewer extends VectorPreviewer {
52689
+ // A record can reference the same data more than one way, so keep the sources distinct. The
52690
+ // style layers draw from this too, so both have to come from here.
52691
+ getSourceId() {
52692
+ return `${this.resource.id}-geojson`;
52693
+ }
52685
52694
  async createSources() {
52686
52695
  return [
52687
52696
  {
52688
- id: `${this.resource.id}-geojson`,
52697
+ id: this.getSourceId(),
52689
52698
  type: await this.resource.getMapLibreSourceType(),
52690
52699
  data: await this.resource.getMapLibreSourceUrl(),
52691
52700
  generateId: true, // autogenerate feature IDs for labeling
@@ -52698,11 +52707,15 @@ class OpenIndexMapPreviewer extends GeoJsonPreviewer {
52698
52707
  }
52699
52708
 
52700
52709
  class PMTilesRasterPreviewer extends RasterPreviewer {
52710
+ // An archive has no scheme to name it by, and the raster layer draws from this too
52711
+ getSourceId() {
52712
+ return `${this.resource.id}-pmtiles`;
52713
+ }
52701
52714
  // PMTiles sources use 'url' instead of 'tiles' and have no scheme or tileSize
52702
52715
  async createSources() {
52703
52716
  return [
52704
52717
  {
52705
- id: `${this.resource.id}-pmtiles`,
52718
+ id: this.getSourceId(),
52706
52719
  type: 'raster',
52707
52720
  url: await this.resource.getMapLibreSourceUrl(),
52708
52721
  },
@@ -52858,7 +52871,7 @@ class WmsPreviewer extends RasterPreviewer {
52858
52871
  async createSources() {
52859
52872
  return [
52860
52873
  {
52861
- id: `${this.resource.id}-wms`,
52874
+ id: this.getSourceId(),
52862
52875
  type: 'raster',
52863
52876
  tiles: [await this.resource.getMapLibreSourceUrl()],
52864
52877
  tileSize: this.resource.getTileSize(),
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var ogmAlerts_ogmAttributes_ogmImage_ogmMap_ogmMenubar_ogmMetadata_ogmPreview_ogmPreviews_ogmSettings_ogmSidebar_ogmViewer_entry = require('./ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-B4jkHqvr.js');
3
+ var ogmAlerts_ogmAttributes_ogmImage_ogmMap_ogmMenubar_ogmMetadata_ogmPreview_ogmPreviews_ogmSettings_ogmSidebar_ogmViewer_entry = require('./ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-B_nGMI1e.js');
4
4
  require('./index-mu9UK_Fb.js');
5
5
 
6
6
 
@@ -27,7 +27,7 @@ export class OgmAttributes {
27
27
  const feature = this.features[this.currentIndex];
28
28
  const multiple = this.features.length > 1;
29
29
  const label = getFeatureLabel(feature);
30
- return (h("wa-scroller", { orientation: "vertical" }, h("table", { class: "attribute-table" }, multiple && label ? (h("thead", null, h("tr", { class: "header" }, h("td", { colSpan: 2 }, h("div", { class: "pagination" }, h("wa-button", { appearance: "plain", disabled: this.currentIndex === 0, onClick: () => this.currentIndex-- }, h("wa-icon", { name: "arrow-left", label: "Previous feature", canvas: "auto" })), label && (h("div", { class: "label" }, h("div", null, label))), h("div", { class: "count" }, ' ', "(", this.currentIndex + 1, "/", this.features.length, ")"), h("wa-button", { appearance: "plain", disabled: this.currentIndex === this.features.length - 1, onClick: () => this.currentIndex++ }, h("wa-icon", { name: "arrow-right", label: "Next feature", canvas: "auto" }))))))) : (label && (h("thead", null, h("tr", { class: "header" }, h("td", { colSpan: 2 }, h("div", { class: "label" }, h("div", null, label))))))), h("tbody", null, Object.entries(feature.properties || {}).map(([key, value]) => (h("tr", { key: key }, h("td", { class: "key" }, key), h("td", { class: "value", innerHTML: Autolinker.link(value.toString(), { hashtag: false, mention: false, phone: false }) }))))))));
30
+ return (h("wa-scroller", { orientation: "vertical" }, h("table", { class: "attribute-table" }, multiple && label ? (h("thead", null, h("tr", { class: "header" }, h("td", { colSpan: 2 }, h("div", { class: "pagination" }, h("wa-button", { appearance: "plain", disabled: this.currentIndex === 0, onClick: () => this.currentIndex-- }, h("wa-icon", { name: "arrow-left", label: "Previous feature", canvas: "auto" })), label && (h("div", { class: "label" }, h("div", null, label))), h("div", { class: "count" }, ' ', "(", this.currentIndex + 1, "/", this.features.length, ")"), h("wa-button", { appearance: "plain", disabled: this.currentIndex === this.features.length - 1, onClick: () => this.currentIndex++ }, h("wa-icon", { name: "arrow-right", label: "Next feature", canvas: "auto" }))))))) : (label && (h("thead", null, h("tr", { class: "header" }, h("td", { colSpan: 2 }, h("div", { class: "label" }, h("div", null, label))))))), h("tbody", null, Object.entries(feature.properties || {}).map(([key, value]) => (h("tr", { key: key }, h("td", { class: "key" }, key), h("td", { class: "value", innerHTML: Autolinker.link(value?.toString() ?? '', { hashtag: false, mention: false, phone: false }) }))))))));
31
31
  }
32
32
  static get is() { return "ogm-attributes"; }
33
33
  static get encapsulation() { return "shadow"; }
@@ -0,0 +1,24 @@
1
+ import { render, describe, it, expect, h } from "@stencil/vitest";
2
+ // A WMS GetFeatureInfo response, where attributes that don't apply to the feature come back null
3
+ const feature = {
4
+ type: 'Feature',
5
+ id: 'cugir007741.1',
6
+ geometry: { type: 'Point', coordinates: [-73.903384, 44.365321] },
7
+ properties: { region: 5, stat_name: 'EMN - WHITEFACE MT. SMT', ozone: 'Y', pm_2_5: null },
8
+ };
9
+ const rows = (root) => Array.from(root.shadowRoot.querySelectorAll('tbody tr')).map(tr => Array.from(tr.querySelectorAll('td')).map(td => td.textContent));
10
+ describe('ogm-attributes', () => {
11
+ it('renders nothing without features', async () => {
12
+ const { root } = await render(h("ogm-attributes", { features: [] }));
13
+ expect(root.shadowRoot.querySelector('table')).toBeNull();
14
+ });
15
+ it('renders a row per attribute, leaving the value empty for a null', async () => {
16
+ const { root } = await render(h("ogm-attributes", { features: [feature] }));
17
+ expect(rows(root)).toEqual([
18
+ ['region', '5'],
19
+ ['stat_name', 'EMN - WHITEFACE MT. SMT'],
20
+ ['ozone', 'Y'],
21
+ ['pm_2_5', ''],
22
+ ]);
23
+ });
24
+ });
@@ -10,11 +10,15 @@ export default class CogPreviewer extends RasterPreviewer {
10
10
  super(resource, map, style);
11
11
  maplibregl.addProtocol('cog', cogProtocol);
12
12
  }
13
+ // A COG has no scheme to name it by, and the raster layer draws from this too
14
+ getSourceId() {
15
+ return `${this.resource.id}-cog`;
16
+ }
13
17
  // COG sources use 'url' instead of 'tiles' and have no scheme
14
18
  async createSources() {
15
19
  return [
16
20
  {
17
- id: `${this.resource.id}-cog`,
21
+ id: this.getSourceId(),
18
22
  type: 'raster',
19
23
  url: await this.resource.getMapLibreSourceUrl(),
20
24
  tileSize: this.resource.getTileSize(),
@@ -0,0 +1,61 @@
1
+ import { describe, it, expect } from "@stencil/vitest";
2
+ import CogPreviewer from "./cog";
3
+ import CogResource from "../resources/cog";
4
+ // Just enough of a MapLibre map to record what the previewer adds
5
+ class FakeMap {
6
+ sources = new Map();
7
+ layers = new Map();
8
+ getSource(id) {
9
+ return this.sources.get(id);
10
+ }
11
+ addSource(id, spec) {
12
+ this.sources.set(id, spec);
13
+ }
14
+ removeSource(id) {
15
+ this.sources.delete(id);
16
+ }
17
+ getLayer(id) {
18
+ return this.layers.get(id);
19
+ }
20
+ addLayer(layer) {
21
+ // MapLibre refuses a layer whose source hasn't been added yet
22
+ if (!this.sources.has(layer.source))
23
+ throw new Error(`No source ${layer.source} for layer ${layer.id}`);
24
+ this.layers.set(layer.id, layer);
25
+ }
26
+ removeLayer(id) {
27
+ this.layers.delete(id);
28
+ }
29
+ }
30
+ // The previewer only reads the opacity
31
+ const style = { opacity: 0.8 };
32
+ const COG_URL = 'https://example.com/scan.tif';
33
+ // Nothing here reads the GeoTIFF: the source is built from the URL alone
34
+ const preview = async () => {
35
+ const map = new FakeMap();
36
+ const previewer = new CogPreviewer(new CogResource('princeton-fk4544658v', COG_URL), map, style);
37
+ await previewer.preview();
38
+ return { map, previewer };
39
+ };
40
+ describe('CogPreviewer#preview', () => {
41
+ it('hands MapLibre the URL behind the cog:// protocol', async () => {
42
+ const { map, previewer } = await preview();
43
+ const source = map.sources.get('princeton-fk4544658v-cog');
44
+ expect(source.type).toEqual('raster');
45
+ expect(source.url).toEqual(`cog://${COG_URL}`);
46
+ expect(previewer.sourceIds).toEqual(['princeton-fk4544658v-cog']);
47
+ });
48
+ it('draws its raster layer from the source it added', async () => {
49
+ const { map, previewer } = await preview();
50
+ // A layer pointing at any other ID would be dropped by MapLibre, drawing nothing
51
+ expect([...map.layers.values()].every(layer => map.sources.has(layer.source))).toBe(true);
52
+ expect([...map.layers.keys()]).toEqual(['princeton-fk4544658v-cog']);
53
+ expect(previewer.layerIds).toEqual(['princeton-fk4544658v-cog']);
54
+ });
55
+ it('removes what it added when cleared', async () => {
56
+ const { map, previewer } = await preview();
57
+ await previewer.clearPreview();
58
+ expect(map.sources.size).toEqual(0);
59
+ expect(map.layers.size).toEqual(0);
60
+ });
61
+ });
@@ -1,9 +1,14 @@
1
1
  import VectorPreviewer from "./vector";
2
2
  export default class GeoJsonPreviewer extends VectorPreviewer {
3
+ // A record can reference the same data more than one way, so keep the sources distinct. The
4
+ // style layers draw from this too, so both have to come from here.
5
+ getSourceId() {
6
+ return `${this.resource.id}-geojson`;
7
+ }
3
8
  async createSources() {
4
9
  return [
5
10
  {
6
- id: `${this.resource.id}-geojson`,
11
+ id: this.getSourceId(),
7
12
  type: await this.resource.getMapLibreSourceType(),
8
13
  data: await this.resource.getMapLibreSourceUrl(),
9
14
  generateId: true, // autogenerate feature IDs for labeling
@@ -0,0 +1,81 @@
1
+ import { describe, it, expect } from "@stencil/vitest";
2
+ import GeoJsonPreviewer from "./geojson";
3
+ import OpenIndexMapPreviewer from "./openindexmap";
4
+ import GeoJsonResource from "../resources/geojson";
5
+ import OpenIndexMapResource from "../resources/openindexmap";
6
+ // Just enough of a MapLibre map to record what the previewer adds
7
+ class FakeMap {
8
+ sources = new Map();
9
+ layers = new Map();
10
+ getSource(id) {
11
+ return this.sources.get(id);
12
+ }
13
+ addSource(id, spec) {
14
+ this.sources.set(id, spec);
15
+ }
16
+ removeSource(id) {
17
+ this.sources.delete(id);
18
+ }
19
+ getLayer(id) {
20
+ return this.layers.get(id);
21
+ }
22
+ addLayer(layer) {
23
+ // MapLibre refuses a layer whose source hasn't been added yet
24
+ if (!this.sources.has(layer.source))
25
+ throw new Error(`No source ${layer.source} for layer ${layer.id}`);
26
+ this.layers.set(layer.id, layer);
27
+ }
28
+ removeLayer(id) {
29
+ this.layers.delete(id);
30
+ }
31
+ }
32
+ // The previewers only read the colors and label styles, none of which these tests assert on
33
+ const style = { opacity: 0.8, fillColor: '#00f', strokeColor: '#009', textColor: '#000', textFont: 'Noto Sans Regular', textSize: 12 };
34
+ const GEOJSON_URL = 'https://example.com/index-map.json';
35
+ // Nothing here fetches: the source URL and the layer names are known without reading the document
36
+ const previewGeoJson = async () => {
37
+ const map = new FakeMap();
38
+ const previewer = new GeoJsonPreviewer(new GeoJsonResource('princeton-fk4544658v', GEOJSON_URL), map, style);
39
+ await previewer.preview();
40
+ return { map, previewer };
41
+ };
42
+ const previewIndexMap = async () => {
43
+ const map = new FakeMap();
44
+ const previewer = new OpenIndexMapPreviewer(new OpenIndexMapResource('princeton-fk4544658v', GEOJSON_URL), map, style);
45
+ await previewer.preview();
46
+ return { map, previewer };
47
+ };
48
+ const SUFFIXES = ['polygons', 'polygon-outlines', 'lines', 'points', 'polygon-labels', 'line-labels', 'point-labels'];
49
+ describe('GeoJsonPreviewer#preview', () => {
50
+ it('hands MapLibre the document URL as a geojson source', async () => {
51
+ const { map, previewer } = await previewGeoJson();
52
+ const source = map.sources.get('princeton-fk4544658v-geojson');
53
+ expect(source.type).toEqual('geojson');
54
+ expect(source.data).toEqual(GEOJSON_URL);
55
+ expect(previewer.sourceIds).toEqual(['princeton-fk4544658v-geojson']);
56
+ });
57
+ it('draws its style layers from the source it added', async () => {
58
+ const { map } = await previewGeoJson();
59
+ // A layer pointing at any other ID would be dropped by MapLibre, drawing nothing
60
+ expect([...map.layers.values()].every(layer => map.sources.has(layer.source))).toBe(true);
61
+ expect([...map.layers.keys()]).toEqual(SUFFIXES.map(suffix => `princeton-fk4544658v-geojson-geojson-${suffix}`));
62
+ });
63
+ it('removes what it added when cleared', async () => {
64
+ const { map, previewer } = await previewGeoJson();
65
+ await previewer.clearPreview();
66
+ expect(map.sources.size).toEqual(0);
67
+ expect(map.layers.size).toEqual(0);
68
+ });
69
+ });
70
+ describe('OpenIndexMapPreviewer#preview', () => {
71
+ it('draws the index map polygons from the source it added', async () => {
72
+ const { map } = await previewIndexMap();
73
+ const polygons = map.layers.get('princeton-fk4544658v-geojson-indexmap-polygons');
74
+ expect(polygons.type).toEqual('fill');
75
+ expect(map.sources.has(polygons.source)).toBe(true);
76
+ });
77
+ it('styles the one layer an index map has', async () => {
78
+ const { map } = await previewIndexMap();
79
+ expect([...map.layers.keys()]).toEqual(SUFFIXES.map(suffix => `princeton-fk4544658v-geojson-indexmap-${suffix}`));
80
+ });
81
+ });
@@ -1,10 +1,14 @@
1
1
  import RasterPreviewer from "./raster";
2
2
  export default class PMTilesRasterPreviewer extends RasterPreviewer {
3
+ // An archive has no scheme to name it by, and the raster layer draws from this too
4
+ getSourceId() {
5
+ return `${this.resource.id}-pmtiles`;
6
+ }
3
7
  // PMTiles sources use 'url' instead of 'tiles' and have no scheme or tileSize
4
8
  async createSources() {
5
9
  return [
6
10
  {
7
- id: `${this.resource.id}-pmtiles`,
11
+ id: this.getSourceId(),
8
12
  type: 'raster',
9
13
  url: await this.resource.getMapLibreSourceUrl(),
10
14
  },
@@ -0,0 +1,62 @@
1
+ import { describe, it, expect } from "@stencil/vitest";
2
+ import PMTilesRasterPreviewer from "./pmtiles-raster";
3
+ import PMTilesResource from "../resources/pmtiles";
4
+ // Just enough of a MapLibre map to record what the previewer adds
5
+ class FakeMap {
6
+ sources = new Map();
7
+ layers = new Map();
8
+ getSource(id) {
9
+ return this.sources.get(id);
10
+ }
11
+ addSource(id, spec) {
12
+ this.sources.set(id, spec);
13
+ }
14
+ removeSource(id) {
15
+ this.sources.delete(id);
16
+ }
17
+ getLayer(id) {
18
+ return this.layers.get(id);
19
+ }
20
+ addLayer(layer) {
21
+ // MapLibre refuses a layer whose source hasn't been added yet
22
+ if (!this.sources.has(layer.source))
23
+ throw new Error(`No source ${layer.source} for layer ${layer.id}`);
24
+ this.layers.set(layer.id, layer);
25
+ }
26
+ removeLayer(id) {
27
+ this.layers.delete(id);
28
+ }
29
+ }
30
+ // The previewer only reads the opacity
31
+ const style = { opacity: 0.8 };
32
+ const PMTILES_URL = 'https://example.com/tiles.pmtiles';
33
+ // Nothing here reads the archive: the source is built from the URL alone, and the header is only
34
+ // touched for bounds
35
+ const preview = async () => {
36
+ const map = new FakeMap();
37
+ const previewer = new PMTilesRasterPreviewer(new PMTilesResource('princeton-fk4544658v', PMTILES_URL), map, style);
38
+ await previewer.preview();
39
+ return { map, previewer };
40
+ };
41
+ describe('PMTilesRasterPreviewer#preview', () => {
42
+ it('hands MapLibre the URL behind the pmtiles:// protocol', async () => {
43
+ const { map, previewer } = await preview();
44
+ const source = map.sources.get('princeton-fk4544658v-pmtiles');
45
+ expect(source.type).toEqual('raster');
46
+ expect(source.url).toEqual(`pmtiles://${PMTILES_URL}`);
47
+ expect(previewer.sourceIds).toEqual(['princeton-fk4544658v-pmtiles']);
48
+ });
49
+ it('draws its raster layer from the source it added', async () => {
50
+ const { map, previewer } = await preview();
51
+ // A layer pointing at any other ID would be dropped by MapLibre, drawing nothing
52
+ expect([...map.layers.values()].every(layer => map.sources.has(layer.source))).toBe(true);
53
+ expect([...map.layers.keys()]).toEqual(['princeton-fk4544658v-pmtiles']);
54
+ expect(previewer.layerIds).toEqual(['princeton-fk4544658v-pmtiles']);
55
+ });
56
+ it('removes what it added when cleared', async () => {
57
+ const { map, previewer } = await preview();
58
+ await previewer.clearPreview();
59
+ expect(map.sources.size).toEqual(0);
60
+ expect(map.layers.size).toEqual(0);
61
+ });
62
+ });
@@ -6,7 +6,7 @@ export default class WmsPreviewer extends RasterPreviewer {
6
6
  async createSources() {
7
7
  return [
8
8
  {
9
- id: `${this.resource.id}-wms`,
9
+ id: this.getSourceId(),
10
10
  type: 'raster',
11
11
  tiles: [await this.resource.getMapLibreSourceUrl()],
12
12
  tileSize: this.resource.getTileSize(),
@@ -1,5 +1,5 @@
1
1
  import { i as inflate_1 } from './pako.esm-KbdoS3Oq.js';
2
- import { g as getDefaultExportFromCjs, L as LercAddCompression, a as LercParameters } from './ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-DtEO48bS.js';
2
+ import { g as getDefaultExportFromCjs, L as LercAddCompression, a as LercParameters } from './ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-DSguoh85.js';
3
3
  import { B as BaseDecoder } from './basedecoder-BK531nfi.js';
4
4
  import './index-DTLAlWKQ.js';
5
5
 
@@ -4915,7 +4915,7 @@ const OgmAttributes = class {
4915
4915
  const feature = this.features[this.currentIndex];
4916
4916
  const multiple = this.features.length > 1;
4917
4917
  const label = getFeatureLabel(feature);
4918
- return (h$2("wa-scroller", { orientation: "vertical" }, h$2("table", { class: "attribute-table" }, multiple && label ? (h$2("thead", null, h$2("tr", { class: "header" }, h$2("td", { colSpan: 2 }, h$2("div", { class: "pagination" }, h$2("wa-button", { appearance: "plain", disabled: this.currentIndex === 0, onClick: () => this.currentIndex-- }, h$2("wa-icon", { name: "arrow-left", label: "Previous feature", canvas: "auto" })), label && (h$2("div", { class: "label" }, h$2("div", null, label))), h$2("div", { class: "count" }, ' ', "(", this.currentIndex + 1, "/", this.features.length, ")"), h$2("wa-button", { appearance: "plain", disabled: this.currentIndex === this.features.length - 1, onClick: () => this.currentIndex++ }, h$2("wa-icon", { name: "arrow-right", label: "Next feature", canvas: "auto" }))))))) : (label && (h$2("thead", null, h$2("tr", { class: "header" }, h$2("td", { colSpan: 2 }, h$2("div", { class: "label" }, h$2("div", null, label))))))), h$2("tbody", null, Object.entries(feature.properties || {}).map(([key, value]) => (h$2("tr", { key: key }, h$2("td", { class: "key" }, key), h$2("td", { class: "value", innerHTML: Autolinker.link(value.toString(), { hashtag: false, mention: false, phone: false }) }))))))));
4918
+ return (h$2("wa-scroller", { orientation: "vertical" }, h$2("table", { class: "attribute-table" }, multiple && label ? (h$2("thead", null, h$2("tr", { class: "header" }, h$2("td", { colSpan: 2 }, h$2("div", { class: "pagination" }, h$2("wa-button", { appearance: "plain", disabled: this.currentIndex === 0, onClick: () => this.currentIndex-- }, h$2("wa-icon", { name: "arrow-left", label: "Previous feature", canvas: "auto" })), label && (h$2("div", { class: "label" }, h$2("div", null, label))), h$2("div", { class: "count" }, ' ', "(", this.currentIndex + 1, "/", this.features.length, ")"), h$2("wa-button", { appearance: "plain", disabled: this.currentIndex === this.features.length - 1, onClick: () => this.currentIndex++ }, h$2("wa-icon", { name: "arrow-right", label: "Next feature", canvas: "auto" }))))))) : (label && (h$2("thead", null, h$2("tr", { class: "header" }, h$2("td", { colSpan: 2 }, h$2("div", { class: "label" }, h$2("div", null, label))))))), h$2("tbody", null, Object.entries(feature.properties || {}).map(([key, value]) => (h$2("tr", { key: key }, h$2("td", { class: "key" }, key), h$2("td", { class: "value", innerHTML: Autolinker.link(value?.toString() ?? '', { hashtag: false, mention: false, phone: false }) }))))))));
4919
4919
  }
4920
4920
  static get watchers() { return {
4921
4921
  "features": [{
@@ -45576,7 +45576,7 @@ const defaultDecoderDefinitions = [
45576
45576
  // LERC
45577
45577
  {
45578
45578
  cases: 34887,
45579
- importFn: () => import('./lerc-BxCv6y50.js')
45579
+ importFn: () => import('./lerc-BQHa9iiK.js')
45580
45580
  .then(async (m) => {
45581
45581
  await m.zstd.init();
45582
45582
  return m;
@@ -52480,11 +52480,15 @@ class CogPreviewer extends RasterPreviewer {
52480
52480
  super(resource, map, style);
52481
52481
  maplibregl.addProtocol('cog', cogProtocol);
52482
52482
  }
52483
+ // A COG has no scheme to name it by, and the raster layer draws from this too
52484
+ getSourceId() {
52485
+ return `${this.resource.id}-cog`;
52486
+ }
52483
52487
  // COG sources use 'url' instead of 'tiles' and have no scheme
52484
52488
  async createSources() {
52485
52489
  return [
52486
52490
  {
52487
- id: `${this.resource.id}-cog`,
52491
+ id: this.getSourceId(),
52488
52492
  type: 'raster',
52489
52493
  url: await this.resource.getMapLibreSourceUrl(),
52490
52494
  tileSize: this.resource.getTileSize(),
@@ -52680,10 +52684,15 @@ class VectorPreviewer extends MapPreviewer {
52680
52684
  }
52681
52685
 
52682
52686
  class GeoJsonPreviewer extends VectorPreviewer {
52687
+ // A record can reference the same data more than one way, so keep the sources distinct. The
52688
+ // style layers draw from this too, so both have to come from here.
52689
+ getSourceId() {
52690
+ return `${this.resource.id}-geojson`;
52691
+ }
52683
52692
  async createSources() {
52684
52693
  return [
52685
52694
  {
52686
- id: `${this.resource.id}-geojson`,
52695
+ id: this.getSourceId(),
52687
52696
  type: await this.resource.getMapLibreSourceType(),
52688
52697
  data: await this.resource.getMapLibreSourceUrl(),
52689
52698
  generateId: true, // autogenerate feature IDs for labeling
@@ -52696,11 +52705,15 @@ class OpenIndexMapPreviewer extends GeoJsonPreviewer {
52696
52705
  }
52697
52706
 
52698
52707
  class PMTilesRasterPreviewer extends RasterPreviewer {
52708
+ // An archive has no scheme to name it by, and the raster layer draws from this too
52709
+ getSourceId() {
52710
+ return `${this.resource.id}-pmtiles`;
52711
+ }
52699
52712
  // PMTiles sources use 'url' instead of 'tiles' and have no scheme or tileSize
52700
52713
  async createSources() {
52701
52714
  return [
52702
52715
  {
52703
- id: `${this.resource.id}-pmtiles`,
52716
+ id: this.getSourceId(),
52704
52717
  type: 'raster',
52705
52718
  url: await this.resource.getMapLibreSourceUrl(),
52706
52719
  },
@@ -52856,7 +52869,7 @@ class WmsPreviewer extends RasterPreviewer {
52856
52869
  async createSources() {
52857
52870
  return [
52858
52871
  {
52859
- id: `${this.resource.id}-wms`,
52872
+ id: this.getSourceId(),
52860
52873
  type: 'raster',
52861
52874
  tiles: [await this.resource.getMapLibreSourceUrl()],
52862
52875
  tileSize: this.resource.getTileSize(),
@@ -1,2 +1,2 @@
1
- export { O as ogm_alerts, b as ogm_attributes, c as ogm_image, d as ogm_map, e as ogm_menubar, f as ogm_metadata, h as ogm_preview, i as ogm_previews, j as ogm_settings, k as ogm_sidebar, l as ogm_viewer } from './ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-DtEO48bS.js';
1
+ export { O as ogm_alerts, b as ogm_attributes, c as ogm_image, d as ogm_map, e as ogm_menubar, f as ogm_metadata, h as ogm_preview, i as ogm_previews, j as ogm_settings, k as ogm_sidebar, l as ogm_viewer } from './ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-DSguoh85.js';
2
2
  import './index-DTLAlWKQ.js';
@@ -1 +1 @@
1
- import{p as e,b as r}from"./p-DTLAlWKQ.js";export{s as setNonce}from"./p-DTLAlWKQ.js";import{g as a}from"./p-DQuL1Twl.js";(()=>{const r=import.meta.url,a={};return""!==r&&(a.resourcesUrl=new URL(".",r).href),e(a)})().then((async e=>(await a(),r([["p-c9af56a3",[[513,"ogm-viewer",{recordUrl:[1,"record-url"],theme:[1],hideTitle:[4,"hide-title"],record:[32],error:[32],previewOpacity:[32],sidebarOpen:[32],loading:[32],loadRecord:[64]},[[0,"sidebarToggled","toggleSidebar"],[0,"opacityChange","adjustPreviewOpacity"],[0,"mapLoading","setLoadingStarted"],[0,"imageLoading","setLoadingStarted"],[0,"mapIdle","setLoadingFinished"],[0,"imageLoaded","setLoadingFinished"]],{recordUrl:[{updateRecord:0}],record:[{resetLoading:0}]}],[513,"ogm-previews",{theme:[1],record:[16],previewOpacity:[2,"preview-opacity"],sidebarPadding:[2,"sidebar-padding"],resources:[32]},null,{record:[{getSources:0}]}],[513,"ogm-sidebar",{record:[16],theme:[1],open:[4]}],[513,"ogm-menubar",{record:[16],theme:[1],loading:[4],hideTitle:[4,"hide-title"]}],[513,"ogm-preview",{theme:[1],previewResource:[16],previewOpacity:[2,"preview-opacity"],sidebarPadding:[2,"sidebar-padding"],error:[32]},[[0,"previewError","handlePreviewError"]],{previewResource:[{resetError:0}]}],[513,"ogm-metadata",{record:[16],theme:[1],fieldNames:[16],filteredRecord:[32]}],[513,"ogm-settings",{record:[16]},[[0,"input","handleOpacityChange"]]],[513,"ogm-map",{previewResource:[16],theme:[1],padding:[2],easeMapTo:[64]},[[16,"featureSelected","handleFeatureSelected"]],{previewResource:[{loadResource:0}],theme:[{onThemeChange:0}],padding:[{onPaddingChange:0}]}],[513,"ogm-alerts",{theme:[1],error:[16]}],[513,"ogm-image",{previewResource:[16],theme:[1],padding:[2]},null,{previewResource:[{onSourceChange:0}],padding:[{onPaddingChange:0}]}],[513,"ogm-attributes",{features:[16],currentIndex:[32]},null,{features:[{onFeaturesChange:0}],currentIndex:[{onCurrentIndexChange:0}]}]]]],e))));
1
+ import{p as e,b as r}from"./p-DTLAlWKQ.js";export{s as setNonce}from"./p-DTLAlWKQ.js";import{g as a}from"./p-DQuL1Twl.js";(()=>{const r=import.meta.url,a={};return""!==r&&(a.resourcesUrl=new URL(".",r).href),e(a)})().then((async e=>(await a(),r([["p-c95acce0",[[513,"ogm-viewer",{recordUrl:[1,"record-url"],theme:[1],hideTitle:[4,"hide-title"],record:[32],error:[32],previewOpacity:[32],sidebarOpen:[32],loading:[32],loadRecord:[64]},[[0,"sidebarToggled","toggleSidebar"],[0,"opacityChange","adjustPreviewOpacity"],[0,"mapLoading","setLoadingStarted"],[0,"imageLoading","setLoadingStarted"],[0,"mapIdle","setLoadingFinished"],[0,"imageLoaded","setLoadingFinished"]],{recordUrl:[{updateRecord:0}],record:[{resetLoading:0}]}],[513,"ogm-previews",{theme:[1],record:[16],previewOpacity:[2,"preview-opacity"],sidebarPadding:[2,"sidebar-padding"],resources:[32]},null,{record:[{getSources:0}]}],[513,"ogm-sidebar",{record:[16],theme:[1],open:[4]}],[513,"ogm-menubar",{record:[16],theme:[1],loading:[4],hideTitle:[4,"hide-title"]}],[513,"ogm-preview",{theme:[1],previewResource:[16],previewOpacity:[2,"preview-opacity"],sidebarPadding:[2,"sidebar-padding"],error:[32]},[[0,"previewError","handlePreviewError"]],{previewResource:[{resetError:0}]}],[513,"ogm-metadata",{record:[16],theme:[1],fieldNames:[16],filteredRecord:[32]}],[513,"ogm-settings",{record:[16]},[[0,"input","handleOpacityChange"]]],[513,"ogm-map",{previewResource:[16],theme:[1],padding:[2],easeMapTo:[64]},[[16,"featureSelected","handleFeatureSelected"]],{previewResource:[{loadResource:0}],theme:[{onThemeChange:0}],padding:[{onPaddingChange:0}]}],[513,"ogm-alerts",{theme:[1],error:[16]}],[513,"ogm-image",{previewResource:[16],theme:[1],padding:[2]},null,{previewResource:[{onSourceChange:0}],padding:[{onPaddingChange:0}]}],[513,"ogm-attributes",{features:[16],currentIndex:[32]},null,{features:[{onFeaturesChange:0}],currentIndex:[{onCurrentIndexChange:0}]}]]]],e))));