Skip to content

Repository files navigation

CI Built With Stencil

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-viewer

Then 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-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.

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:

  1. Inside the manifest, following the annotation pages a canvas links until it finds one.
  2. Failing that, a dct_references_s key of https://iiif.io/api/extension/georef/1/context.json pointing 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 install

You can start a local development web server with:

npm start

Formatting

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 lint

Tests

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 tests

Unit 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.Z

The 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.

About

A web-based viewer for OpenGeoMetadata records

Resources

Stars

3 stars

Watchers

2 watching

Forks

Releases

Contributors

Languages