@projektemacher/storymapjs 0.10.6 → 0.10.7
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 +11 -0
- package/dist/assets/{demo-CVQ7kFek.js → demo-D6cTmzn6.js} +1 -1
- package/dist/assets/{harness-C-VZV-ou.js → harness-BPFlzutp.js} +1 -1
- package/dist/assets/main-Y-MYUSJ4.js +17 -0
- package/dist/css/fonts/font.oldstandard.css +18 -22
- package/dist/demo.html +2 -2
- package/dist/docs/migration.html +1 -1
- package/dist/embed/index.html +129 -4
- package/dist/harness.html +2 -2
- package/dist/index.html +17 -0
- package/dist/js/storymap.d.ts +126 -7
- package/dist/js/storymap.js +4518 -3613
- package/dist/js/storymap.js.map +1 -1
- package/docs/migration-from-knightlab.md +139 -0
- package/docs/storymap-as-iiif-manifest.md +510 -0
- package/package.json +6 -3
- package/src/animation/easings.ts +18 -0
- package/src/animation/morpheus.d.ts +41 -0
- package/src/core/Browser.ts +19 -0
- package/src/core/Load.ts +180 -0
- package/src/core/Util.ts +354 -0
- package/src/core/mixins.ts +171 -0
- package/src/dom/Dom.ts +31 -0
- package/src/dom/DomEvent.ts +61 -0
- package/src/globals.d.ts +16 -0
- package/src/language/Language.ts +107 -0
- package/src/language/locale/be.json +18 -0
- package/src/language/locale/bg.json +18 -0
- package/src/language/locale/cs.json +18 -0
- package/src/language/locale/de.json +20 -0
- package/src/language/locale/el.json +18 -0
- package/src/language/locale/en.json +28 -0
- package/src/language/locale/es.json +18 -0
- package/src/language/locale/et.json +18 -0
- package/src/language/locale/fr.json +18 -0
- package/src/language/locale/he.json +18 -0
- package/src/language/locale/hu.json +18 -0
- package/src/language/locale/is.json +18 -0
- package/src/language/locale/it.json +18 -0
- package/src/language/locale/jp.json +18 -0
- package/src/language/locale/ko.json +18 -0
- package/src/language/locale/nl.json +18 -0
- package/src/language/locale/nn.json +18 -0
- package/src/language/locale/no.json +18 -0
- package/src/language/locale/pl.json +18 -0
- package/src/language/locale/pt.json +18 -0
- package/src/language/locale/ru.json +18 -0
- package/src/language/locale/sk.json +18 -0
- package/src/language/locale/sr.json +17 -0
- package/src/language/locale/sv.json +18 -0
- package/src/language/locale/tr.json +18 -0
- package/src/language/locale/uk.json +18 -0
- package/src/language/locale/ur.json +18 -0
- package/src/language/locale/zh-cn.json +18 -0
- package/src/language/locale/zh-tw.json +18 -0
- package/src/main.ts +51 -0
- package/src/map/Map.ts +717 -0
- package/src/map/MapMarker.ts +149 -0
- package/src/map/openlayers/Map.OpenLayers.ts +1879 -0
- package/src/map/openlayers/MapMarker.OpenLayers.ts +176 -0
- package/src/map/openlayers/zoomifyTiles.ts +28 -0
- package/src/map/types.ts +17 -0
- package/src/media/EmbedUtil.ts +168 -0
- package/src/media/Media.ts +409 -0
- package/src/media/MediaType.ts +163 -0
- package/src/media/types/Audio.ts +87 -0
- package/src/media/types/Blockquote.ts +40 -0
- package/src/media/types/DailyMotion.ts +58 -0
- package/src/media/types/DocumentCloud.ts +41 -0
- package/src/media/types/Facebook.ts +41 -0
- package/src/media/types/Flickr.ts +115 -0
- package/src/media/types/GoogleDoc.ts +59 -0
- package/src/media/types/IFrame.ts +51 -0
- package/src/media/types/Image.ts +49 -0
- package/src/media/types/Juxtapose.ts +32 -0
- package/src/media/types/SoundCloud.ts +77 -0
- package/src/media/types/Text.ts +172 -0
- package/src/media/types/Twitter.ts +96 -0
- package/src/media/types/Video.ts +84 -0
- package/src/media/types/Vimeo.ts +65 -0
- package/src/media/types/Website.ts +36 -0
- package/src/media/types/Wikipedia.ts +124 -0
- package/src/media/types/YouTube.ts +192 -0
- package/src/scss/Typography.scss +237 -0
- package/src/scss/VCO.StoryMap.Dark.scss +138 -0
- package/src/scss/VCO.StoryMap.scss +164 -0
- package/src/scss/Variables.Dark.scss +56 -0
- package/src/scss/Variables.scss +47 -0
- package/src/scss/core/Mixins.scss +112 -0
- package/src/scss/core/Reset.scss +206 -0
- package/src/scss/fonts/_font.base.scss +113 -0
- package/src/scss/fonts/font.abril-droidsans.scss +75 -0
- package/src/scss/fonts/font.amatic-andika.scss +73 -0
- package/src/scss/fonts/font.bitter-raleway.scss +86 -0
- package/src/scss/fonts/font.clicker-garamond.scss +92 -0
- package/src/scss/fonts/font.dancing-ledger.scss +74 -0
- package/src/scss/fonts/font.default.scss +9 -0
- package/src/scss/fonts/font.fjalla-average.scss +80 -0
- package/src/scss/fonts/font.georgia-helvetica.scss +58 -0
- package/src/scss/fonts/font.knightlab.scss +97 -0
- package/src/scss/fonts/font.lustria-lato.scss +80 -0
- package/src/scss/fonts/font.medula-lato.scss +73 -0
- package/src/scss/fonts/font.oldstandard.scss +88 -0
- package/src/scss/fonts/font.opensans-gentiumbook.scss +80 -0
- package/src/scss/fonts/font.playfair-faunaone.scss +86 -0
- package/src/scss/fonts/font.playfair.scss +85 -0
- package/src/scss/fonts/font.pt.scss +90 -0
- package/src/scss/fonts/font.roboto-megrim.scss +73 -0
- package/src/scss/fonts/font.rufina-sintony.scss +73 -0
- package/src/scss/fonts/font.ubuntu.scss +78 -0
- package/src/scss/fonts/font.unicaone-vollkorn.scss +85 -0
- package/src/scss/icons/Icons.scss +239 -0
- package/src/scss/map/VCO.ImageMarker.scss +23 -0
- package/src/scss/map/VCO.Map.scss +21 -0
- package/src/scss/map/VCO.MapMarker.scss +147 -0
- package/src/scss/map/openlayers/VCO.Map.OpenLayers.scss +126 -0
- package/src/scss/media/VCO.Media.scss +222 -0
- package/src/scss/media/types/VCO.Media.Blockquote.scss +76 -0
- package/src/scss/media/types/VCO.Media.IFrame.scss +11 -0
- package/src/scss/media/types/VCO.Media.Image.scss +13 -0
- package/src/scss/media/types/VCO.Media.Instagram.scss +7 -0
- package/src/scss/media/types/VCO.Media.Profile.scss +5 -0
- package/src/scss/media/types/VCO.Media.Text.scss +90 -0
- package/src/scss/media/types/VCO.Media.Twitter.scss +87 -0
- package/src/scss/media/types/VCO.Media.Wikipedia.scss +64 -0
- package/src/scss/site/site.scss +748 -0
- package/src/scss/slider/VCO.Slide.scss +447 -0
- package/src/scss/slider/VCO.SlideNav.scss +338 -0
- package/src/scss/slider/VCO.StorySlider.scss +64 -0
- package/src/scss/snapmap/VCO.SnapMap.scss +103 -0
- package/src/scss/ui/VCO.Consent.scss +77 -0
- package/src/scss/ui/VCO.MenuBar.Button.scss +99 -0
- package/src/scss/ui/VCO.MenuBar.scss +20 -0
- package/src/scss/ui/VCO.Message.scss +104 -0
- package/src/site/site.ts +87 -0
- package/src/slider/Slide.ts +460 -0
- package/src/slider/SlideNav.ts +212 -0
- package/src/slider/StorySlider.ts +722 -0
- package/src/storymap/Consent.ts +146 -0
- package/src/storymap/StoryMap.ts +1108 -0
- package/src/storymap/iiif.ts +386 -0
- package/src/storymap/validate.ts +184 -0
- package/src/types.ts +297 -0
- package/src/ui/Draggable.ts +374 -0
- package/src/ui/MenuBar.ts +323 -0
- package/src/ui/Message.ts +118 -0
- package/src/ui/Swipable.ts +388 -0
- package/dist/assets/main-DwbXrrYn.js +0 -17
package/src/map/Map.ts
ADDED
|
@@ -0,0 +1,717 @@
|
|
|
1
|
+
import { mergeData, slideTransitionDuration } from "../core/Util";
|
|
2
|
+
import { DomMixed, Evented, type EventedInstance } from "../core/mixins";
|
|
3
|
+
import Dom from "../dom/Dom";
|
|
4
|
+
import { Browser } from "../core/Browser";
|
|
5
|
+
import type { Map as OlMap } from "ol";
|
|
6
|
+
import type { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
|
|
7
|
+
import type OverviewMap from "ol/control/OverviewMap";
|
|
8
|
+
import type MapMarker from "./MapMarker";
|
|
9
|
+
import type { LinePoint, ViewToOptions } from "./types";
|
|
10
|
+
import type {
|
|
11
|
+
AnimationHandle,
|
|
12
|
+
LatLngLiteral,
|
|
13
|
+
StorymapData,
|
|
14
|
+
StorymapOptions,
|
|
15
|
+
StorymapSlide,
|
|
16
|
+
StorymapSlideLocation,
|
|
17
|
+
} from "../types";
|
|
18
|
+
/* Map
|
|
19
|
+
Makes a Map
|
|
20
|
+
|
|
21
|
+
Events:
|
|
22
|
+
markerAdded
|
|
23
|
+
markerRemoved
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
================================================ */
|
|
27
|
+
|
|
28
|
+
/** Wheel/scroll zoom bookkeeping (handles cleared via clearTimeout). */
|
|
29
|
+
interface ScrollState {
|
|
30
|
+
start_time: number | null;
|
|
31
|
+
timer?: ReturnType<typeof setTimeout>;
|
|
32
|
+
timer_done?: ReturnType<typeof setTimeout>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class MapBase {
|
|
36
|
+
declare "_el": { container: HTMLElement; map: HTMLElement; map_mask: HTMLElement };
|
|
37
|
+
declare "_loaded": { data: boolean; map: boolean };
|
|
38
|
+
declare "_map": OlMap | null;
|
|
39
|
+
declare "_mini_map": OverviewMap | null;
|
|
40
|
+
declare "_markers": MapMarker[];
|
|
41
|
+
declare "zoom_min_max": { min: number | null; max: number | null };
|
|
42
|
+
declare "_line": VectorLayer | null;
|
|
43
|
+
declare "_line_active": VectorLayer | null;
|
|
44
|
+
declare "current_marker": number;
|
|
45
|
+
declare "bounds_array": number[][] | null;
|
|
46
|
+
declare "_tile_layer": TileLayer | null;
|
|
47
|
+
declare "_tile_layer_mini": TileLayer | null;
|
|
48
|
+
declare "_image_layer": TileLayer | null;
|
|
49
|
+
declare "data": StorymapData;
|
|
50
|
+
declare "options": StorymapOptions;
|
|
51
|
+
declare "animator": AnimationHandle | null;
|
|
52
|
+
declare "_transition_duration": number;
|
|
53
|
+
declare "timer": ReturnType<typeof setTimeout> | null;
|
|
54
|
+
declare "touch_scale": number;
|
|
55
|
+
declare "scroll": ScrollState;
|
|
56
|
+
declare "fire": EventedInstance["fire"];
|
|
57
|
+
constructor(
|
|
58
|
+
elem: string | HTMLElement,
|
|
59
|
+
data?: Partial<StorymapData>,
|
|
60
|
+
options?: Partial<StorymapOptions>,
|
|
61
|
+
) {
|
|
62
|
+
// DOM ELEMENTS
|
|
63
|
+
this._el = {
|
|
64
|
+
container: {} as HTMLElement,
|
|
65
|
+
map: {} as HTMLElement,
|
|
66
|
+
map_mask: {} as HTMLElement,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
if (typeof elem === "object") {
|
|
70
|
+
this._el.container = elem;
|
|
71
|
+
} else {
|
|
72
|
+
this._el.container = Dom.get(elem);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// LOADED
|
|
76
|
+
this._loaded = {
|
|
77
|
+
data: false,
|
|
78
|
+
map: false,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// MAP
|
|
82
|
+
this._map = null;
|
|
83
|
+
|
|
84
|
+
// MINI MAP
|
|
85
|
+
this._mini_map = null;
|
|
86
|
+
|
|
87
|
+
// Markers
|
|
88
|
+
this._markers = [];
|
|
89
|
+
|
|
90
|
+
// Marker Zoom Miniumum and Maximum
|
|
91
|
+
this.zoom_min_max = {
|
|
92
|
+
min: null,
|
|
93
|
+
max: null,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// Line
|
|
97
|
+
this._line = null;
|
|
98
|
+
this._line_active = null;
|
|
99
|
+
|
|
100
|
+
// Current Marker
|
|
101
|
+
this.current_marker = 0;
|
|
102
|
+
|
|
103
|
+
// Markers Bounds Array
|
|
104
|
+
this.bounds_array = null;
|
|
105
|
+
|
|
106
|
+
// Map Tiles Layer
|
|
107
|
+
this._tile_layer = null;
|
|
108
|
+
|
|
109
|
+
// Map Tiles Layer for Mini Map
|
|
110
|
+
this._tile_layer_mini = null;
|
|
111
|
+
|
|
112
|
+
// Image Layer (for iiif)
|
|
113
|
+
this._image_layer = null;
|
|
114
|
+
|
|
115
|
+
// Data
|
|
116
|
+
this.data = {
|
|
117
|
+
uniqueid: "",
|
|
118
|
+
slides: [{ test: "yes" }, { test: "yes" }, { test: "yes" }],
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
//Options
|
|
122
|
+
this.options = {
|
|
123
|
+
map_type: "osm:standard",
|
|
124
|
+
map_as_image: false,
|
|
125
|
+
map_mini: false,
|
|
126
|
+
map_background_color: "#d9d9d9",
|
|
127
|
+
map_subdomains: "",
|
|
128
|
+
map_access_token: "",
|
|
129
|
+
overlays: [],
|
|
130
|
+
overview_extent: null,
|
|
131
|
+
iiif: {
|
|
132
|
+
url: "",
|
|
133
|
+
attribution: "",
|
|
134
|
+
},
|
|
135
|
+
skinny_size: 650,
|
|
136
|
+
less_bounce: true,
|
|
137
|
+
path_gfx: "gfx",
|
|
138
|
+
start_at_slide: 0,
|
|
139
|
+
map_popup: false,
|
|
140
|
+
zoom_distance: 100,
|
|
141
|
+
calculate_zoom: true, // Allow map to determine best zoom level between markers (recommended)
|
|
142
|
+
line_follows_path: true, // Map history path follows default line, if false it will connect previous and current only
|
|
143
|
+
line_color: "#333",
|
|
144
|
+
line_color_inactive: "#000",
|
|
145
|
+
line_weight: 5,
|
|
146
|
+
line_opacity: 0.2,
|
|
147
|
+
line_dash: "5,5",
|
|
148
|
+
line_join: "miter",
|
|
149
|
+
show_lines: true,
|
|
150
|
+
show_history_line: true,
|
|
151
|
+
map_center_offset: null, // takes object {top:0,left:0}
|
|
152
|
+
} as StorymapOptions;
|
|
153
|
+
|
|
154
|
+
// Animation
|
|
155
|
+
this.animator = null;
|
|
156
|
+
this._transition_duration = this.options.duration;
|
|
157
|
+
|
|
158
|
+
// Timer
|
|
159
|
+
this.timer = null;
|
|
160
|
+
|
|
161
|
+
// Touchpad Events
|
|
162
|
+
this.touch_scale = 1;
|
|
163
|
+
this.scroll = {
|
|
164
|
+
start_time: null,
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// Merge Data and Options
|
|
168
|
+
mergeData(this.options, options);
|
|
169
|
+
mergeData(this.data, data);
|
|
170
|
+
|
|
171
|
+
this._initLayout();
|
|
172
|
+
this._initEvents();
|
|
173
|
+
this._createMap();
|
|
174
|
+
this._initData();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* Public
|
|
178
|
+
================================================== */
|
|
179
|
+
updateDisplay(w: number, h: number, animate?: boolean, d?: number, offset?: unknown): void {
|
|
180
|
+
this._updateDisplay(w, h, animate, d, offset);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
goTo(n: number, change?: boolean): void {
|
|
184
|
+
if (n < this._markers.length && n >= 0) {
|
|
185
|
+
let zoom;
|
|
186
|
+
const previous_marker = this.current_marker;
|
|
187
|
+
|
|
188
|
+
this.current_marker = n;
|
|
189
|
+
|
|
190
|
+
// Scale the transition duration with the jump distance so that
|
|
191
|
+
// out-of-order navigation glides instead of flicking
|
|
192
|
+
this._transition_duration = slideTransitionDuration(previous_marker, n);
|
|
193
|
+
|
|
194
|
+
const marker = this._markers[this.current_marker];
|
|
195
|
+
|
|
196
|
+
// Stop animation
|
|
197
|
+
if (this.animator) {
|
|
198
|
+
this.animator.stop();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Reset Active Markers
|
|
202
|
+
this._resetMarkersActive();
|
|
203
|
+
|
|
204
|
+
// Check to see if it's an overview
|
|
205
|
+
if (marker.data.type && marker.data.type === "overview") {
|
|
206
|
+
this._markerOverview();
|
|
207
|
+
if (!change) {
|
|
208
|
+
this._onMarkerChange();
|
|
209
|
+
}
|
|
210
|
+
} else {
|
|
211
|
+
// Make marker active
|
|
212
|
+
marker.active(true);
|
|
213
|
+
|
|
214
|
+
if (change) {
|
|
215
|
+
// Set Map View
|
|
216
|
+
if (marker.data.location) {
|
|
217
|
+
this._viewTo(marker.data.location, {
|
|
218
|
+
duration: this._transition_duration,
|
|
219
|
+
});
|
|
220
|
+
} else {
|
|
221
|
+
// nothing to show
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
if (this._hasLocation(marker.data)) {
|
|
225
|
+
// Calculate Zoom
|
|
226
|
+
zoom = this._calculateZoomChange(
|
|
227
|
+
this._getMapCenter(true),
|
|
228
|
+
marker.location(),
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
// Set Map View
|
|
232
|
+
this._viewTo(marker.data.location, {
|
|
233
|
+
calculate_zoom: this.options.calculate_zoom,
|
|
234
|
+
zoom: zoom,
|
|
235
|
+
duration: this._transition_duration,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Show Line
|
|
239
|
+
if (this.options.line_follows_path) {
|
|
240
|
+
if (
|
|
241
|
+
this.options.show_history_line &&
|
|
242
|
+
marker.data.real_marker &&
|
|
243
|
+
this._markers[previous_marker].data.real_marker
|
|
244
|
+
) {
|
|
245
|
+
let lines_array: LinePoint[] = [];
|
|
246
|
+
// Accumulate from the first marker so the
|
|
247
|
+
// connections between previous slides stay
|
|
248
|
+
// marked (mirrors the backward branch, which
|
|
249
|
+
// settles at the traveled path 0..current).
|
|
250
|
+
// The end state is the full traveled path, but
|
|
251
|
+
// only the latest hop animates: grow_from is
|
|
252
|
+
// the already-traveled prefix 0..previous,
|
|
253
|
+
// which stays drawn while [prev..current]
|
|
254
|
+
// traces progressively (see _replaceLines).
|
|
255
|
+
let line_num = 0,
|
|
256
|
+
point;
|
|
257
|
+
let retract_path_source: LinePoint[] | null = null;
|
|
258
|
+
let grow_path_source: LinePoint[] | null = null;
|
|
259
|
+
if (previous_marker < this.current_marker) {
|
|
260
|
+
while (line_num < this.current_marker) {
|
|
261
|
+
if (this._hasLocation(this._markers[line_num].data)) {
|
|
262
|
+
point = {
|
|
263
|
+
lat: this._markers[line_num].data.location.lat,
|
|
264
|
+
lon: this._markers[line_num].data.location.lon,
|
|
265
|
+
};
|
|
266
|
+
lines_array.push(point);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
line_num++;
|
|
270
|
+
}
|
|
271
|
+
const grow_path: LinePoint[] = [];
|
|
272
|
+
for (let idx = 0; idx <= previous_marker; idx++) {
|
|
273
|
+
if (this._hasLocation(this._markers[idx].data)) {
|
|
274
|
+
grow_path.push({
|
|
275
|
+
lat: this._markers[idx].data.location.lat,
|
|
276
|
+
lon: this._markers[idx].data.location.lon,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
grow_path_source = grow_path;
|
|
281
|
+
} else if (previous_marker > this.current_marker) {
|
|
282
|
+
// Backward navigation: the line retracts —
|
|
283
|
+
// the end state is the traveled path from
|
|
284
|
+
// the first marker to the current one, and
|
|
285
|
+
// the far end pulls back from the old
|
|
286
|
+
// marker to the new one (handled by the
|
|
287
|
+
// map's retract animation).
|
|
288
|
+
const traveled = [];
|
|
289
|
+
for (let idx = 0; idx <= this.current_marker; idx++) {
|
|
290
|
+
if (this._hasLocation(this._markers[idx].data)) {
|
|
291
|
+
traveled.push({
|
|
292
|
+
lat: this._markers[idx].data.location.lat,
|
|
293
|
+
lon: this._markers[idx].data.location.lon,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const retract_path = [];
|
|
298
|
+
for (let idx = 0; idx <= previous_marker; idx++) {
|
|
299
|
+
if (this._hasLocation(this._markers[idx].data)) {
|
|
300
|
+
retract_path.push({
|
|
301
|
+
lat: this._markers[idx].data.location.lat,
|
|
302
|
+
lon: this._markers[idx].data.location.lon,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
lines_array = traveled;
|
|
307
|
+
retract_path_source = retract_path;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (!retract_path_source) {
|
|
311
|
+
lines_array.push({
|
|
312
|
+
lat: marker.data.location.lat,
|
|
313
|
+
lon: marker.data.location.lon,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
this._replaceLines(this._line_active, lines_array, {
|
|
318
|
+
duration: this._transition_duration,
|
|
319
|
+
retractFrom: retract_path_source,
|
|
320
|
+
growFrom: grow_path_source,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
} else {
|
|
324
|
+
// Show Line
|
|
325
|
+
if (
|
|
326
|
+
this.options.show_history_line &&
|
|
327
|
+
marker.data.real_marker &&
|
|
328
|
+
this._markers[previous_marker].data.real_marker
|
|
329
|
+
) {
|
|
330
|
+
this._replaceLines(
|
|
331
|
+
this._line_active,
|
|
332
|
+
[
|
|
333
|
+
{
|
|
334
|
+
lat: marker.data.location.lat,
|
|
335
|
+
lon: marker.data.location.lon,
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
lat: this._markers[previous_marker].data.location.lat,
|
|
339
|
+
lon: this._markers[previous_marker].data.location.lon,
|
|
340
|
+
},
|
|
341
|
+
],
|
|
342
|
+
{ duration: this._transition_duration },
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
} else {
|
|
347
|
+
this._markerOverview();
|
|
348
|
+
if (!change) {
|
|
349
|
+
this._onMarkerChange();
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Fire Event
|
|
354
|
+
this._onMarkerChange();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
panTo(loc: LatLngLiteral, animate?: boolean): void {
|
|
361
|
+
this._panTo(loc, animate);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
zoomTo(z: number, animate?: boolean): void {
|
|
365
|
+
this._zoomTo(z, animate);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
viewTo(loc: StorymapSlideLocation, opts?: ViewToOptions): void {
|
|
369
|
+
this._viewTo(loc, opts);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
getBoundsZoom(m1: LatLngLiteral, m2: LatLngLiteral, inside?: boolean, padding?: unknown): void {
|
|
373
|
+
this._getBoundsZoom(m1, m2, inside, padding); // (LatLngBounds[, Boolean, Point]) -> Number
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
markerOverview(): void {
|
|
377
|
+
this._markerOverview();
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
calculateMarkerZooms(): void {
|
|
381
|
+
this._calculateMarkerZooms();
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
createMiniMap(): void {
|
|
385
|
+
this._createMiniMap();
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
setMapOffset(left: number, top: number): void {
|
|
389
|
+
// Update Component Displays
|
|
390
|
+
if (!this.options.map_center_offset) {
|
|
391
|
+
this.options.map_center_offset = { left: left, top: top };
|
|
392
|
+
} else {
|
|
393
|
+
this.options.map_center_offset.left = left;
|
|
394
|
+
this.options.map_center_offset.top = top;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
calculateMinMaxZoom(): void {
|
|
399
|
+
for (let i = 0; i < this._markers.length; i++) {
|
|
400
|
+
if (this._markers[i].data.location && this._markers[i].data.location.zoom) {
|
|
401
|
+
this.updateMinMaxZoom(this._markers[i].data.location.zoom);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
updateMinMaxZoom(zoom: number): void {
|
|
407
|
+
if (!this.zoom_min_max.max) {
|
|
408
|
+
this.zoom_min_max.max = zoom;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (!this.zoom_min_max.min) {
|
|
412
|
+
this.zoom_min_max.min = zoom;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (this.zoom_min_max.max < zoom) {
|
|
416
|
+
this.zoom_min_max.max = zoom;
|
|
417
|
+
}
|
|
418
|
+
if (this.zoom_min_max.min > zoom) {
|
|
419
|
+
this.zoom_min_max.min = zoom;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
initialMapLocation(): void {
|
|
424
|
+
if (this._loaded.data && this._loaded.map) {
|
|
425
|
+
// don't clobber navigation that already happened while the map was
|
|
426
|
+
// still loading (the first loadend can arrive late)
|
|
427
|
+
if (this.current_marker === 0) {
|
|
428
|
+
this.goTo(this.options.start_at_slide, true);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/* Adding, Hiding, Showing etc
|
|
434
|
+
================================================== */
|
|
435
|
+
show(): void {}
|
|
436
|
+
|
|
437
|
+
hide(): void {}
|
|
438
|
+
|
|
439
|
+
/* Adding and Removing Markers
|
|
440
|
+
================================================== */
|
|
441
|
+
createMarkers(array: StorymapSlide[]): void {
|
|
442
|
+
this._createMarkers(array);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
createMarker(d: StorymapSlide): void {
|
|
446
|
+
this._createMarker(d);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
_destroyMarker(marker: MapMarker): void {
|
|
450
|
+
this._removeMarker(marker);
|
|
451
|
+
for (let i = 0; i < this._markers.length; i++) {
|
|
452
|
+
if (this._markers[i] === marker) {
|
|
453
|
+
this._markers.splice(i, 1);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
this.fire("markerRemoved", marker);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
_createMarkers(array: StorymapSlide[]): void {
|
|
460
|
+
for (let i = 0; i < array.length; i++) {
|
|
461
|
+
this._createMarker(array[i]); // this must be called even for overview which has no marker or other logic must be fixed.
|
|
462
|
+
if (this._hasLocation(array[i]) && this.options.show_lines) {
|
|
463
|
+
this._addToLine(this._line, array[i]);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* A slide has a real location: lat and lon are both numbers — lat 0 and
|
|
470
|
+
* lon 0 are valid coordinates and must not be treated as missing.
|
|
471
|
+
*/
|
|
472
|
+
_hasLocation(d: StorymapSlide): boolean {
|
|
473
|
+
return (
|
|
474
|
+
!!d.location && typeof d.location.lat == "number" && typeof d.location.lon == "number"
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/* Map Specific
|
|
479
|
+
================================================== */
|
|
480
|
+
|
|
481
|
+
/* Map Specific Create
|
|
482
|
+
================================================== */
|
|
483
|
+
// Extend this map class and use this to create the map using preferred API
|
|
484
|
+
_createMap(): void {}
|
|
485
|
+
|
|
486
|
+
/* Mini Map Specific Create
|
|
487
|
+
================================================== */
|
|
488
|
+
// Extend this map class and use this to create the map using preferred API
|
|
489
|
+
_createMiniMap(): void {}
|
|
490
|
+
|
|
491
|
+
/* Map Specific Marker
|
|
492
|
+
================================================== */
|
|
493
|
+
|
|
494
|
+
// Specific Marker Methods based on preferred Map API
|
|
495
|
+
_createMarker(d?: StorymapSlide): void {
|
|
496
|
+
const marker = {} as MapMarker;
|
|
497
|
+
marker.on("markerclick", this._onMarkerClick);
|
|
498
|
+
this._addMarker(marker);
|
|
499
|
+
this._markers.push(marker);
|
|
500
|
+
marker.marker_number = this._markers.length - 1;
|
|
501
|
+
this.fire("markerAdded", marker);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
_addMarker(marker: MapMarker): void {}
|
|
505
|
+
|
|
506
|
+
_removeMarker(marker: MapMarker): void {}
|
|
507
|
+
|
|
508
|
+
_resetMarkersActive(): void {
|
|
509
|
+
for (let i = 0; i < this._markers.length; i++) {
|
|
510
|
+
this._markers[i].active(false);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
_calculateMarkerZooms(): void {}
|
|
515
|
+
|
|
516
|
+
/* Map Specific Line
|
|
517
|
+
================================================== */
|
|
518
|
+
|
|
519
|
+
_createLine(d?: StorymapSlide): unknown {
|
|
520
|
+
return { data: d };
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
_addToLine(line: VectorLayer | null, d: LinePoint): void {}
|
|
524
|
+
|
|
525
|
+
_replaceLines(
|
|
526
|
+
line: VectorLayer | null,
|
|
527
|
+
d: LinePoint[],
|
|
528
|
+
animate?: {
|
|
529
|
+
duration: number;
|
|
530
|
+
retractFrom?: LinePoint[] | null;
|
|
531
|
+
growFrom?: LinePoint[] | null;
|
|
532
|
+
},
|
|
533
|
+
): void {}
|
|
534
|
+
|
|
535
|
+
_addLineToMap(line: VectorLayer): void {}
|
|
536
|
+
|
|
537
|
+
/* Map Specific Methods
|
|
538
|
+
================================================== */
|
|
539
|
+
|
|
540
|
+
_panTo(loc: LatLngLiteral, animate?: boolean): void {}
|
|
541
|
+
|
|
542
|
+
_zoomTo(z: number, animate?: boolean): void {}
|
|
543
|
+
|
|
544
|
+
_viewTo(loc: StorymapSlideLocation, opts?: ViewToOptions): void {}
|
|
545
|
+
|
|
546
|
+
_updateMapDisplay(animate?: boolean, d?: number): void {}
|
|
547
|
+
|
|
548
|
+
_refreshMap(): void {}
|
|
549
|
+
|
|
550
|
+
_getMapZoom(): number {
|
|
551
|
+
return 1;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
_getMapCenter(correct_for_center?: boolean): LatLngLiteral {
|
|
555
|
+
return { lat: 0, lng: 0 };
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
_getBoundsZoom(
|
|
559
|
+
m1: LatLngLiteral,
|
|
560
|
+
m2: LatLngLiteral,
|
|
561
|
+
inside?: boolean,
|
|
562
|
+
padding?: unknown,
|
|
563
|
+
): number {
|
|
564
|
+
return undefined;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
_markerOverview(duration?: number): void {}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Great-circle length of the route through all markers in kilometers;
|
|
571
|
+
* `undefined` when the map cannot compute it or there are fewer than two
|
|
572
|
+
* markers (issue #341).
|
|
573
|
+
*/
|
|
574
|
+
getRouteDistance(): number | undefined {
|
|
575
|
+
return undefined;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/* Events
|
|
579
|
+
================================================== */
|
|
580
|
+
_onMarkerChange(e?: unknown): void {
|
|
581
|
+
this.fire("change", { current_marker: this.current_marker });
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
_onMarkerClick(e: { marker_number: number }): void {
|
|
585
|
+
if (this.current_marker !== e.marker_number) {
|
|
586
|
+
this.goTo(e.marker_number, false);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
_onMapLoaded(e?: unknown): void {
|
|
591
|
+
// OpenLayers fires `loadend` after every finished tile-load cycle, not
|
|
592
|
+
// just the first render — without this guard every navigation would
|
|
593
|
+
// snap the map back to the start slide once its tiles arrive
|
|
594
|
+
if (this._loaded.map) {
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
this._loaded.map = true;
|
|
598
|
+
|
|
599
|
+
if (this.options.calculate_zoom) {
|
|
600
|
+
this.calculateMarkerZooms();
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
this.calculateMinMaxZoom();
|
|
604
|
+
|
|
605
|
+
if (this.options.map_mini && !Browser.touch) {
|
|
606
|
+
this.createMiniMap();
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
this.initialMapLocation();
|
|
610
|
+
this.fire("loaded", this.data);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
_onWheel(e: WheelEvent): void {
|
|
614
|
+
// borrowed from http://jsbin.com/qiyaseza/5/edit
|
|
615
|
+
if (e.ctrlKey) {
|
|
616
|
+
const s = Math.exp(-e.deltaY / 100);
|
|
617
|
+
this.touch_scale *= s;
|
|
618
|
+
e.preventDefault();
|
|
619
|
+
e.stopPropagation();
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
if (!this.scroll.start_time) {
|
|
623
|
+
this.scroll.start_time = +new Date();
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
const time_left = Math.max(40 - (+new Date() - this.scroll.start_time), 0);
|
|
627
|
+
|
|
628
|
+
clearTimeout(this.scroll.timer);
|
|
629
|
+
|
|
630
|
+
this.scroll.timer = setTimeout(() => {
|
|
631
|
+
this._scollZoom();
|
|
632
|
+
}, time_left);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
_scollZoom(e?: unknown): void {
|
|
636
|
+
const current_zoom = this._getMapZoom();
|
|
637
|
+
|
|
638
|
+
this.scroll.start_time = null;
|
|
639
|
+
clearTimeout(this.scroll.timer);
|
|
640
|
+
clearTimeout(this.scroll.timer_done);
|
|
641
|
+
|
|
642
|
+
this.scroll.timer_done = setTimeout(() => {
|
|
643
|
+
this._scollZoomDone();
|
|
644
|
+
}, 1000);
|
|
645
|
+
|
|
646
|
+
this.zoomTo(Math.round(current_zoom * this.touch_scale));
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
_scollZoomDone(e?: unknown): void {
|
|
650
|
+
this.touch_scale = 1;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/* Private Methods
|
|
654
|
+
================================================== */
|
|
655
|
+
|
|
656
|
+
_calculateZoomChange(
|
|
657
|
+
origin: LatLngLiteral,
|
|
658
|
+
destination: LatLngLiteral,
|
|
659
|
+
correct_for_center?: boolean,
|
|
660
|
+
): number {
|
|
661
|
+
return this._getBoundsZoom(origin, destination, correct_for_center);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
_updateDisplay(w?: number, h?: number, animate?: boolean, d?: number, offset?: unknown): void {
|
|
665
|
+
// Update Map Display
|
|
666
|
+
this._updateMapDisplay(animate, d);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/** Re-apply runtime-changed options (no-op in the base class) */
|
|
670
|
+
applyOptions(_keys: string[]): void {}
|
|
671
|
+
|
|
672
|
+
_initLayout(): void {
|
|
673
|
+
// Create Layout
|
|
674
|
+
this._el.map_mask = Dom.create("div", "vco-map-mask", this._el.container);
|
|
675
|
+
|
|
676
|
+
if (this.options.map_as_image) {
|
|
677
|
+
this._el.map = Dom.create(
|
|
678
|
+
"div",
|
|
679
|
+
"vco-map-display vco-mapimage-display",
|
|
680
|
+
this._el.map_mask,
|
|
681
|
+
);
|
|
682
|
+
} else {
|
|
683
|
+
this._el.map = Dom.create("div", "vco-map-display", this._el.map_mask);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
_initData(): void {
|
|
688
|
+
if (this.data.slides) {
|
|
689
|
+
this._createMarkers(this.data.slides);
|
|
690
|
+
this._afterCreateMarkers();
|
|
691
|
+
this._resetMarkersActive();
|
|
692
|
+
if (this._markers.length > 0) {
|
|
693
|
+
this._markers[this.current_marker].active(true);
|
|
694
|
+
}
|
|
695
|
+
this._loaded.data = true;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/** Hook after marker creation (overridden per engine as needed) */
|
|
700
|
+
_afterCreateMarkers(): void {}
|
|
701
|
+
|
|
702
|
+
_initEvents(): void {
|
|
703
|
+
this._el.map.addEventListener("wheel", (e) => {
|
|
704
|
+
this._onWheel(e);
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
//this.on("wheel", this._onWheel, this);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
export default class Map extends DomMixed(Evented(MapBase)) {
|
|
712
|
+
constructor(...args: ConstructorParameters<typeof MapBase>) {
|
|
713
|
+
super(...args);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
export { Map };
|