A web-based viewer for previewing OpenGeoMetadata records. Try the online demo!
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';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.
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>You can style the viewer's colors by setting CSS custom properties on its element.
ogm-viewer {
--ogm-fill-color: #8f1414;
--ogm-stroke-color: #4a0a0a;
}Here are the supported properties and what they apply to:
| Property | Applies to |
|---|---|
--ogm-fill-color |
Polygon and circle fill |
--ogm-fill-highlight-color |
Fill of a hovered feature |
--ogm-fill-selected-color |
Fill of the feature whose attributes are shown |
--ogm-fill-invalid-color |
Fill of a feature marked unavailable |
--ogm-stroke-color |
Lines, and polygon and circle borders |
--ogm-stroke-highlight-color |
Stroke of a hovered feature |
--ogm-stroke-selected-color |
Stroke of the selected feature |
--ogm-stroke-invalid-color |
Stroke 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-fill-opacity |
Initial opacity of drawn data |
--ogm-fill-highlight-opacity |
Opacity of a highlighted feature |
--ogm-padding |
Gap kept between the data and the map edge (pixels) |
By default, the viewer uses styles from Web Awesome that match the current mode (dark or light). Anything you override will be used in both modes.
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).
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);
}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.
After cloning the repository, install dependencies:
npm installYou can start a local development web server with:
npm startCode 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 lintYou 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.
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.