ogm-viewer 0.3.0 → 0.5.0

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 (215) hide show
  1. package/dist/cjs/{index-CVTUnaNg.js → index-mu9UK_Fb.js} +66 -3
  2. package/dist/cjs/{lerc-TQEssgMv.js → lerc-Df0hDWkS.js} +7 -7
  3. package/dist/cjs/loader.cjs.js +2 -2
  4. package/dist/cjs/{ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-settings.ogm-sidebar.ogm-viewer-ifPxRNEo.js → ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-DMEfXquS.js} +13843 -6976
  5. package/dist/cjs/ogm-alerts_11.cjs.entry.js +18 -0
  6. package/dist/cjs/ogm-viewer.cjs.js +2 -2
  7. package/dist/collection/assets/icons/exclamation-triangle-fill.svg +3 -0
  8. package/dist/collection/assets/webawesome/styles/color/palettes/base.css +44 -0
  9. package/dist/collection/assets/webawesome/styles/color/palettes/bright.css +145 -0
  10. package/dist/collection/assets/webawesome/styles/color/palettes/default.css +146 -0
  11. package/dist/collection/assets/webawesome/styles/color/palettes/shoelace.css +146 -0
  12. package/dist/collection/assets/webawesome/styles/color/variants/brand.css +162 -0
  13. package/dist/collection/assets/webawesome/styles/color/variants/danger.css +162 -0
  14. package/dist/collection/assets/webawesome/styles/color/variants/neutral.css +162 -0
  15. package/dist/collection/assets/webawesome/styles/color/variants/success.css +162 -0
  16. package/dist/collection/assets/webawesome/styles/color/variants/warning.css +162 -0
  17. package/dist/collection/assets/webawesome/styles/color/variants.css +5 -0
  18. package/dist/collection/assets/webawesome/styles/component/form-control.styles.d.ts +2 -0
  19. package/dist/collection/assets/webawesome/styles/component/form-control.styles.ts +43 -0
  20. package/dist/collection/assets/webawesome/styles/component/host.styles.d.ts +2 -0
  21. package/dist/collection/assets/webawesome/styles/component/host.styles.ts +18 -0
  22. package/dist/collection/assets/webawesome/styles/component/segmented-field.styles.d.ts +19 -0
  23. package/dist/collection/assets/webawesome/styles/component/segmented-field.styles.ts +92 -0
  24. package/dist/collection/assets/webawesome/styles/component/size.styles.d.ts +2 -0
  25. package/dist/collection/assets/webawesome/styles/component/size.styles.ts +26 -0
  26. package/dist/collection/assets/webawesome/styles/component/variants.styles.d.ts +2 -0
  27. package/dist/collection/assets/webawesome/styles/component/variants.styles.ts +69 -0
  28. package/dist/collection/assets/webawesome/styles/component/visually-hidden.styles.d.ts +2 -0
  29. package/dist/collection/assets/webawesome/styles/component/visually-hidden.styles.ts +19 -0
  30. package/dist/collection/assets/webawesome/styles/layers.css +21 -0
  31. package/dist/collection/assets/webawesome/styles/native.css +1439 -0
  32. package/dist/collection/assets/webawesome/styles/themes/awesome.css +614 -0
  33. package/dist/collection/assets/webawesome/styles/themes/default.css +373 -0
  34. package/dist/collection/assets/webawesome/styles/themes/shoelace.css +648 -0
  35. package/dist/collection/assets/webawesome/styles/utilities/align-items.css +44 -0
  36. package/dist/collection/assets/webawesome/styles/utilities/border-radius.css +20 -0
  37. package/dist/collection/assets/webawesome/styles/utilities/flex-wrap.css +16 -0
  38. package/dist/collection/assets/webawesome/styles/utilities/fouce.css +17 -0
  39. package/dist/collection/assets/webawesome/styles/utilities/gap.css +56 -0
  40. package/dist/collection/assets/webawesome/styles/utilities/justify-content.css +32 -0
  41. package/dist/collection/assets/webawesome/styles/utilities/layout.css +159 -0
  42. package/dist/collection/assets/webawesome/styles/utilities/placeholder.css +9 -0
  43. package/dist/collection/assets/webawesome/styles/utilities/prose.css +161 -0
  44. package/dist/collection/assets/webawesome/styles/utilities/scroll-lock.css +20 -0
  45. package/dist/collection/assets/webawesome/styles/utilities/size.css +21 -0
  46. package/dist/collection/assets/webawesome/styles/utilities/text.css +262 -0
  47. package/dist/collection/assets/webawesome/styles/utilities/variants.css +62 -0
  48. package/dist/collection/assets/webawesome/styles/utilities/visually-hidden.css +17 -0
  49. package/dist/collection/assets/webawesome/styles/utilities.css +17 -0
  50. package/dist/collection/assets/webawesome/styles/webawesome.css +11 -0
  51. package/dist/collection/collection-manifest.json +4 -0
  52. package/dist/collection/components/ogm-alerts/ogm-alerts.css +51 -0
  53. package/dist/collection/components/ogm-alerts/ogm-alerts.js +71 -0
  54. package/dist/collection/components/ogm-alerts/ogm-alerts.test.js +26 -0
  55. package/dist/collection/components/ogm-attributes/ogm-attributes.css +68 -0
  56. package/dist/collection/components/ogm-attributes/ogm-attributes.js +112 -0
  57. package/dist/collection/components/ogm-image/ogm-image.css +1 -1
  58. package/dist/collection/components/ogm-image/ogm-image.js +70 -20
  59. package/dist/collection/components/ogm-map/ogm-map.css +43 -44
  60. package/dist/collection/components/ogm-map/ogm-map.js +229 -91
  61. package/dist/collection/components/ogm-menubar/ogm-menubar.css +16 -14
  62. package/dist/collection/components/ogm-menubar/ogm-menubar.js +3 -5
  63. package/dist/collection/components/ogm-menubar/ogm-menubar.test.js +28 -3
  64. package/dist/collection/components/ogm-metadata/ogm-metadata.css +6 -492
  65. package/dist/collection/components/ogm-metadata/ogm-metadata.js +3 -5
  66. package/dist/collection/components/ogm-metadata/ogm-metadata.test.js +1 -1
  67. package/dist/collection/components/ogm-preview/ogm-preview.css +16 -0
  68. package/dist/collection/components/ogm-preview/ogm-preview.js +144 -0
  69. package/dist/collection/components/ogm-preview/ogm-preview.test.js +37 -0
  70. package/dist/collection/components/ogm-previews/ogm-previews.css +45 -0
  71. package/dist/collection/components/ogm-previews/ogm-previews.js +162 -0
  72. package/dist/collection/components/ogm-previews/ogm-previews.test.js +83 -0
  73. package/dist/collection/components/ogm-settings/ogm-settings.js +7 -9
  74. package/dist/collection/components/ogm-sidebar/ogm-sidebar.css +50 -503
  75. package/dist/collection/components/ogm-sidebar/ogm-sidebar.js +8 -12
  76. package/dist/collection/components/ogm-viewer/ogm-viewer.css +4 -974
  77. package/dist/collection/components/ogm-viewer/ogm-viewer.js +69 -32
  78. package/dist/collection/lib/errors.js +137 -0
  79. package/dist/collection/lib/errors.test.js +96 -0
  80. package/dist/collection/lib/previewers/cog-deck.js +14 -9
  81. package/dist/collection/lib/previewers/cog.js +3 -3
  82. package/dist/collection/lib/previewers/geojson.js +3 -2
  83. package/dist/collection/lib/previewers/maplibre.js +9 -15
  84. package/dist/collection/lib/previewers/pmtiles-raster.js +1 -1
  85. package/dist/collection/lib/previewers/pmtiles-vector.js +7 -1
  86. package/dist/collection/lib/previewers/raster.js +1 -1
  87. package/dist/collection/lib/previewers/vector.js +65 -30
  88. package/dist/collection/lib/previewers/wms.js +1 -1
  89. package/dist/collection/lib/record.js +1 -1
  90. package/dist/collection/lib/record.test.js +1 -1
  91. package/dist/collection/lib/references.js +0 -65
  92. package/dist/collection/lib/references.test.js +0 -150
  93. package/dist/collection/lib/sources/cog.js +5 -2
  94. package/dist/collection/lib/sources/geojson.js +9 -2
  95. package/dist/collection/lib/sources/iiif-manifest.js +54 -0
  96. package/dist/collection/lib/sources/iiif-manifest.test.js +110 -0
  97. package/dist/collection/lib/sources/iiif.js +11 -0
  98. package/dist/collection/lib/sources/maplibre.js +8 -0
  99. package/dist/collection/lib/sources/openindexmap.js +3 -0
  100. package/dist/collection/lib/sources/pmtiles.js +10 -4
  101. package/dist/collection/lib/sources/raster.js +3 -3
  102. package/dist/collection/lib/sources/source.js +26 -7
  103. package/dist/collection/lib/sources/tilejson.js +7 -1
  104. package/dist/collection/lib/sources/tms.js +3 -0
  105. package/dist/collection/lib/sources/vector.js +3 -3
  106. package/dist/collection/lib/sources/wms.js +6 -11
  107. package/dist/collection/lib/sources/xyz.js +3 -0
  108. package/dist/collection/lib/themes/maplibre.js +46 -0
  109. package/dist/collection/lib/themes/theme.js +23 -0
  110. package/dist/esm/{index-BdFT_kJa.js → index-DTLAlWKQ.js} +66 -3
  111. package/dist/esm/{lerc-DFDScDrO.js → lerc-CB_Jcu33.js} +2 -2
  112. package/dist/esm/loader.js +3 -3
  113. package/dist/esm/{ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-settings.ogm-sidebar.ogm-viewer-r5w_49n3.js → ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-Dlc6USWB.js} +13840 -6977
  114. package/dist/esm/ogm-alerts_11.entry.js +2 -0
  115. package/dist/esm/ogm-viewer.js +3 -3
  116. package/dist/ogm-viewer/assets/icons/exclamation-triangle-fill.svg +3 -0
  117. package/dist/ogm-viewer/assets/webawesome/styles/color/palettes/base.css +44 -0
  118. package/dist/ogm-viewer/assets/webawesome/styles/color/palettes/bright.css +145 -0
  119. package/dist/ogm-viewer/assets/webawesome/styles/color/palettes/default.css +146 -0
  120. package/dist/ogm-viewer/assets/webawesome/styles/color/palettes/shoelace.css +146 -0
  121. package/dist/ogm-viewer/assets/webawesome/styles/color/variants/brand.css +162 -0
  122. package/dist/ogm-viewer/assets/webawesome/styles/color/variants/danger.css +162 -0
  123. package/dist/ogm-viewer/assets/webawesome/styles/color/variants/neutral.css +162 -0
  124. package/dist/ogm-viewer/assets/webawesome/styles/color/variants/success.css +162 -0
  125. package/dist/ogm-viewer/assets/webawesome/styles/color/variants/warning.css +162 -0
  126. package/dist/ogm-viewer/assets/webawesome/styles/color/variants.css +5 -0
  127. package/dist/ogm-viewer/assets/webawesome/styles/component/form-control.styles.d.ts +2 -0
  128. package/dist/ogm-viewer/assets/webawesome/styles/component/form-control.styles.ts +43 -0
  129. package/dist/ogm-viewer/assets/webawesome/styles/component/host.styles.d.ts +2 -0
  130. package/dist/ogm-viewer/assets/webawesome/styles/component/host.styles.ts +18 -0
  131. package/dist/ogm-viewer/assets/webawesome/styles/component/segmented-field.styles.d.ts +19 -0
  132. package/dist/ogm-viewer/assets/webawesome/styles/component/segmented-field.styles.ts +92 -0
  133. package/dist/ogm-viewer/assets/webawesome/styles/component/size.styles.d.ts +2 -0
  134. package/dist/ogm-viewer/assets/webawesome/styles/component/size.styles.ts +26 -0
  135. package/dist/ogm-viewer/assets/webawesome/styles/component/variants.styles.d.ts +2 -0
  136. package/dist/ogm-viewer/assets/webawesome/styles/component/variants.styles.ts +69 -0
  137. package/dist/ogm-viewer/assets/webawesome/styles/component/visually-hidden.styles.d.ts +2 -0
  138. package/dist/ogm-viewer/assets/webawesome/styles/component/visually-hidden.styles.ts +19 -0
  139. package/dist/ogm-viewer/assets/webawesome/styles/layers.css +21 -0
  140. package/dist/ogm-viewer/assets/webawesome/styles/native.css +1439 -0
  141. package/dist/ogm-viewer/assets/webawesome/styles/themes/awesome.css +614 -0
  142. package/dist/ogm-viewer/assets/webawesome/styles/themes/default.css +373 -0
  143. package/dist/ogm-viewer/assets/webawesome/styles/themes/shoelace.css +648 -0
  144. package/dist/ogm-viewer/assets/webawesome/styles/utilities/align-items.css +44 -0
  145. package/dist/ogm-viewer/assets/webawesome/styles/utilities/border-radius.css +20 -0
  146. package/dist/ogm-viewer/assets/webawesome/styles/utilities/flex-wrap.css +16 -0
  147. package/dist/ogm-viewer/assets/webawesome/styles/utilities/fouce.css +17 -0
  148. package/dist/ogm-viewer/assets/webawesome/styles/utilities/gap.css +56 -0
  149. package/dist/ogm-viewer/assets/webawesome/styles/utilities/justify-content.css +32 -0
  150. package/dist/ogm-viewer/assets/webawesome/styles/utilities/layout.css +159 -0
  151. package/dist/ogm-viewer/assets/webawesome/styles/utilities/placeholder.css +9 -0
  152. package/dist/ogm-viewer/assets/webawesome/styles/utilities/prose.css +161 -0
  153. package/dist/ogm-viewer/assets/webawesome/styles/utilities/scroll-lock.css +20 -0
  154. package/dist/ogm-viewer/assets/webawesome/styles/utilities/size.css +21 -0
  155. package/dist/ogm-viewer/assets/webawesome/styles/utilities/text.css +262 -0
  156. package/dist/ogm-viewer/assets/webawesome/styles/utilities/variants.css +62 -0
  157. package/dist/ogm-viewer/assets/webawesome/styles/utilities/visually-hidden.css +17 -0
  158. package/dist/ogm-viewer/assets/webawesome/styles/utilities.css +17 -0
  159. package/dist/ogm-viewer/assets/webawesome/styles/webawesome.css +11 -0
  160. package/dist/ogm-viewer/ogm-viewer.esm.js +1 -1
  161. package/dist/ogm-viewer/p-7936ccc9.entry.js +1 -0
  162. package/dist/ogm-viewer/p-CWtUrqsM.js +2822 -0
  163. package/dist/ogm-viewer/p-DTLAlWKQ.js +2 -0
  164. package/dist/ogm-viewer/{p-BeA3REDA.js → p-DqRDI3AC.js} +1 -1
  165. package/dist/types/components/ogm-alerts/ogm-alerts.d.ts +6 -0
  166. package/dist/types/components/ogm-alerts/ogm-alerts.test.d.ts +1 -0
  167. package/dist/types/components/ogm-attributes/ogm-attributes.d.ts +10 -0
  168. package/dist/types/components/ogm-image/ogm-image.d.ts +8 -3
  169. package/dist/types/components/ogm-map/ogm-map.d.ts +38 -14
  170. package/dist/types/components/ogm-menubar/ogm-menubar.d.ts +1 -1
  171. package/dist/types/components/ogm-metadata/ogm-metadata.d.ts +1 -1
  172. package/dist/types/components/ogm-preview/ogm-preview.d.ts +13 -0
  173. package/dist/types/components/ogm-preview/ogm-preview.test.d.ts +1 -0
  174. package/dist/types/components/ogm-previews/ogm-previews.d.ts +12 -0
  175. package/dist/types/components/ogm-previews/ogm-previews.test.d.ts +1 -0
  176. package/dist/types/components/ogm-settings/ogm-settings.d.ts +2 -2
  177. package/dist/types/components/ogm-sidebar/ogm-sidebar.d.ts +1 -1
  178. package/dist/types/components/ogm-viewer/ogm-viewer.d.ts +17 -14
  179. package/dist/types/components.d.ts +122 -18
  180. package/dist/types/lib/errors.d.ts +13 -0
  181. package/dist/types/lib/errors.test.d.ts +1 -0
  182. package/dist/types/lib/previewers/cog-deck.d.ts +7 -3
  183. package/dist/types/lib/previewers/cog.d.ts +2 -2
  184. package/dist/types/lib/previewers/maplibre.d.ts +7 -9
  185. package/dist/types/lib/previewers/pmtiles-vector.d.ts +1 -0
  186. package/dist/types/lib/previewers/vector.d.ts +3 -15
  187. package/dist/types/lib/record.d.ts +1 -1
  188. package/dist/types/lib/references.d.ts +0 -8
  189. package/dist/types/lib/sources/cog.d.ts +3 -2
  190. package/dist/types/lib/sources/geojson.d.ts +3 -2
  191. package/dist/types/lib/sources/iiif-manifest.d.ts +12 -0
  192. package/dist/types/lib/sources/iiif-manifest.test.d.ts +1 -0
  193. package/dist/types/lib/sources/iiif.d.ts +5 -0
  194. package/dist/types/lib/sources/maplibre.d.ts +7 -0
  195. package/dist/types/lib/sources/openindexmap.d.ts +1 -0
  196. package/dist/types/lib/sources/pmtiles.d.ts +6 -4
  197. package/dist/types/lib/sources/raster.d.ts +3 -3
  198. package/dist/types/lib/sources/source.d.ts +7 -7
  199. package/dist/types/lib/sources/tilejson.d.ts +3 -2
  200. package/dist/types/lib/sources/tms.d.ts +1 -0
  201. package/dist/types/lib/sources/vector.d.ts +4 -5
  202. package/dist/types/lib/sources/wms.d.ts +4 -3
  203. package/dist/types/lib/sources/xyz.d.ts +1 -0
  204. package/dist/types/lib/themes/maplibre.d.ts +27 -0
  205. package/dist/types/lib/themes/theme.d.ts +7 -0
  206. package/package.json +3 -2
  207. package/dist/cjs/ogm-image_7.cjs.entry.js +0 -14
  208. package/dist/collection/lib/previewers/index.js +0 -36
  209. package/dist/collection/lib/sources/index.js +0 -29
  210. package/dist/esm/ogm-image_7.entry.js +0 -2
  211. package/dist/ogm-viewer/p-0b81e024.entry.js +0 -1
  212. package/dist/ogm-viewer/p-33R3d9fV.js +0 -1950
  213. package/dist/ogm-viewer/p-BdFT_kJa.js +0 -2
  214. package/dist/types/lib/previewers/index.d.ts +0 -3
  215. package/dist/types/lib/sources/index.d.ts +0 -3
@@ -1,18 +1,5 @@
1
1
  import MapLibrePreviewer from "./maplibre";
2
- const defaultOptions = {
3
- fillColor: '#888888',
4
- fillOpacity: 0.6,
5
- fillHighlightOpacity: 0.8,
6
- lineColor: '#000000',
7
- labelFont: 'Noto Sans Regular',
8
- labelSize: 10,
9
- textColor: '#000000',
10
- };
11
2
  export default class VectorPreviewer extends MapLibrePreviewer {
12
- constructor(source, map, options) {
13
- super(source, map, options);
14
- this.options = { ...defaultOptions, ...options };
15
- }
16
3
  // Set opacity of all layers in this previewer
17
4
  async setOpacity(opacity) {
18
5
  this.opacity = opacity;
@@ -28,6 +15,7 @@ export default class VectorPreviewer extends MapLibrePreviewer {
28
15
  return layerIds.flatMap(layerId => {
29
16
  return [
30
17
  this.createPolygonLayer(layerId),
18
+ this.createPolygonOutlineLayer(layerId),
31
19
  this.createLineLayer(layerId),
32
20
  this.createPointLayer(layerId),
33
21
  this.createPolygonLabelLayer(layerId),
@@ -43,9 +31,35 @@ export default class VectorPreviewer extends MapLibrePreviewer {
43
31
  type: 'fill',
44
32
  source: this.getSourceId(),
45
33
  paint: {
46
- 'fill-color': this.options.fillColor,
47
- 'fill-outline-color': this.options.lineColor,
48
- 'fill-opacity': ['case', ['boolean', ['feature-state', 'hover'], false], this.options.fillHighlightOpacity, this.options.fillOpacity],
34
+ 'fill-color': [
35
+ 'case',
36
+ ['boolean', ['feature-state', 'selected'], false],
37
+ this.style.fillSelectedColor,
38
+ ['boolean', ['feature-state', 'hover'], false],
39
+ this.style.fillHighlightColor,
40
+ this.style.fillColor,
41
+ ],
42
+ 'fill-opacity': ['case', ['boolean', ['feature-state', 'selected'], false], this.style.fillHighlightOpacity, this.style.fillOpacity],
43
+ },
44
+ filter: ['==', ['geometry-type'], 'Polygon'],
45
+ };
46
+ }
47
+ // Create a styled layer that will be used to outline polygon geometry
48
+ createPolygonOutlineLayer(layerId) {
49
+ return {
50
+ id: `${this.getSourceId()}-${layerId}-polygon-outlines`,
51
+ type: 'line',
52
+ source: this.getSourceId(),
53
+ paint: {
54
+ 'line-color': [
55
+ 'case',
56
+ ['boolean', ['feature-state', 'selected'], false],
57
+ this.style.strokeSelectedColor,
58
+ ['boolean', ['feature-state', 'hover'], false],
59
+ this.style.strokeHighlightColor,
60
+ this.style.strokeColor,
61
+ ],
62
+ 'line-width': ['case', ['boolean', ['feature-state', 'selected'], false], 2, 1],
49
63
  },
50
64
  filter: ['==', ['geometry-type'], 'Polygon'],
51
65
  };
@@ -57,7 +71,14 @@ export default class VectorPreviewer extends MapLibrePreviewer {
57
71
  type: 'line',
58
72
  source: this.getSourceId(),
59
73
  paint: {
60
- 'line-color': this.options.lineColor,
74
+ 'line-color': [
75
+ 'case',
76
+ ['boolean', ['feature-state', 'selected'], false],
77
+ this.style.strokeSelectedColor,
78
+ ['boolean', ['feature-state', 'hover'], false],
79
+ this.style.strokeHighlightColor,
80
+ this.style.strokeColor,
81
+ ],
61
82
  'line-width': 4,
62
83
  },
63
84
  filter: ['==', ['geometry-type'], 'LineString'],
@@ -70,11 +91,25 @@ export default class VectorPreviewer extends MapLibrePreviewer {
70
91
  type: 'circle',
71
92
  source: this.getSourceId(),
72
93
  paint: {
73
- 'circle-color': this.options.fillColor,
74
- 'circle-stroke-color': this.options.lineColor,
75
- 'circle-stroke-width': ['case', ['boolean', ['feature-state', 'hover'], false], 2, 1],
94
+ 'circle-color': [
95
+ 'case',
96
+ ['boolean', ['feature-state', 'selected'], false],
97
+ this.style.fillSelectedColor,
98
+ ['boolean', ['feature-state', 'hover'], false],
99
+ this.style.fillHighlightColor,
100
+ this.style.fillColor,
101
+ ],
102
+ 'circle-stroke-color': [
103
+ 'case',
104
+ ['boolean', ['feature-state', 'selected'], false],
105
+ this.style.strokeSelectedColor,
106
+ ['boolean', ['feature-state', 'hover'], false],
107
+ this.style.strokeHighlightColor,
108
+ this.style.strokeColor,
109
+ ],
110
+ 'circle-stroke-width': ['case', ['boolean', ['feature-state', 'selected'], false], 2, 1],
76
111
  'circle-radius': ['interpolate', ['linear'], ['zoom'], 4, 2, 12, 4],
77
- 'circle-opacity': ['case', ['boolean', ['feature-state', 'hover'], false], this.options.fillHighlightOpacity, this.options.fillOpacity],
112
+ 'circle-opacity': ['case', ['boolean', ['feature-state', 'selected'], false], this.style.fillHighlightOpacity, this.style.fillOpacity],
78
113
  },
79
114
  filter: ['==', ['geometry-type'], 'Point'],
80
115
  };
@@ -87,9 +122,9 @@ export default class VectorPreviewer extends MapLibrePreviewer {
87
122
  source: this.getSourceId(),
88
123
  layout: {
89
124
  'text-field': ['get', 'id'],
90
- 'text-font': [this.options.labelFont],
125
+ 'text-font': [this.style.textFont],
91
126
  'text-max-angle': 85,
92
- 'text-size': this.options.labelSize,
127
+ 'text-size': this.style.textSize,
93
128
  'text-offset': [0, 1],
94
129
  'text-anchor': 'bottom',
95
130
  'text-rotation-alignment': 'map',
@@ -98,7 +133,7 @@ export default class VectorPreviewer extends MapLibrePreviewer {
98
133
  'symbol-spacing': 250,
99
134
  },
100
135
  paint: {
101
- 'text-color': this.options.textColor,
136
+ 'text-color': this.style.textColor,
102
137
  'text-halo-color': 'white',
103
138
  'text-halo-width': 1,
104
139
  },
@@ -114,11 +149,11 @@ export default class VectorPreviewer extends MapLibrePreviewer {
114
149
  layout: {
115
150
  'symbol-placement': 'line',
116
151
  'text-field': ['get', 'id'],
117
- 'text-font': [this.options.labelFont],
118
- 'text-size': this.options.labelSize,
152
+ 'text-font': [this.style.textFont],
153
+ 'text-size': this.style.textSize,
119
154
  },
120
155
  paint: {
121
- 'text-color': this.options.textColor,
156
+ 'text-color': this.style.textColor,
122
157
  'text-halo-color': 'white',
123
158
  'text-halo-width': 1,
124
159
  },
@@ -133,12 +168,12 @@ export default class VectorPreviewer extends MapLibrePreviewer {
133
168
  source: this.getSourceId(),
134
169
  layout: {
135
170
  'text-field': ['get', 'id'],
136
- 'text-font': [this.options.labelFont],
137
- 'text-size': this.options.labelSize,
171
+ 'text-font': [this.style.textFont],
172
+ 'text-size': this.style.textSize,
138
173
  'text-offset': [0, -1],
139
174
  },
140
175
  paint: {
141
- 'text-color': this.options.textColor,
176
+ 'text-color': this.style.textColor,
142
177
  'text-halo-color': 'white',
143
178
  'text-halo-width': 1,
144
179
  },
@@ -4,7 +4,7 @@ export default class WmsPreviewer extends RasterPreviewer {
4
4
  async createSource() {
5
5
  return {
6
6
  type: 'raster',
7
- tiles: [await this.source.getSourceUrl()],
7
+ tiles: [await this.source.getMapLibreSourceUrl()],
8
8
  tileSize: this.source.getTileSize(),
9
9
  };
10
10
  }
@@ -50,7 +50,7 @@ export const OGM_FIELD_NAMES = {
50
50
  /**
51
51
  * Class for representing an OGM Aardvark record parsed from JSON data.
52
52
  */
53
- export class OgmRecord {
53
+ export default class OgmRecord {
54
54
  // Original JSON data
55
55
  json;
56
56
  // Required
@@ -1,6 +1,6 @@
1
1
  import { describe, it, expect, vi } from "@stencil/vitest";
2
- import { OgmRecord } from "./record";
3
2
  import { LngLatBounds } from "maplibre-gl";
3
+ import OgmRecord from "./record";
4
4
  describe('OgmRecord', () => {
5
5
  it('errors when initialized with an unsupported version', () => {
6
6
  expect(() => {
@@ -35,8 +35,6 @@ const METADATA_REFERENCE_URIS = [
35
35
  export class References {
36
36
  // Underlying object to hold references
37
37
  references;
38
- // Cache for fetched IIIF manifest
39
- iiifManifest;
40
38
  // Create a new instance with the JSON string from a record
41
39
  constructor(dct_references_s) {
42
40
  try {
@@ -91,33 +89,6 @@ export class References {
91
89
  get iiifManifestUrl() {
92
90
  return this.references['http://iiif.io/api/presentation#manifest'];
93
91
  }
94
- // List of IIIF image URLs extracted from the manifest
95
- async iiifImageUrls() {
96
- if (this.iiifImageUrl)
97
- return [this.iiifImageUrl];
98
- if (!this.iiifManifestUrl)
99
- return [];
100
- // Fetch and cache the manifest if we haven't already
101
- if (!this.iiifManifest) {
102
- try {
103
- await this.fetchManifest();
104
- }
105
- catch (error) {
106
- console.error('Failed to fetch IIIF manifest:', error);
107
- return [];
108
- }
109
- }
110
- // Try to extract image URLs from the manifest
111
- try {
112
- if (this.iiifVersion == 3)
113
- return this.extractIiif3ImageUrls(this.iiifManifest);
114
- return this.extractIiif2ImageUrls(this.iiifManifest);
115
- }
116
- catch (error) {
117
- console.error('Failed to extract IIIF image URLs from manifest:', error);
118
- return [];
119
- }
120
- }
121
92
  // List of download links with URL and label, if using multiple downloads
122
93
  get downloadLinks() {
123
94
  const fieldContents = this.references['http://schema.org/downloadUrl'];
@@ -169,40 +140,4 @@ export class References {
169
140
  get iiifReferences() {
170
141
  return [this.iiifImageUrl, this.iiifManifestUrl];
171
142
  }
172
- // Get the IIIF presentation spec version of the manifest, if we have one
173
- get iiifVersion() {
174
- return this.iiifManifest['@context']?.includes('http://iiif.io/api/presentation/3/context.json') ? 3 : 2;
175
- }
176
- // Given a v2 manifest, extract all of the IIIF images and format as info.json URLs
177
- extractIiif2ImageUrls(manifest) {
178
- return (manifest.sequences
179
- .flatMap(seq => seq.canvases)
180
- .flatMap(can => can.images)
181
- .flatMap(img => img.resource)
182
- //@ts-ignore
183
- .flatMap(res => (res['@type'] === 'dctypes:Image' ? res.service['@id'] + '/info.json' : [])));
184
- }
185
- // Given a v3 manifest, extract all of the IIIF images and format as info.json URLs
186
- extractIiif3ImageUrls(manifest) {
187
- // Recursively search the '.items' key until we end up with nodes that have type 'ImageService2'
188
- return (manifest.items
189
- .flatMap(canvas => canvas.items)
190
- .flatMap(annotationPage => annotationPage?.items || [])
191
- .flatMap(annotation => (Array.isArray(annotation.body) ? annotation.body : [annotation.body]))
192
- //@ts-ignore
193
- .flatMap(annotationBody => annotationBody.service)
194
- .flatMap(service => service.id + '/info.json'));
195
- }
196
- // TODO: use navPlace as the bounds source if available
197
- // Attempt to fetch and parse the IIIF manifest, if any
198
- async fetchManifest() {
199
- if (!this.iiifManifestUrl)
200
- return;
201
- const response = await fetch(this.iiifManifestUrl);
202
- if (!response.ok)
203
- throw new Error(`Unexpected response fetching IIIF manifest: ${response.statusText}`);
204
- const manifest = await response.json();
205
- this.iiifManifest = manifest;
206
- return manifest;
207
- }
208
143
  }
@@ -74,156 +74,6 @@ describe('References', () => {
74
74
  expect(references.iiifManifestUrl).toBe('http://example.com/manifest.json');
75
75
  });
76
76
  });
77
- describe('Fetching IIIF image URLs', () => {
78
- it('should return IIIF image URL directly if present', async () => {
79
- const contents = { 'http://iiif.io/api/image': 'http://example.com/image1/info.json' };
80
- const references = new References(JSON.stringify(contents));
81
- const urls = await references.iiifImageUrls();
82
- expect(urls).toEqual(['http://example.com/image1/info.json']);
83
- });
84
- it('should fetch and extract image URLs from IIIF v2 manifest', async () => {
85
- const manifest = {
86
- '@context': 'http://iiif.io/api/presentation/2/context.json',
87
- '@id': 'http://example.com/manifest.json',
88
- '@type': 'sc:Manifest',
89
- 'sequences': [
90
- {
91
- canvases: [
92
- {
93
- images: [
94
- {
95
- resource: {
96
- '@id': 'http://example.com/image1/full/full/0/default.jpg',
97
- '@type': 'dctypes:Image',
98
- 'service': {
99
- '@id': 'http://example.com/image1',
100
- },
101
- },
102
- },
103
- ],
104
- },
105
- ],
106
- },
107
- ],
108
- };
109
- const references = new References(JSON.stringify({ 'http://iiif.io/api/presentation#manifest': 'http://example.com/manifest.json' }));
110
- vi.spyOn(global, 'fetch').mockResolvedValueOnce(new Response(JSON.stringify(manifest)));
111
- const urls = await references.iiifImageUrls();
112
- expect(urls).toEqual(['http://example.com/image1/info.json']);
113
- });
114
- it('should fetch and extract image URLs from IIIF v3 manifest', async () => {
115
- const manifest = {
116
- '@context': 'http://iiif.io/api/presentation/3/context.json',
117
- 'id': 'http://example.com/manifest.json',
118
- 'type': 'Manifest',
119
- 'items': [
120
- {
121
- id: 'http://example.com/canvas1',
122
- type: 'Canvas',
123
- items: [
124
- {
125
- id: 'http://example.com/annotationpage1',
126
- type: 'AnnotationPage',
127
- items: [
128
- {
129
- id: 'http://example.com/annotation1',
130
- type: 'Annotation',
131
- body: {
132
- id: 'http://example.com/image1/full/full/0/default.jpg',
133
- type: 'Image',
134
- service: {
135
- id: 'http://example.com/image1',
136
- type: 'ImageService2',
137
- },
138
- },
139
- },
140
- ],
141
- },
142
- ],
143
- },
144
- ],
145
- };
146
- const references = new References(JSON.stringify({ 'http://iiif.io/api/presentation#manifest': 'http://example.com/manifest.json' }));
147
- vi.spyOn(global, 'fetch').mockResolvedValueOnce(new Response(JSON.stringify(manifest)));
148
- const urls = await references.iiifImageUrls();
149
- expect(urls).toEqual(['http://example.com/image1/info.json']);
150
- });
151
- it('should not fetch manifest again if already cached', async () => {
152
- const manifest = {
153
- '@context': 'http://iiif.io/api/presentation/2/context.json',
154
- '@id': 'http://example.com/manifest.json',
155
- '@type': 'sc:Manifest',
156
- 'sequences': [
157
- {
158
- canvases: [
159
- {
160
- images: [
161
- {
162
- resource: {
163
- '@id': 'http://example.com/image1/full/full/0/default.jpg',
164
- '@type': 'dctypes:Image',
165
- 'service': {
166
- '@id': 'http://example.com/image1',
167
- },
168
- },
169
- },
170
- ],
171
- },
172
- ],
173
- },
174
- ],
175
- };
176
- const references = new References(JSON.stringify({ 'http://iiif.io/api/presentation#manifest': 'http://example.com/manifest.json' }));
177
- const fetchSpy = vi.spyOn(global, 'fetch').mockResolvedValueOnce(new Response(JSON.stringify(manifest)));
178
- const urls1 = await references.iiifImageUrls();
179
- const urls2 = await references.iiifImageUrls();
180
- expect(fetchSpy).toHaveBeenCalledTimes(1);
181
- expect(urls1).toEqual(['http://example.com/image1/info.json']);
182
- expect(urls2).toEqual(['http://example.com/image1/info.json']);
183
- });
184
- it('should return empty array if manifest URL is not present', async () => {
185
- const references = new References('{}');
186
- const urls = await references.iiifImageUrls();
187
- expect(urls).toEqual([]);
188
- });
189
- it('should return empty array if manifest has no items', async () => {
190
- const manifest = {
191
- '@context': 'http://iiif.io/api/presentation/3/context.json',
192
- 'id': 'http://example.com/manifest.json',
193
- 'type': 'Manifest',
194
- 'items': [],
195
- };
196
- const references = new References(JSON.stringify({ 'http://iiif.io/api/presentation#manifest': 'http://example.com/manifest.json' }));
197
- vi.spyOn(global, 'fetch').mockResolvedValueOnce(new Response(JSON.stringify(manifest)));
198
- const urls = await references.iiifImageUrls();
199
- expect(urls).toEqual([]);
200
- });
201
- it('should return empty array and error if manifest fetch fails', async () => {
202
- const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
203
- const references = new References(JSON.stringify({ 'http://iiif.io/api/presentation#manifest': 'http://example.com/manifest.json' }));
204
- vi.spyOn(global, 'fetch').mockRejectedValueOnce(new Error('Network error'));
205
- const urls = await references.iiifImageUrls();
206
- expect(urls).toEqual([]);
207
- expect(consoleErrorSpy).toHaveBeenCalled();
208
- });
209
- it('should return empty array and error if manifest does not match spec', async () => {
210
- const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
211
- const manifest = { unexpected: 'structure' };
212
- const references = new References(JSON.stringify({ 'http://iiif.io/api/presentation#manifest': 'http://example.com/manifest.json' }));
213
- vi.spyOn(global, 'fetch').mockResolvedValueOnce(new Response(JSON.stringify(manifest)));
214
- const urls = await references.iiifImageUrls();
215
- expect(urls).toEqual([]);
216
- expect(consoleErrorSpy).toHaveBeenCalled();
217
- });
218
- it('should return empty array if manifest is not valid JSON', async () => {
219
- const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
220
- const references = new References(JSON.stringify({ 'http://iiif.io/api/presentation#manifest': 'http://example.com/manifest.json' }));
221
- vi.spyOn(global, 'fetch').mockResolvedValueOnce(new Response('invalid json'));
222
- const urls = await references.iiifImageUrls();
223
- expect(urls).toEqual([]);
224
- expect(consoleErrorSpy).toHaveBeenCalled();
225
- });
226
- });
227
77
  describe('downloads', () => {
228
78
  it('should return empty links list if no download links are present', () => {
229
79
  const references = new References('{}');
@@ -1,7 +1,10 @@
1
1
  import RasterSource from "./raster";
2
2
  export default class CogSource extends RasterSource {
3
+ label() {
4
+ return 'Cloud Optimized GeoTIFF';
5
+ }
3
6
  // Appends the cog:// protocol; must be registered first to work
4
- getSourceUrl() {
7
+ getMapLibreSourceUrl() {
5
8
  return `cog://${this.url}`;
6
9
  }
7
10
  // COGs have no specific scheme identifier for MapLibre
@@ -10,6 +13,6 @@ export default class CogSource extends RasterSource {
10
13
  }
11
14
  // TODO: is it possible to read COG metadata to get bounds?
12
15
  async getBounds() {
13
- return undefined;
16
+ return super.getBounds();
14
17
  }
15
18
  }
@@ -1,16 +1,20 @@
1
1
  import geojsonExtent from "@mapbox/geojson-extent";
2
2
  import VectorSource from "./vector";
3
+ import { fetchOrThrow } from "../errors";
3
4
  export default class GeoJSONSource extends VectorSource {
4
5
  // Data parsed from GeoJSON document
5
6
  data;
6
7
  // Fetch and memoize data
7
8
  async getData() {
8
9
  if (!this.data) {
9
- const resp = await fetch(this.url);
10
+ const resp = await fetchOrThrow(this.url);
10
11
  this.data = await resp.json();
11
12
  }
12
13
  return this.data;
13
14
  }
15
+ label() {
16
+ return 'GeoJSON';
17
+ }
14
18
  // GeoJSON is always a vector source
15
19
  async isVector() {
16
20
  return true;
@@ -20,14 +24,17 @@ export default class GeoJSONSource extends VectorSource {
20
24
  return undefined;
21
25
  }
22
26
  // GeoJSON has a special source type
23
- async getType() {
27
+ async getMapLibreSourceType() {
24
28
  return 'geojson';
25
29
  }
26
30
  // Only one layer in a GeoJSON document
27
31
  async getVectorLayers() {
28
32
  return ['geojson'];
29
33
  }
34
+ // Used to zoom the map to the data once loaded
30
35
  async getBounds() {
36
+ if (this.bounds)
37
+ return this.bounds;
31
38
  const data = await this.getData();
32
39
  const bounds = geojsonExtent(data);
33
40
  return [
@@ -0,0 +1,54 @@
1
+ import IIIFSource from "./iiif";
2
+ import { fetchOrThrow } from "../errors";
3
+ // A manifest containing multiple IIIF image URLs for preview
4
+ export default class IIIFManifestSource extends IIIFSource {
5
+ // The parsed manifest contents
6
+ manifest;
7
+ label() {
8
+ return 'IIIF Manifest';
9
+ }
10
+ // List of IIIF image URLs extracted from the manifest
11
+ async getIIIFImageUrls() {
12
+ // Fetch and cache the manifest if we haven't already
13
+ const manifest = await this.fetchManifest();
14
+ if (!manifest)
15
+ return [];
16
+ // Try to extract image URLs from the manifest
17
+ if (this.getIIIFVersion(manifest) == 3)
18
+ return this.extractIiif3ImageUrls(manifest);
19
+ return this.extractIiif2ImageUrls(manifest);
20
+ }
21
+ // Attempt to fetch and parse the IIIF manifest, if any
22
+ async fetchManifest() {
23
+ if (this.manifest)
24
+ return this.manifest;
25
+ const response = await fetchOrThrow(this.url);
26
+ const manifest = await response.json();
27
+ this.manifest = manifest;
28
+ return manifest;
29
+ }
30
+ // Get the IIIF presentation spec version of the manifest
31
+ getIIIFVersion(manifest) {
32
+ return manifest['@context']?.includes('http://iiif.io/api/presentation/3/context.json') ? 3 : 2;
33
+ }
34
+ // Given a v2 manifest, extract all of the IIIF images and format as info.json URLs
35
+ extractIiif2ImageUrls(manifest) {
36
+ return (manifest.sequences
37
+ .flatMap(seq => seq.canvases)
38
+ .flatMap(can => can.images)
39
+ .flatMap(img => img.resource)
40
+ //@ts-ignore
41
+ .flatMap(res => (res['@type'] === 'dctypes:Image' ? res.service['@id'] + '/info.json' : [])));
42
+ }
43
+ // Given a v3 manifest, extract all of the IIIF images and format as info.json URLs
44
+ extractIiif3ImageUrls(manifest) {
45
+ // Recursively search the '.items' key until we end up with nodes that have type 'ImageService2'
46
+ return (manifest.items
47
+ .flatMap(canvas => canvas.items)
48
+ .flatMap(annotationPage => annotationPage?.items || [])
49
+ .flatMap(annotation => (Array.isArray(annotation.body) ? annotation.body : [annotation.body]))
50
+ //@ts-ignore
51
+ .flatMap(annotationBody => annotationBody.service)
52
+ .flatMap(service => service.id + '/info.json'));
53
+ }
54
+ }
@@ -0,0 +1,110 @@
1
+ import { describe, it, expect, vi, afterEach } from "@stencil/vitest";
2
+ import IIIFManifestSource from "./iiif-manifest";
3
+ const MANIFEST_URL = 'http://example.com/manifest.json';
4
+ // A source always points at a manifest URL; the manifest itself is fetched lazily
5
+ const createSource = () => new IIIFManifestSource('test-id', MANIFEST_URL);
6
+ // A minimal IIIF v2 manifest with a single image
7
+ const v2Manifest = {
8
+ '@context': 'http://iiif.io/api/presentation/2/context.json',
9
+ '@id': MANIFEST_URL,
10
+ '@type': 'sc:Manifest',
11
+ 'sequences': [
12
+ {
13
+ canvases: [
14
+ {
15
+ images: [
16
+ {
17
+ resource: {
18
+ '@id': 'http://example.com/image1/full/full/0/default.jpg',
19
+ '@type': 'dctypes:Image',
20
+ 'service': {
21
+ '@id': 'http://example.com/image1',
22
+ },
23
+ },
24
+ },
25
+ ],
26
+ },
27
+ ],
28
+ },
29
+ ],
30
+ };
31
+ // A minimal IIIF v3 manifest with a single image
32
+ const v3Manifest = {
33
+ '@context': 'http://iiif.io/api/presentation/3/context.json',
34
+ 'id': MANIFEST_URL,
35
+ 'type': 'Manifest',
36
+ 'items': [
37
+ {
38
+ id: 'http://example.com/canvas1',
39
+ type: 'Canvas',
40
+ items: [
41
+ {
42
+ id: 'http://example.com/annotationpage1',
43
+ type: 'AnnotationPage',
44
+ items: [
45
+ {
46
+ id: 'http://example.com/annotation1',
47
+ type: 'Annotation',
48
+ body: {
49
+ id: 'http://example.com/image1/full/full/0/default.jpg',
50
+ type: 'Image',
51
+ service: {
52
+ id: 'http://example.com/image1',
53
+ type: 'ImageService2',
54
+ },
55
+ },
56
+ },
57
+ ],
58
+ },
59
+ ],
60
+ },
61
+ ],
62
+ };
63
+ describe('IIIFManifestSource', () => {
64
+ afterEach(() => vi.restoreAllMocks());
65
+ describe('getIIIFImageUrls', () => {
66
+ it('should fetch and extract image URLs from a IIIF v2 manifest', async () => {
67
+ const fetchSpy = vi.spyOn(global, 'fetch').mockResolvedValueOnce(new Response(JSON.stringify(v2Manifest)));
68
+ const urls = await createSource().getIIIFImageUrls();
69
+ expect(fetchSpy.mock.calls[0][0]).toBe(MANIFEST_URL);
70
+ expect(urls).toEqual(['http://example.com/image1/info.json']);
71
+ });
72
+ it('should fetch and extract image URLs from a IIIF v3 manifest', async () => {
73
+ const fetchSpy = vi.spyOn(global, 'fetch').mockResolvedValueOnce(new Response(JSON.stringify(v3Manifest)));
74
+ const urls = await createSource().getIIIFImageUrls();
75
+ expect(fetchSpy.mock.calls[0][0]).toBe(MANIFEST_URL);
76
+ expect(urls).toEqual(['http://example.com/image1/info.json']);
77
+ });
78
+ it('should not fetch the manifest again if already cached', async () => {
79
+ const fetchSpy = vi.spyOn(global, 'fetch').mockResolvedValueOnce(new Response(JSON.stringify(v2Manifest)));
80
+ const source = createSource();
81
+ const urls1 = await source.getIIIFImageUrls();
82
+ const urls2 = await source.getIIIFImageUrls();
83
+ expect(fetchSpy).toHaveBeenCalledTimes(1);
84
+ expect(urls1).toEqual(['http://example.com/image1/info.json']);
85
+ expect(urls2).toEqual(['http://example.com/image1/info.json']);
86
+ });
87
+ it('should return an empty array if the manifest has no items', async () => {
88
+ const manifest = { ...v3Manifest, items: [] };
89
+ vi.spyOn(global, 'fetch').mockResolvedValueOnce(new Response(JSON.stringify(manifest)));
90
+ const urls = await createSource().getIIIFImageUrls();
91
+ expect(urls).toEqual([]);
92
+ });
93
+ it('should throw if the manifest fetch fails', async () => {
94
+ vi.spyOn(global, 'fetch').mockRejectedValueOnce(new Error('Network error'));
95
+ await expect(createSource().getIIIFImageUrls()).rejects.toThrow('Network error');
96
+ });
97
+ it('should throw an HttpError if the manifest response is not ok', async () => {
98
+ vi.spyOn(global, 'fetch').mockResolvedValueOnce(new Response('Not found', { status: 404, statusText: 'Not Found' }));
99
+ await expect(createSource().getIIIFImageUrls()).rejects.toMatchObject({ name: 'HttpError', status: 404 });
100
+ });
101
+ it('should throw if the manifest is not valid JSON', async () => {
102
+ vi.spyOn(global, 'fetch').mockResolvedValueOnce(new Response('invalid json'));
103
+ await expect(createSource().getIIIFImageUrls()).rejects.toThrow();
104
+ });
105
+ it('should throw if the manifest does not match the IIIF spec', async () => {
106
+ vi.spyOn(global, 'fetch').mockResolvedValueOnce(new Response(JSON.stringify({ unexpected: 'structure' })));
107
+ await expect(createSource().getIIIFImageUrls()).rejects.toThrow();
108
+ });
109
+ });
110
+ });