@projektemacher/storymapjs 0.10.8 → 0.11.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.
- package/CHANGELOG +81 -0
- package/README.md +129 -12
- package/dist/assets/{demo-DBpeF31K.js → demo-bWnOyfUw.js} +1 -1
- package/dist/assets/harness-C3JUv5Ii.js +1 -0
- package/dist/assets/{harness-multi-CYHgI0a9.js → harness-multi-XZNex3tb.js} +1 -1
- package/dist/assets/{harness-support-Do7sIp2j.js → harness-support-CjfZIVeb.js} +1 -1
- package/dist/assets/main-DQ32hWBM.js +17 -0
- package/dist/context.json +13 -2
- package/dist/css/storymap.css +1 -1
- package/dist/demo.html +3 -2
- package/dist/docs/api/assets/navigation.js +1 -1
- package/dist/docs/api/assets/search.js +1 -1
- package/dist/docs/api/classes/StoryMap.html +777 -269
- package/dist/docs/api/functions/MediaType.html +1 -1
- package/dist/docs/api/functions/isPresentation3Collection.html +1 -1
- package/dist/docs/api/functions/isPresentation3Manifest.html +1 -1
- package/dist/docs/api/functions/isSlideshowCollection.html +51 -0
- package/dist/docs/api/functions/loadCSS.html +1 -1
- package/dist/docs/api/functions/manifestToStorymapData.html +1 -1
- package/dist/docs/api/functions/setLanguage.html +1 -1
- package/dist/docs/api/functions/slideshowToStorymapData.html +51 -0
- package/dist/docs/api/functions/slideshowVersion.html +48 -0
- package/dist/docs/api/functions/storymapToManifest.html +1 -1
- package/dist/docs/api/functions/validateStorymap.html +1 -1
- package/dist/docs/api/functions/validateStorymapAndReport.html +1 -1
- package/dist/docs/api/index.html +115 -12
- package/dist/docs/api/interfaces/AnimationHandle.html +2 -2
- package/dist/docs/api/interfaces/ImagereadyPayload.html +4 -4
- package/dist/docs/api/interfaces/LanguageEntry.html +6 -6
- package/dist/docs/api/interfaces/LatLngLiteral.html +4 -4
- package/dist/docs/api/interfaces/LoadOptions.html +2 -2
- package/dist/docs/api/interfaces/MapEvents.html +116 -0
- package/dist/docs/api/interfaces/MapMarkerEvents.html +66 -0
- package/dist/docs/api/interfaces/MarkerEventPayload.html +57 -0
- package/dist/docs/api/interfaces/MediaEvents.html +78 -0
- package/dist/docs/api/interfaces/MenuBarEvents.html +114 -0
- package/dist/docs/api/interfaces/MessageEvents.html +72 -0
- package/dist/docs/api/interfaces/OlLayer.html +1 -1
- package/dist/docs/api/interfaces/OlMap.html +1 -1
- package/dist/docs/api/interfaces/OlSource.html +1 -1
- package/dist/docs/api/interfaces/OlTileLayer.html +1 -1
- package/dist/docs/api/interfaces/OlVectorLayer.html +1 -1
- package/dist/docs/api/interfaces/OlView.html +1 -1
- package/dist/docs/api/interfaces/SlideBackgroundState.html +66 -0
- package/dist/docs/api/interfaces/SlideEvents.html +78 -0
- package/dist/docs/api/interfaces/SlideNavEvents.html +72 -0
- package/dist/docs/api/interfaces/SlideshowPlayerSettings.html +182 -0
- package/dist/docs/api/interfaces/SlideshowToStorymapResult.html +60 -0
- package/dist/docs/api/interfaces/SlideshowTranslatorOptions.html +65 -0
- package/dist/docs/api/interfaces/SlideshowWarning.html +72 -0
- package/dist/docs/api/interfaces/StoryMapEvents.html +146 -0
- package/dist/docs/api/interfaces/StoryMapMarker.html +763 -0
- package/dist/docs/api/interfaces/StorySliderEvents.html +102 -0
- package/dist/docs/api/interfaces/StorymapBasemap.html +69 -0
- package/dist/docs/api/interfaces/StorymapData.html +12 -6
- package/dist/docs/api/interfaces/StorymapDataWrapper.html +2 -2
- package/dist/docs/api/interfaces/StorymapDocument.html +2 -2
- package/dist/docs/api/interfaces/StorymapError.html +3 -3
- package/dist/docs/api/interfaces/StorymapGeoreference.html +5 -5
- package/dist/docs/api/interfaces/StorymapGeoreferenceBody.html +4 -4
- package/dist/docs/api/interfaces/StorymapGroundControlPoint.html +4 -4
- package/dist/docs/api/interfaces/StorymapLanguageMap.html +2 -2
- package/dist/docs/api/interfaces/StorymapManifest.html +12 -12
- package/dist/docs/api/interfaces/StorymapManifestAnnotation.html +43 -11
- package/dist/docs/api/interfaces/StorymapManifestBackground.html +6 -6
- package/dist/docs/api/interfaces/StorymapManifestCanvas.html +65 -17
- package/dist/docs/api/interfaces/StorymapManifestContentResource.html +8 -8
- package/dist/docs/api/interfaces/StorymapManifestFeatureCollection.html +4 -4
- package/dist/docs/api/interfaces/StorymapManifestGeoreferencing.html +7 -7
- package/dist/docs/api/interfaces/StorymapManifestImageService.html +4 -4
- package/dist/docs/api/interfaces/StorymapManifestRange.html +5 -5
- package/dist/docs/api/interfaces/StorymapManifestService.html +4 -4
- package/dist/docs/api/interfaces/StorymapManifestSpecificResource.html +4 -4
- package/dist/docs/api/interfaces/StorymapManifestStatement.html +3 -3
- package/dist/docs/api/interfaces/StorymapMapOptions.html +5 -5
- package/dist/docs/api/interfaces/StorymapOptions.html +277 -75
- package/dist/docs/api/interfaces/StorymapOverlayLayer.html +42 -11
- package/dist/docs/api/interfaces/StorymapSlide.html +70 -16
- package/dist/docs/api/interfaces/StorymapSlideBackground.html +4 -4
- package/dist/docs/api/interfaces/StorymapSlideLocation.html +58 -14
- package/dist/docs/api/interfaces/StorymapSlideMarker.html +8 -9
- package/dist/docs/api/interfaces/StorymapSlideMedia.html +49 -10
- package/dist/docs/api/interfaces/StorymapSlideNarration.html +61 -9
- package/dist/docs/api/interfaces/StorymapSlideText.html +4 -4
- package/dist/docs/api/interfaces/StorymapTilejson.html +8 -8
- package/dist/docs/api/interfaces/SwipableEvents.html +102 -0
- package/dist/docs/api/interfaces/TextEvents.html +66 -0
- package/dist/docs/api/media/events.md +66 -0
- package/dist/docs/api/media/migration-from-knightlab.md +89 -49
- package/dist/docs/api/media/slideshow.md +109 -0
- package/dist/docs/api/media/storymap-as-iiif-manifest.md +1007 -0
- package/dist/docs/api/modules.html +6 -6
- package/dist/docs/api/types/ContentState.html +3 -3
- package/dist/docs/api/types/FiredEvent.html +43 -0
- package/dist/docs/api/types/ImagereadyKind.html +1 -1
- package/dist/docs/api/types/MediaTypeMatch.html +5 -5
- package/dist/docs/api/types/SwipeDirection.html +36 -0
- package/dist/docs/api/types/TileSourceFactory.html +1 -1
- package/dist/docs/authoring.html +20 -7
- package/dist/docs/events.html +263 -0
- package/dist/docs/iiif.html +136 -22
- package/dist/docs/migration.html +66 -19
- package/dist/docs/readme.html +113 -12
- package/dist/embed/index.html +7 -0
- package/dist/examples/font-css-false.json +33 -0
- package/dist/examples/issue-image-region.json +1 -1
- package/dist/examples/layers-control.json +60 -0
- package/dist/examples/map-template-provider.json +36 -0
- package/dist/examples/multi-media.json +71 -0
- package/dist/examples-iiif/annotated-image.json +16 -0
- package/dist/examples-iiif/font-css-false.json +114 -0
- package/dist/examples-iiif/issue-image-region.json +1 -1
- package/dist/examples-iiif/layers-control.json +226 -0
- package/dist/examples-iiif/map-template-provider.json +133 -0
- package/dist/examples-iiif/multi-media.json +237 -0
- package/dist/examples-slideshow/single.json +79 -0
- package/dist/examples-slideshow/static/pixel.png +0 -0
- package/dist/examples-slideshow/static.json +44 -0
- package/dist/harness-multi.html +3 -3
- package/dist/harness.html +4 -3
- package/dist/index.html +3 -2
- package/dist/js/storymap.d.ts +1326 -289
- package/dist/js/storymap.js +6690 -4784
- package/dist/js/storymap.js.map +1 -1
- package/dist/navplace-properties.json +14 -0
- package/dist/site.css +54 -36
- package/docs/migration-from-knightlab.md +89 -49
- package/docs/storymap-as-iiif-manifest.md +199 -126
- package/package.json +4 -2
- package/schema/storymap.schema.json +334 -34
- package/src/core/Util.ts +3 -1
- package/src/core/mixins.ts +42 -28
- package/src/language/Language.ts +7 -0
- package/src/language/locale/.expected-gaps.json +287 -27
- package/src/language/locale/de.json +11 -1
- package/src/language/locale/en.json +11 -1
- package/src/main.ts +51 -0
- package/src/map/Map.ts +44 -6
- package/src/map/MapMarker.ts +16 -3
- package/src/map/openlayers/Map.OpenLayers.ts +787 -62
- package/src/map/openlayers/MapMarker.OpenLayers.ts +113 -13
- package/src/map/slideView.ts +149 -0
- package/src/map/types.ts +2 -0
- package/src/media/EmbedUtil.ts +27 -2
- package/src/media/Media.ts +27 -4
- package/src/media/embedId.ts +6 -0
- package/src/media/types/Flickr.ts +14 -3
- package/src/media/types/HtmlMedia.ts +66 -0
- package/src/media/types/Image.ts +15 -3
- package/src/media/types/SoundCloud.ts +1 -1
- package/src/media/types/Text.ts +27 -8
- package/src/media/types/Twitter.ts +9 -7
- package/src/media/types/Vimeo.ts +1 -1
- package/src/media/types/YouTube.ts +2 -2
- package/src/scss/Typography.scss +15 -15
- package/src/scss/VCO.StoryMap.scss +173 -8
- package/src/scss/core/Reset.scss +5 -18
- package/src/scss/map/VCO.Map.scss +1 -1
- package/src/scss/map/VCO.MapMarker.scss +20 -9
- package/src/scss/map/openlayers/VCO.Map.OpenLayers.scss +7 -4
- package/src/scss/media/VCO.Media.scss +7 -7
- package/src/scss/media/types/VCO.Media.Blockquote.scss +1 -1
- package/src/scss/media/types/VCO.Media.Text.scss +5 -5
- package/src/scss/media/types/VCO.Media.Twitter.scss +4 -4
- package/src/scss/media/types/VCO.Media.Wikipedia.scss +2 -19
- package/src/scss/site/site.scss +55 -36
- package/src/scss/slider/VCO.Slide.scss +49 -11
- package/src/scss/slider/VCO.SlideNav.scss +23 -7
- package/src/scss/slider/VCO.StorySlider.scss +50 -0
- package/src/scss/snapmap/VCO.SnapMap.scss +3 -3
- package/src/scss/ui/VCO.Consent.scss +20 -14
- package/src/scss/ui/VCO.Layers.scss +119 -0
- package/src/scss/ui/VCO.MenuBar.Button.scss +140 -19
- package/src/scss/ui/VCO.MenuBar.scss +9 -2
- package/src/scss/ui/VCO.Message.scss +14 -0
- package/src/slider/Slide.ts +232 -74
- package/src/slider/SlideNav.ts +15 -4
- package/src/slider/StorySlider.ts +203 -22
- package/src/storymap/Consent.ts +22 -0
- package/src/storymap/StoryMap.ts +944 -131
- package/src/storymap/content-state.ts +3 -8
- package/src/storymap/font-css.ts +72 -0
- package/src/storymap/from-slideshow.ts +785 -0
- package/src/storymap/iiif-shared.ts +228 -0
- package/src/storymap/iiif.ts +289 -100
- package/src/storymap/to-iiif.ts +131 -44
- package/src/types.ts +382 -17
- package/src/ui/LayersControl.ts +302 -0
- package/src/ui/MenuBar.ts +232 -21
- package/src/ui/Message.ts +36 -3
- package/src/ui/Swipable.ts +25 -7
- package/dist/assets/harness-Cr0rYpvt.js +0 -1
- package/dist/assets/main-DXalctuR.js +0 -17
- package/src/scss/VCO.StoryMap.Dark.scss +0 -150
- package/src/scss/Variables.Dark.scss +0 -57
package/CHANGELOG
CHANGED
|
@@ -1,3 +1,84 @@
|
|
|
1
|
+
0.11.0 (2026-10-07)
|
|
2
|
+
------------------------
|
|
3
|
+
Added
|
|
4
|
+
-----
|
|
5
|
+
- Inactive slides are hidden from assistive tech (`aria-hidden` + `inert`
|
|
6
|
+
in `Slide.setActive()`), so screen readers no longer read every
|
|
7
|
+
off-screen slide; preloading (including iframes) is unaffected
|
|
8
|
+
- Keyboard access: map pins are focusable buttons (Enter/Space activates,
|
|
9
|
+
focus returns on popup close), messages dismiss from the keyboard, and a
|
|
10
|
+
skip link jumps to the slide content. Autoplay gains a menubar
|
|
11
|
+
pause/resume toggle; slide text carries its `lang`; consent dialogs are
|
|
12
|
+
labelled dialogues with focus; media errors announce via `role=alert`
|
|
13
|
+
- Reduced motion is honored everywhere it matters: map glides, line draw,
|
|
14
|
+
background fades, nav intro, smooth scroll and the loader freeze, and an
|
|
15
|
+
OS toggle flipped mid-story stops autoplay. Touch targets are 44px,
|
|
16
|
+
muted text meets contrast, and focus rings are visible
|
|
17
|
+
- Programmatic popup cards: `storymap.openMarkerPopup(n)` navigates to the
|
|
18
|
+
stop and opens its card (false and no navigation when disabled, out of
|
|
19
|
+
range, disposed or mapless), plus `closeMarkerPopup(n?)` and
|
|
20
|
+
`isPopupOpen(n)`. The marker itself exposes `openPopup()` /
|
|
21
|
+
`closePopup()` / `togglePopup()` / `isPopupEnabled()` / `popupOpen`,
|
|
22
|
+
and the `StoryMapMarker` type is exported for hosts
|
|
23
|
+
- `popupopen` / `popupclose` (`{ marker_number, current_slide }`) and a
|
|
24
|
+
viewer-level `markerclick` re-fire, so hosts can tell marker clicks apart
|
|
25
|
+
from programmatic navigation
|
|
26
|
+
- `tweetAuthor()` next to `tweetId()`: `Twitter` extracts both through the
|
|
27
|
+
shared helpers instead of its own regex
|
|
28
|
+
- `font_css: false` (or `"none"`) injects no theme stylesheet for
|
|
29
|
+
bundler consumers that import it themselves; the consent dialog lists no
|
|
30
|
+
font service for it, and a failing theme load warns with its URL. The
|
|
31
|
+
IIIF `storymap:fontCss` term round-trips `false`
|
|
32
|
+
- Layer switcher: `show_layers_control: true` adds a menubar disclosure
|
|
33
|
+
button with basemap radios (`basemaps[]`, entry 0 initial unless
|
|
34
|
+
`map_type` says otherwise) and overlay checkboxes (rows track built
|
|
35
|
+
layers, so malformed entries never appear). Overlay `label` (string or
|
|
36
|
+
function), `locked` (checked and disabled) and `control: false` (hidden
|
|
37
|
+
row) annotate entries; cross-projection basemaps are refused with a
|
|
38
|
+
warning. Fires `basemapchange` / `overlaychange`, also on the viewer
|
|
39
|
+
- IIIF narration (V1 of #358): a `motivation: "supplementing"` Sound/Video
|
|
40
|
+
body plays as `slide.narration`, and the writer emits one back. Array
|
|
41
|
+
`motivation` values are honored everywhere — previously an array read as
|
|
42
|
+
"no motivation" and was accepted as the canvas painting, shadowing the
|
|
43
|
+
real media
|
|
44
|
+
- Second visible media slot (V2 of #358): `media_extra` renders further media
|
|
45
|
+
items after the primary one (`media_layout: "stack"`, the default, or
|
|
46
|
+
`"row"` for two side-by-side items); documents without it render
|
|
47
|
+
identically. Extra `painting` annotations read as `media_extra` and are
|
|
48
|
+
written back, so the slot round-trips — only the layout stays viewer-side,
|
|
49
|
+
IIIF has no term for it. Consent, the audio badge and the popup thumbnail
|
|
50
|
+
all see every item
|
|
51
|
+
- Dark theme without a second stylesheet: every widget colour is a
|
|
52
|
+
`--vco-*` custom property (Sass values kept as fallbacks, so the default
|
|
53
|
+
render is unchanged); `theme: "dark"` forces the dark palette, `"light"`
|
|
54
|
+
pins the light one, unset follows `prefers-color-scheme`. The unshippable
|
|
55
|
+
`VCO.StoryMap.Dark.scss` / `Variables.Dark.scss` pair is deleted, the
|
|
56
|
+
dead widget reset is live again, and dark text pairs clear AA. The
|
|
57
|
+
landing page follows the OS scheme too
|
|
58
|
+
- Typed events: every emitter has an `*Events` map (exported from the
|
|
59
|
+
library), so `storymap.on("chnage", …)` is a compile error and handlers
|
|
60
|
+
infer their payload. `fire()` can no longer be handed a `type`/`target`
|
|
61
|
+
in the payload, `off()` removes all matches, and teardowns detach
|
|
62
|
+
their listeners
|
|
63
|
+
- Full XYZ templates naming a known provider are credited to it
|
|
64
|
+
(`tile.openstreetmap.org` and subdomains, `stadiamaps.com`,
|
|
65
|
+
`openmaptiles.org`, `mapbox.com`, `arcgisonline.com`/`esri.com`,
|
|
66
|
+
`carto.com`/`basemaps.cartocdn.com` — subdomains match their parent), in
|
|
67
|
+
both the rendered line and the source attributions. Relative templates
|
|
68
|
+
still render "Map data"
|
|
69
|
+
|
|
70
|
+
Changed
|
|
71
|
+
-------
|
|
72
|
+
- The IIIF reader/writer share `src/storymap/iiif-shared.ts`
|
|
73
|
+
(`LOCATION_PROPERTIES`, JSON guards, bbox and URL checks) instead of
|
|
74
|
+
three copies; the writer's Node CLI import carries an explicit `.ts`
|
|
75
|
+
extension, which type-stripping resolution requires
|
|
76
|
+
- Map attribution comes from one provider-credit table (linked HTML and
|
|
77
|
+
plain text cannot drift apart); font-theme URL helpers live in
|
|
78
|
+
`src/storymap/font-css.ts` (re-exported from `StoryMap`)
|
|
79
|
+
- Error paths log with `console.warn`, prefixed `StoryMapJS:`, instead of
|
|
80
|
+
`console.log`
|
|
81
|
+
|
|
1
82
|
0.10.8 (2026-09-29)
|
|
2
83
|
------------------------
|
|
3
84
|
Code audit: one regression, a set of latent bugs, seven stored-XSS sinks, a
|
package/README.md
CHANGED
|
@@ -39,8 +39,10 @@ Points are set to only display on mouseover in image mode, but you can set map_a
|
|
|
39
39
|
|
|
40
40
|
## Map Options
|
|
41
41
|
|
|
42
|
-
To disable connecting lines on maps set `
|
|
43
|
-
options (the default `
|
|
42
|
+
To disable connecting lines on maps set `show_lines: false` in the storymap
|
|
43
|
+
options (the default `true` renders cartography with `show_history_line`).
|
|
44
|
+
`map_as_image: true` is something else: image-map mode, only meaningful with
|
|
45
|
+
`map_type: "iiif"` (the image itself becomes the map).
|
|
44
46
|
|
|
45
47
|
`storymap.map` is the raw OpenLayers map, typed with the re-exported `ol`
|
|
46
48
|
types, and `getBaseLayer()`, `getOverlayLayers()`, `getMinimap()`,
|
|
@@ -72,6 +74,85 @@ More config options available to do what you want with the line:
|
|
|
72
74
|
|
|
73
75
|
To disable zoom calculation/edit zoom level set calculate_zoom to false in the config options.
|
|
74
76
|
|
|
77
|
+
### More data options
|
|
78
|
+
|
|
79
|
+
Beyond the map options above, the storymap data takes `overlays[]`
|
|
80
|
+
(stacked raster layers over the basemap), `tilejson` (a TileJSON source for
|
|
81
|
+
the base layer), `overview_extent` (the overview slide's bounds),
|
|
82
|
+
`keyboard` (page-wide arrow-key navigation for multi-viewer pages),
|
|
83
|
+
per-slide `marker: { popup, audioBadge }` (the active marker's card, openable
|
|
84
|
+
via `storymap.openMarkerPopup(n)`, and the narration/audio dot) and
|
|
85
|
+
`narration: { url }` per slide. `autoplay_media` is global (wait for slide
|
|
86
|
+
media to end while autoplaying); the per-slide dwell is `slidetimeout`.
|
|
87
|
+
All are validated
|
|
88
|
+
against `schema/storymap.schema.json` — read it (or `src/types.ts`) for the
|
|
89
|
+
full list with defaults.
|
|
90
|
+
|
|
91
|
+
`show_layers_control: true` adds a menubar disclosure button listing the
|
|
92
|
+
`overlays[]` as checkboxes and `basemaps[]` as basemap radios, so the
|
|
93
|
+
visitor can switch layers without touching code.
|
|
94
|
+
|
|
95
|
+
`theme: "dark"` forces the dark palette, `"light"` pins the light one;
|
|
96
|
+
unset, the widget follows `prefers-color-scheme`.
|
|
97
|
+
|
|
98
|
+
### Slideshow-style tours
|
|
99
|
+
|
|
100
|
+
Slides can carry per-slide presentation for image tours (a stop can restyle
|
|
101
|
+
the view while it is active; everything is optional and validated against
|
|
102
|
+
`schema/storymap.schema.json`):
|
|
103
|
+
|
|
104
|
+
location: {
|
|
105
|
+
region: [x, y, w, h], // image-pixel stop (IIIF xywh); negative origins clamp to the canvas
|
|
106
|
+
rotation: 45, // view rotation in degrees clockwise
|
|
107
|
+
filter: { sepia: 40 }, // brightness/contrast/saturate 0-200 (%), hueRotate -180-180 (°), sepia 0-100 (%), blur 0-20 (px)
|
|
108
|
+
mask: { x: 0.1, y: 0.1, w: 0.8, h: 0.8, opacity: 0.5 }, // spotlight mask (fractions) + color/invert
|
|
109
|
+
basemap: "osm:bright", // per-slide basemap (any map_type, IIIF info.json URL or image file)
|
|
110
|
+
},
|
|
111
|
+
narration: { url, loop, offset, play: "auto"|"click", stopOnExit, stopAllPrevious },
|
|
112
|
+
slidetimeout: 9000, // per-slide autoplay dwell in ms (0 holds); default is the global autoplay
|
|
113
|
+
imgoverlay: { url, size, extent, opacity }, // image overlay while the slide is active
|
|
114
|
+
|
|
115
|
+
Audio/video media take the same `offset`/`loop`/`play`/`stopOnExit` flags
|
|
116
|
+
on the slide's `media` object (`stopAllPrevious` is narration-only).
|
|
117
|
+
|
|
118
|
+
When a slide's IIIF `info.json` cannot be loaded, `iiif: { width, height,
|
|
119
|
+
fallbackUrl }` paints the static image instead of a blank basemap. Without
|
|
120
|
+
stated dimensions the viewer probes the fallback image's natural size first,
|
|
121
|
+
but only for slideshow tours (15s timeout); other documents keep the logged
|
|
122
|
+
error path. Per-slide static basemaps (`image_srv` pointing at a plain
|
|
123
|
+
image file, absolute or same-origin relative) probe the same way, and a
|
|
124
|
+
failed `info.json` fetch falls back to a probed static image in place.
|
|
125
|
+
|
|
126
|
+
The player chrome is opt-in storymap options (absent means the default
|
|
127
|
+
layout): `textmode: "left"|"right"|"bottom"` with `textsize` (10–80 %,
|
|
128
|
+
bottom dock only — the player drops side-dock sizes too),
|
|
129
|
+
`progressbar: "bar"|"dots"|"squares"|"block"|"thinblock"|"off"` (`true`
|
|
130
|
+
means `"bar"`, `false` means hidden),
|
|
131
|
+
`fxmode: "slide"|"fade"|"none"`, `mode: "static"` (stacked reading list with
|
|
132
|
+
scroll-spy map sync), `hudcolor`/`hudbgcolor`/`hudopacity`,
|
|
133
|
+
`shownav`/`show_headings`/`show_scrollbars`/`show_info` toggles and
|
|
134
|
+
`viewerheight: "400px"`.
|
|
135
|
+
|
|
136
|
+
**IIIF round-trip:** the per-slide fields do survive — `rotation`,
|
|
137
|
+
`filter`, `mask`, `basemap`, `slidetimeout`, `imgoverlay`, `provenance`
|
|
138
|
+
and the playback bags travel as `storymap:` terms (see
|
|
139
|
+
[docs/storymap-as-iiif-manifest.md](docs/storymap-as-iiif-manifest.md)).
|
|
140
|
+
The player chrome does **not**: it has no IIIF vocabulary and is
|
|
141
|
+
translator-only (a storymap→manifest→storymap cycle drops it).
|
|
142
|
+
|
|
143
|
+
These presentation fields render **only for slideshow tours** (documents
|
|
144
|
+
loaded from that format, which set the internal `slideshow_source` marker).
|
|
145
|
+
Hand-written storymap documents and IIIF manifests keep the long-standing
|
|
146
|
+
rendering even when they name the new keys — captions always show, the
|
|
147
|
+
autoplay interval stays global, the panel keeps its default dock. Hosts may
|
|
148
|
+
pass `slideshow_source: true` explicitly as an escape hatch (e.g. in tests).
|
|
149
|
+
|
|
150
|
+
Slideshow tours (W3C `AnnotationCollection` documents) load directly — by
|
|
151
|
+
object, file or URL, following `next` pages — or convert offline with
|
|
152
|
+
`npm run convert:slideshow -- [--settings settings.json] [--out out.json] <tour-url-or-file>`
|
|
153
|
+
(see [docs/slideshow.md](docs/slideshow.md) for the field mapping,
|
|
154
|
+
player-settings handling and loss table).
|
|
155
|
+
|
|
75
156
|
Images can now be used in place of map pins.
|
|
76
157
|
Use `image` inside the location object and include a url to use, together with
|
|
77
158
|
`use_custom_marker: true` in the location object (or set `use_custom_markers:
|
|
@@ -103,7 +184,10 @@ an opaque slide panel instead of the gradient over the map), set
|
|
|
103
184
|
Any value containing `{z}` renders as a raster XYZ layer; a path without `{z}`
|
|
104
185
|
that looks like a URL/path renders as a vector style layer; anything else falls
|
|
105
186
|
back to classic OSM raster — except `"none"`, which builds no map at all and
|
|
106
|
-
runs the story as text and media only.
|
|
187
|
+
runs the story as text and media only. A full template naming a known provider
|
|
188
|
+
(`https://tile.openstreetmap.org/{z}/{x}/{y}.png`) is credited to that
|
|
189
|
+
provider; anything else gets the generic "Map data" line (add your own via
|
|
190
|
+
`attribution`).
|
|
107
191
|
|
|
108
192
|
### Switching the basemap at runtime
|
|
109
193
|
|
|
@@ -114,11 +198,18 @@ current slide is re-fitted after the swap.
|
|
|
114
198
|
|
|
115
199
|
### Icons
|
|
116
200
|
|
|
117
|
-
Default pins use the bundled `vco-icons` font (`dist/css/icons
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
201
|
+
Default pins use the bundled `vco-icons` font (`dist/css/icons/`). The SCSS
|
|
202
|
+
source uses the absolute public path (`/css/icons/...`) so `vite dev` serves
|
|
203
|
+
the fonts directly; `vite build` rewrites them to relative `./icons/...` in
|
|
204
|
+
`dist/css/storymap.css`, so pins render on subpath deploys, for bundler
|
|
205
|
+
consumers and on `file://`/Electron hosts without extra configuration.
|
|
206
|
+
Import the stylesheet once
|
|
207
|
+
(`import "@projektemacher/storymapjs/css/storymap.css"`).
|
|
208
|
+
|
|
209
|
+
Font themes (`font_css: "stock:<name>"`) resolve via `import.meta.url`, so
|
|
210
|
+
they only work script-tagged, unbundled. A bundler consumer imports the theme
|
|
211
|
+
instead (`import "@projektemacher/storymapjs/css/fonts/font.default.css"`)
|
|
212
|
+
and passes `font_css: false` for no injected `<link>`.
|
|
122
213
|
|
|
123
214
|
## Custom HTML in slide content
|
|
124
215
|
|
|
@@ -172,9 +263,11 @@ Decisions are stored in `localStorage` under `storymapjs-consent` and have no
|
|
|
172
263
|
expiry — clearing site data asks again.
|
|
173
264
|
|
|
174
265
|
The consent labels are **not** fully translated. `src/language/locale/en.json`
|
|
175
|
-
defines every string
|
|
176
|
-
|
|
177
|
-
|
|
266
|
+
defines every string (34 keys across 29 locale files: English plus 28
|
|
267
|
+
translations). German is missing 1 key, most locales are missing 9 (the audio
|
|
268
|
+
badge, autoplay, layer-switcher, iframe-title and narration-consent strings),
|
|
269
|
+
and five locales (`et`, `is`, `nn`, `ur`, `sr`) are missing 18–19 (additionally
|
|
270
|
+
the fullscreen, consent-dialog, error and overview strings). Run
|
|
178
271
|
`npm run check:locales` to see the current state — it reports the gap per
|
|
179
272
|
locale and is expected to be runnable without failing.
|
|
180
273
|
|
|
@@ -182,7 +275,31 @@ locale and is expected to be runnable without failing.
|
|
|
182
275
|
|
|
183
276
|
If a storymap fails to render, open the browser console: the viewer logs
|
|
184
277
|
fetch and validation errors (e.g. "could not load storymap data from ...").
|
|
185
|
-
The `error` event also fires for programmatic consumers.
|
|
278
|
+
The `error` event also fires for programmatic consumers. The full event
|
|
279
|
+
reference (payloads included) is [docs/events.md](docs/events.md).
|
|
280
|
+
|
|
281
|
+
## Accessibility
|
|
282
|
+
|
|
283
|
+
Supported, and covered by tests: text alternatives on slide images
|
|
284
|
+
(decorative `alt=""` included); real `<button>` menubar actions and slide
|
|
285
|
+
navigation; polite live-region slide announcements; reduced-motion handling
|
|
286
|
+
of the slide glide and autoplay; an embed page that does not disable zoom;
|
|
287
|
+
sanitized author tables that keep their semantics; slides hidden from
|
|
288
|
+
assistive tech while inactive (`aria-hidden` + `inert`), with a layer
|
|
289
|
+
switcher built from native checkboxes, radios and fieldsets; keyboard
|
|
290
|
+
operable map pins and message dismissal; a skip link to the slide content;
|
|
291
|
+
an autoplay pause/resume toggle; slide text pronounced in its own language
|
|
292
|
+
(`lang`); consent dialogs exposed with labels and focus; media errors
|
|
293
|
+
announced as alerts; and a motion kill-switch that also honors an
|
|
294
|
+
OS reduced-motion toggle flipped mid-story.
|
|
295
|
+
|
|
296
|
+
Known limitations (not fixed here): map markers are pointer-only; audio and
|
|
297
|
+
video have no viewer-side captions or transcripts; narration ships without a
|
|
298
|
+
transcript; focus moves only when the layer panel closes with Escape; labels
|
|
299
|
+
and announcements are hardcoded English; several muted text colors fall
|
|
300
|
+
below 4.5:1; third-party embeds are the vendor's conformance. No VPAT or
|
|
301
|
+
ACR is claimed — §508 conformance is decided per deliverable by an
|
|
302
|
+
external audit.
|
|
186
303
|
|
|
187
304
|
## Bundled credentials
|
|
188
305
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./modulepreload-polyfill-P2Xu9kJm.js";import{t as e}from"./main-
|
|
1
|
+
import"./modulepreload-polyfill-P2Xu9kJm.js";import{t as e}from"./main-DQ32hWBM.js";function t(e){document.title=`StoryMapJS: `+e.title}window.storymap=new e(`storymap-embed`,`./demo.json`,{},{title:t});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./modulepreload-polyfill-P2Xu9kJm.js";import{t as e}from"./main-DQ32hWBM.js";import{n as t,t as n}from"./harness-support-CjfZIVeb.js";window.__smErrors=[],window.__smReady=!1,window.addEventListener(`error`,e=>{window.__smErrors.push(String(e.message||e))});var r=new URLSearchParams(window.location.search),i=r.get(`manifest`),a=r.get(`slideshow`),o=r.get(`url`),s=i===null?a===null?r.get(`example`):a:i,c=i===null?a===null?`/examples/`:`/examples-slideshow/`:`/examples-iiif/`,l={};if(r.get(`options`))try{l=JSON.parse(r.get(`options`))}catch(e){window.__smErrors.push(`harness: bad options param: `+e)}var u=t(window);u&&(l.tile_source_factory=u);var d=o??c+s+`.json`;fetch(d).then(e=>e.json()).then(t=>{let i=new e(`storymap-embed`,a!==null&&o===null?d:t,l,{error:e=>{window.__smErrors.push(`storymap: `+(e.message||String(e)))}});window.__sm=i,n(i,r.get(`record`),window),window.__smReady=!0}).catch(e=>{window.__smErrors.push(`harness: `+(e&&e.message?e.message:String(e))),window.__smReady=!0});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./modulepreload-polyfill-P2Xu9kJm.js";import{t as e}from"./main-
|
|
1
|
+
import"./modulepreload-polyfill-P2Xu9kJm.js";import{t as e}from"./main-DQ32hWBM.js";import{n as t,t as n}from"./harness-support-CjfZIVeb.js";window.__smErrors=[],window.__smReady=!1,window.addEventListener(`error`,e=>{window.__smErrors.push(String(e.message||e))});var r=new URLSearchParams(window.location.search),i={a:r.get(`a`)??`katrina`,b:r.get(`b`)??`seurat`},a={a:o(r.get(`aopts`)),b:o(r.get(`bopts`))};for(let[e,n]of Object.entries(a)){let r=t(window);r&&(n.tile_source_factory=r),a[e]=n}function o(e){if(!e)return{};try{return JSON.parse(e)}catch(e){return window.__smErrors.push(`harness-multi: bad options: `+e),{}}}async function s(e){let t=await fetch(`/examples/`+i[e]+`.json`);if(!t.ok)throw Error(`no example `+i[e]);return t.json()}var c=r.get(`shared`)===`1`?await s(`a`):null;try{let t=c??await s(`a`);window.__smA=new e(`sm-a`,t,a.a,{}),n(window.__smA,r.get(`record`),window,`A`);let i=c??await s(`b`);window.__smB=new e(`sm-b`,i,a.b,{}),n(window.__smB,r.get(`record`),window,`B`)}catch(e){window.__smErrors.push(`harness-multi: `+(e?.message??e))}window.__smReady=!0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function e(e,t,r,i=``){let a=(t??``).split(`,`).map(e=>e.trim()).filter(Boolean);if(a.length!==0){r.__events=r.__events??[];for(let t of a)e.on(t,e=>{r.__events.push({type:t,viewer:i,payload:n(e)})})}}function t(e){return typeof e.__tileSourceFactory==`function`?e.__tileSourceFactory:void 0}function n(e){if(typeof e!=`object`||!e)return e;let t={};for(let[a,o]of Object.entries(e))if(typeof o!=`object`||!o)t[a]=typeof o==`function`?`[fn]`:o;else if(a===`source`||a===`layer`)t[a]={type:o.constructor?.name??null,state:typeof o.getState==`function`?o.getState():void 0,url:o.url_??o.href_??r(o,`url`)};else if(a===`target`)t[a]=i(o);else if(Array.isArray(o))t[a]=o.map(e=>n(e));else{let e=Object.getPrototypeOf(o);t[a]=e===Object.prototype||e===null?n(o):{type:o.constructor?.name??null}}return t}function r(e,t){try{return e.get?.(t)}catch{return}}function i(e){let t=a(e)?e:a(e?._map)?e._map:null;if(!t)return{type:e?.constructor?.name??null};let n=t.getView(),r=t.getSize();return{type:e?.constructor?.name??null,size:r?[r[0],r[1]]:null,center:n?.getCenter?.()??null,resolution:n?.getResolution?.()??null,projection:n?.getProjection?.()?.getCode?.()??null}}function a(e){return!!e&&typeof e.getSize==`function`&&typeof e.getView==`function`}export{t as n,e as t};
|
|
1
|
+
function e(e,t,r,i=``){let a=(t??``).split(`,`).map(e=>e.trim()).filter(Boolean);if(a.length!==0){r.__events=r.__events??[];for(let t of a)e.on(t,e=>{r.__events.push({type:t,viewer:i,payload:n(e)})})}}function t(e){return typeof e.__tileSourceFactory==`function`?e.__tileSourceFactory:void 0}function n(e){if(typeof e!=`object`||!e)return e;let t={};for(let[a,o]of Object.entries(e))if(typeof o!=`object`||!o)t[a]=typeof o==`function`?`[fn]`:o;else if(a===`source`||a===`layer`)t[a]={type:o.constructor?.name??null,state:typeof o.getState==`function`?o.getState():void 0,url:o.url_??o.href_??r(o,`url`)};else if(a===`target`)t[a]=i(o);else if(Array.isArray(o))t[a]=o.map(e=>n(e));else{let e=Object.getPrototypeOf(o);t[a]=e===Object.prototype||e===null?n(o):{type:o.constructor?.name??null}}return t}function r(e,t){try{return e.get?.(t)}catch{return}}function i(e){let t=a(e)?e:a(e?.map)?e.map:a(e?._map)?e._map:null;if(!t)return{type:e?.constructor?.name??null};let n=t.getView(),r=t.getSize();return{type:e?.constructor?.name??null,size:r?[r[0],r[1]]:null,center:n?.getCenter?.()??null,resolution:n?.getResolution?.()??null,projection:n?.getProjection?.()?.getCode?.()??null}}function a(e){return!!e&&typeof e.getSize==`function`&&typeof e.getView==`function`}export{t as n,e as t};
|