ogm-viewer
v0.10.0
Published
A web-based viewer for previewing OpenGeoMetadata records
Downloads
979
Readme
OpenGeoMetadata Viewer
A web-based viewer for previewing OpenGeoMetadata records. Try the online demo!
Installation
You can add the viewer to your project by including the following script tag in your HTML:
<script type="module" src="https://unpkg.com/ogm-viewer"></script>If using a bundler, you can install it via npm:
npm install ogm-viewerThen add it to your entrypoint file:
import 'ogm-viewer';Usage
Once installed, the viewer can be used in your HTML as a web component:
<ogm-viewer record-url="https://example.com/record.json"></ogm-viewer>The record-url attribute should point to a valid OpenGeoMetadata Aardvark record in JSON format.
You can also programmatically set the record URL using JavaScript:
const viewer = document.querySelector('ogm-viewer');
viewer.recordUrl = 'https://example.com/record.json';When the record URL changes, the viewer will automatically fetch and display the record data.
Dark mode support
The viewer supports dark mode. If your system preference is set to prefer dark mode, the viewer will automatically apply dark styles.
To programmatically control dark mode, you can use the theme attribute with a value of dark or light:
<ogm-viewer record-url="https://example.com/record.json" theme="dark"></ogm-viewer>Colors
You can style the viewer's colors by setting CSS custom properties on its element.
ogm-viewer {
--ogm-data-color: #8f1414;
}Here are the supported properties and what they apply to:
| Property | Applies to |
| ------------------------------ | ---------------------------------------------------- |
| --ogm-data-color | Polygon fill, line geometry, and circle fill |
| --ogm-highlight-color | The same, for a hovered feature |
| --ogm-selected-color | The same, for the feature whose attributes are shown |
| --ogm-invalid-color | The same, for a feature marked unavailable |
| --ogm-stroke-color | Polygon outlines and circle borders |
| --ogm-stroke-highlight-color | Outline of a hovered feature |
| --ogm-stroke-selected-color | Outline of the selected feature |
| --ogm-stroke-invalid-color | Outline of a feature marked unavailable |
| --ogm-text-color | Feature label text color |
| --ogm-text-halo-color | Feature label text outline color |
| --ogm-text-size | Feature label font size, in pixels |
| --ogm-font-family | Feature label font name (e.g. "Noto Sans Regular") |
| --ogm-data-opacity | Initial opacity of drawn data |
| --ogm-highlight-opacity | Opacity of a highlighted feature |
| --ogm-bounds-opacity | Initial opacity of a bounding box or index map |
| --ogm-padding | Gap kept between the data and the view edge (pixels) |
By default, the viewer uses styles from Web Awesome that match the current mode (dark or light).
You usually only need the four --ogm-*-color properties, plus --ogm-text-color. The rest are derived:
- Each outline comes from the color it outlines, moved away from the basemap: darker in light mode, lighter in dark mode. A color you name is used in both modes, but its outline follows the mode, so one declaration reads on either basemap.
- The label halo comes from
--ogm-text-color, as black or white — whichever contrasts more, the same choice CSScontrast-color()makes. It doesn't consult the mode, because the text color already did.
--ogm-stroke-* and --ogm-text-halo-color are there if you want particular ones instead. Like the other colors, one you name is used in both modes.
Restricted content
For previews of data that need authentication to access, you can set a custom requestTransform function to add headers or cookies to the request. It's a DOM property on <ogm-viewer> that you can set in JavaScript, like the recordUrl property:
viewer.requestTransform = (url, resourceType) => {
// If we aren't requesting something from the restricted area, don't do anything
if (!url.startsWith('https://geo.my-domain.edu/restricted/')) return undefined;
// Otherwise, add an Authorization header with a bearer token
return { headers: { Authorization: `Bearer ${token}` } };
};If you're building a Resource by hand instead, pass the same kind of function as its last constructor argument (or to resourcesFor, if you're building several from a record):
import { GeoJsonResource } from 'ogm-viewer/lib';
const resource = new GeoJsonResource('my-layer', 'https://example.com/restricted/data.json', undefined, requestTransform);The requestTransform will be applied to all requests made by the viewer for that resource, including metadata and tiles, as well as the requests for the MapLibre basemap. The one exception to this is Georeferenced maps using the Allmaps plugin – there's currently no way to fetch these using authentication (see below for more).
Georeferenced maps
A scanned map with a IIIF Georeference Annotation is previewable two ways: as an image to page through, and as a layer warped onto the map. Both come from one IIIFManifestResource, so <ogm-viewer> shows them as two tabs, image first.
The viewer finds the annotation itself, looking in this order:
- Inside the manifest, following the annotation pages a canvas links until it finds one.
- Failing that, a
dct_references_skey ofhttps://iiif.io/api/extension/georef/1/context.jsonpointing at a standalone annotation.
When a record has both, the copy in the manifest wins. Only the first canvas is inspected, so a paged object with an annotation per page is left alone for now.
The map tab is drawn flat, has no globe button, and can't be tilted. These are constraints based on Allmaps' rendering engine, which is used to warp the image. There's also no way to hook into Allmaps' tile requests, so if the annotation points at a restricted image, it won't be able to fetch it. The viewer will still show the image tab, but the map tab will be blank.
To build a preview by hand, the manifest resource takes the standalone annotation URL as its last argument, and works out the rest:
import { GeoreferencePreviewer, IIIFManifestResource } from 'ogm-viewer/lib';
const resource = new IIIFManifestResource('my-map', manifestUrl, undefined, undefined, annotationUrl);
if (await resource.isGeoreferenced()) {
document.querySelector('ogm-preview').previewer = new GeoreferencePreviewer(resource);
}Components
If you're building your own viewer, you can adopt <ogm-viewer>'s components individually.
The easiest way to render a single preview without the full viewer is to use the <ogm-preview> component with a Previewer and corresponding Resource. For example, to preview a GeoJSON resource:
import 'ogm-viewer';
import { GeoJsonPreviewer, GeoJsonResource } from 'ogm-viewer/lib';
await customElements.whenDefined('ogm-preview');
const resource = new GeoJsonResource('my-layer', 'https://example.com/data.json');
document.querySelector('ogm-preview').previewer = new GeoJsonPreviewer(resource);Note that previewer is a DOM property, not an attribute — await for the element to be defined and then set it in JavaScript.
For more than one preview, <ogm-previews> renders the same tab strip <ogm-viewer> uses. Hand it a record and it works out what that record offers; hand it previewers and it uses those instead:
document.querySelector('ogm-previews').previewers = [new GeoJsonPreviewer(geoJsonResource), new OpenIndexMapPreviewer(indexMapResource)];record and previewers are DOM properties too. Neither component has an intrinsic size, so the embedding page should set it via CSS.
Development
After cloning the repository, install dependencies:
npm installYou can start a local development web server with:
npm startFormatting
Code is formatted using Prettier. To format your code for a pull request, run:
npx prettier --write .To type-check and lint your code, run:
npm run lintTests
You can run all tests together or specify a test type:
npm test # runs all tests
npm run test:unit # runs only unit tests
npm run test:component # runs only component testsUnit tests use the *.test.ts extension, while component tests use *.test.tsx.
For more information on testing, see the Stencil documentation.
Releasing
Pushing a version tag publishes it. Update the version in package.json, run npm install so the lockfile agrees, and commit that on main. Then tag it:
git tag vX.Y.Z # replace with your new version number
git push origin vX.Y.ZThe Release workflow checks that the tag and package.json agree, lints, tests, publishes to npm, and drafts the GitHub release with generated notes. It authenticates with npm over OIDC using trusted publishing.
