@jupytergis/schema 0.10.1 → 0.11.1
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/lib/_interface/forms.json +64 -0
- package/lib/_interface/project/jgis.d.ts +22 -1
- package/lib/_interface/project/layers/storySegmentLayer.d.ts +39 -0
- package/lib/doc.d.ts +12 -2
- package/lib/doc.js +79 -5
- package/lib/interfaces.d.ts +26 -1
- package/lib/model.d.ts +19 -2
- package/lib/model.js +76 -2
- package/lib/schema/project/jgis.json +31 -1
- package/lib/schema/project/layers/storySegmentLayer.json +55 -0
- package/lib/types.d.ts +1 -0
- package/lib/types.js +1 -0
- package/package.json +1 -1
|
@@ -302,6 +302,70 @@
|
|
|
302
302
|
}
|
|
303
303
|
}
|
|
304
304
|
},
|
|
305
|
+
"StorySegmentLayer": {
|
|
306
|
+
"type": "object",
|
|
307
|
+
"additionalProperties": false,
|
|
308
|
+
"required": [
|
|
309
|
+
"zoom",
|
|
310
|
+
"extent",
|
|
311
|
+
"transition"
|
|
312
|
+
],
|
|
313
|
+
"properties": {
|
|
314
|
+
"zoom": {
|
|
315
|
+
"type": "number",
|
|
316
|
+
"default": 0
|
|
317
|
+
},
|
|
318
|
+
"extent": {
|
|
319
|
+
"type": "array",
|
|
320
|
+
"default": null,
|
|
321
|
+
"items": {
|
|
322
|
+
"type": "number"
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
"content": {
|
|
326
|
+
"type": "object",
|
|
327
|
+
"additionalProperties": false,
|
|
328
|
+
"properties": {
|
|
329
|
+
"title": {
|
|
330
|
+
"type": "string"
|
|
331
|
+
},
|
|
332
|
+
"image": {
|
|
333
|
+
"type": "string",
|
|
334
|
+
"description": "Link to image for the story"
|
|
335
|
+
},
|
|
336
|
+
"markdown": {
|
|
337
|
+
"type": "string",
|
|
338
|
+
"description": "Markdown string representing the content of the story stop"
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
"transition": {
|
|
343
|
+
"type": "object",
|
|
344
|
+
"description": "Transition configuration between to this story segment",
|
|
345
|
+
"properties": {
|
|
346
|
+
"type": {
|
|
347
|
+
"type": "string",
|
|
348
|
+
"enum": [
|
|
349
|
+
"linear",
|
|
350
|
+
"immediate",
|
|
351
|
+
"smooth"
|
|
352
|
+
],
|
|
353
|
+
"description": "Transition animation style",
|
|
354
|
+
"default": "linear"
|
|
355
|
+
},
|
|
356
|
+
"time": {
|
|
357
|
+
"type": "number",
|
|
358
|
+
"description": "The time in seconds for the transition",
|
|
359
|
+
"default": 1
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
"required": [
|
|
363
|
+
"type",
|
|
364
|
+
"time"
|
|
365
|
+
]
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
},
|
|
305
369
|
"VectorLayer": {
|
|
306
370
|
"type": "object",
|
|
307
371
|
"required": [
|
|
@@ -17,7 +17,8 @@ export type LayerType =
|
|
|
17
17
|
| "WebGlLayer"
|
|
18
18
|
| "ImageLayer"
|
|
19
19
|
| "HeatmapLayer"
|
|
20
|
-
| "StacLayer"
|
|
20
|
+
| "StacLayer"
|
|
21
|
+
| "StorySegmentLayer";
|
|
21
22
|
/**
|
|
22
23
|
* This interface was referenced by `IJGISContent`'s JSON-Schema
|
|
23
24
|
* via the `definition` "sourceType".
|
|
@@ -43,6 +44,7 @@ export type IJGISLayerItem = string | IJGISLayerGroup;
|
|
|
43
44
|
* via the `definition` "jGISLayerTree".
|
|
44
45
|
*/
|
|
45
46
|
export type IJGISLayerTree = IJGISLayerItem[];
|
|
47
|
+
export type WhetherPresentationModeIsActive = boolean;
|
|
46
48
|
|
|
47
49
|
export interface IJGISContent {
|
|
48
50
|
schemaVersion?: string;
|
|
@@ -140,4 +142,23 @@ export interface IJGISOptions {
|
|
|
140
142
|
extent?: number[];
|
|
141
143
|
projection?: string;
|
|
142
144
|
useExtent?: boolean;
|
|
145
|
+
storyMapPresentationMode?: WhetherPresentationModeIsActive;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* This interface was referenced by `IJGISContent`'s JSON-Schema
|
|
149
|
+
* via the `definition` "jGISStoryMap".
|
|
150
|
+
*/
|
|
151
|
+
export interface IJGISStoryMap {
|
|
152
|
+
/**
|
|
153
|
+
* The title of the story map
|
|
154
|
+
*/
|
|
155
|
+
title?: string;
|
|
156
|
+
/**
|
|
157
|
+
* The type of story map
|
|
158
|
+
*/
|
|
159
|
+
storyType?: "guided" | "unguided";
|
|
160
|
+
/**
|
|
161
|
+
* Array of story segments for the story map
|
|
162
|
+
*/
|
|
163
|
+
storySegments?: string[];
|
|
143
164
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/**
|
|
3
|
+
* This file was automatically generated by json-schema-to-typescript.
|
|
4
|
+
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
|
|
5
|
+
* and run json-schema-to-typescript to regenerate this file.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* StorySegmentLayer
|
|
10
|
+
*/
|
|
11
|
+
export interface IStorySegmentLayer {
|
|
12
|
+
zoom: number;
|
|
13
|
+
extent: number[];
|
|
14
|
+
content?: {
|
|
15
|
+
title?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Link to image for the story
|
|
18
|
+
*/
|
|
19
|
+
image?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Markdown string representing the content of the story stop
|
|
22
|
+
*/
|
|
23
|
+
markdown?: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Transition configuration between to this story segment
|
|
27
|
+
*/
|
|
28
|
+
transition: {
|
|
29
|
+
/**
|
|
30
|
+
* Transition animation style
|
|
31
|
+
*/
|
|
32
|
+
type: "linear" | "immediate" | "smooth";
|
|
33
|
+
/**
|
|
34
|
+
* The time in seconds for the transition
|
|
35
|
+
*/
|
|
36
|
+
time: number;
|
|
37
|
+
[k: string]: any;
|
|
38
|
+
};
|
|
39
|
+
}
|
package/lib/doc.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { MapChange, YDocument } from '@jupyter/ydoc';
|
|
2
2
|
import { JSONObject } from '@lumino/coreutils';
|
|
3
3
|
import { ISignal } from '@lumino/signaling';
|
|
4
|
-
import { IJGISLayer, IJGISLayerItem, IJGISLayerTree, IJGISLayers, IJGISOptions, IJGISSource, IJGISSources } from './_interface/project/jgis';
|
|
5
|
-
import { IDict, IJGISLayerDocChange, IJGISLayerTreeDocChange, IJGISSourceDocChange, IJupyterGISDoc, IJupyterGISDocChange } from './interfaces';
|
|
4
|
+
import { IJGISLayer, IJGISLayerItem, IJGISLayerTree, IJGISLayers, IJGISOptions, IJGISSource, IJGISSources, IJGISStoryMap } from './_interface/project/jgis';
|
|
5
|
+
import { IDict, IJGISLayerDocChange, IJGISLayerTreeDocChange, IJGISSourceDocChange, IJGISStoryMapDocChange, IJGISStoryMaps, IJupyterGISDoc, IJupyterGISDocChange } from './interfaces';
|
|
6
6
|
export declare class JupyterGISDoc extends YDocument<IJupyterGISDocChange> implements IJupyterGISDoc {
|
|
7
7
|
constructor();
|
|
8
8
|
getSource(): JSONObject;
|
|
@@ -13,6 +13,8 @@ export declare class JupyterGISDoc extends YDocument<IJupyterGISDocChange> imple
|
|
|
13
13
|
set layers(layers: IJGISLayers);
|
|
14
14
|
set sources(sources: IJGISSources);
|
|
15
15
|
get sources(): IJGISSources;
|
|
16
|
+
set stories(stories: IJGISStoryMaps);
|
|
17
|
+
get stories(): IJGISStoryMaps;
|
|
16
18
|
get layerTree(): IJGISLayerTree;
|
|
17
19
|
set layerTree(layerTree: IJGISLayerTree);
|
|
18
20
|
getLayer(id: string): IJGISLayer | undefined;
|
|
@@ -22,6 +24,7 @@ export declare class JupyterGISDoc extends YDocument<IJupyterGISDocChange> imple
|
|
|
22
24
|
get layersChanged(): ISignal<IJupyterGISDoc, IJGISLayerDocChange>;
|
|
23
25
|
get layerTreeChanged(): ISignal<IJupyterGISDoc, IJGISLayerTreeDocChange>;
|
|
24
26
|
get sourcesChanged(): ISignal<IJupyterGISDoc, IJGISSourceDocChange>;
|
|
27
|
+
get storyMapsChanged(): ISignal<IJupyterGISDoc, IJGISStoryMapDocChange>;
|
|
25
28
|
get optionsChanged(): ISignal<IJupyterGISDoc, MapChange>;
|
|
26
29
|
layerExists(id: string): boolean;
|
|
27
30
|
removeLayer(id: string): void;
|
|
@@ -35,6 +38,10 @@ export declare class JupyterGISDoc extends YDocument<IJupyterGISDocChange> imple
|
|
|
35
38
|
removeSource(id: string): void;
|
|
36
39
|
addSource(id: string, value: IJGISSource): void;
|
|
37
40
|
updateSource(id: string, value: any): void;
|
|
41
|
+
removeStoryMap(id: string): void;
|
|
42
|
+
addStoryMap(id: string, value: IJGISStoryMap): void;
|
|
43
|
+
updateStoryMap(id: string, value: any): void;
|
|
44
|
+
getStoryMap(id: string): IJGISStoryMap | undefined;
|
|
38
45
|
getOption(key: keyof IJGISOptions): IDict | undefined;
|
|
39
46
|
setOption(key: keyof IJGISOptions, value: IDict): void;
|
|
40
47
|
getMetadata(key: string): string | undefined;
|
|
@@ -52,16 +59,19 @@ export declare class JupyterGISDoc extends YDocument<IJupyterGISDocChange> imple
|
|
|
52
59
|
private _layersObserver;
|
|
53
60
|
private _layerTreeObserver;
|
|
54
61
|
private _sourcesObserver;
|
|
62
|
+
private _storyMapsObserver;
|
|
55
63
|
private _optionsObserver;
|
|
56
64
|
private _metaObserver;
|
|
57
65
|
private _layers;
|
|
58
66
|
private _layerTree;
|
|
59
67
|
private _sources;
|
|
68
|
+
private _stories;
|
|
60
69
|
private _options;
|
|
61
70
|
private _metadata;
|
|
62
71
|
private _optionsChanged;
|
|
63
72
|
private _layersChanged;
|
|
64
73
|
private _layerTreeChanged;
|
|
65
74
|
private _sourcesChanged;
|
|
75
|
+
private _storyMapsChanged;
|
|
66
76
|
private _metadataChanged;
|
|
67
77
|
}
|
package/lib/doc.js
CHANGED
|
@@ -7,27 +7,47 @@ export class JupyterGISDoc extends YDocument {
|
|
|
7
7
|
super();
|
|
8
8
|
this.editable = true;
|
|
9
9
|
this._optionsObserver = (event) => {
|
|
10
|
-
|
|
10
|
+
const changes = new Map();
|
|
11
|
+
event.changes.keys.forEach((event, key) => {
|
|
12
|
+
changes.set(key, {
|
|
13
|
+
action: event.action,
|
|
14
|
+
oldValue: event.oldValue,
|
|
15
|
+
newValue: this._options.get(key),
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
this._optionsChanged.emit(changes);
|
|
11
19
|
};
|
|
12
20
|
this._metaObserver = (event) => {
|
|
13
|
-
|
|
21
|
+
const changes = new Map();
|
|
22
|
+
event.changes.keys.forEach((event, key) => {
|
|
23
|
+
changes.set(key, {
|
|
24
|
+
action: event.action,
|
|
25
|
+
oldValue: event.oldValue,
|
|
26
|
+
newValue: this._metadata.get(key),
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
this._metadataChanged.emit(changes);
|
|
14
30
|
};
|
|
15
31
|
this._optionsChanged = new Signal(this);
|
|
16
32
|
this._layersChanged = new Signal(this);
|
|
17
33
|
this._layerTreeChanged = new Signal(this);
|
|
18
34
|
this._sourcesChanged = new Signal(this);
|
|
35
|
+
this._storyMapsChanged = new Signal(this);
|
|
19
36
|
this._metadataChanged = new Signal(this);
|
|
20
37
|
this._options = this.ydoc.getMap('options');
|
|
21
38
|
this._layers = this.ydoc.getMap('layers');
|
|
22
39
|
this._layerTree = this.ydoc.getArray('layerTree');
|
|
23
40
|
this._sources = this.ydoc.getMap('sources');
|
|
41
|
+
this._stories = this.ydoc.getMap('stories');
|
|
24
42
|
this._metadata = this.ydoc.getMap('metadata');
|
|
25
43
|
this.undoManager.addToScope(this._layers);
|
|
26
44
|
this.undoManager.addToScope(this._sources);
|
|
45
|
+
this.undoManager.addToScope(this._stories);
|
|
27
46
|
this.undoManager.addToScope(this._layerTree);
|
|
28
47
|
this._layers.observeDeep(this._layersObserver.bind(this));
|
|
29
48
|
this._layerTree.observe(this._layerTreeObserver.bind(this));
|
|
30
49
|
this._sources.observeDeep(this._sourcesObserver.bind(this));
|
|
50
|
+
this._stories.observeDeep(this._storyMapsObserver.bind(this));
|
|
31
51
|
this._options.observe(this._optionsObserver.bind(this));
|
|
32
52
|
this._metadata.observe(this._metaObserver.bind(this));
|
|
33
53
|
}
|
|
@@ -36,8 +56,9 @@ export class JupyterGISDoc extends YDocument {
|
|
|
36
56
|
const layerTree = this._layerTree.toJSON();
|
|
37
57
|
const options = this._options.toJSON();
|
|
38
58
|
const sources = this._sources.toJSON();
|
|
59
|
+
const stories = this._stories.toJSON();
|
|
39
60
|
const metadata = this._metadata.toJSON();
|
|
40
|
-
return { layers, layerTree, sources, options, metadata };
|
|
61
|
+
return { layers, layerTree, sources, stories, options, metadata };
|
|
41
62
|
}
|
|
42
63
|
setSource(value) {
|
|
43
64
|
if (!value) {
|
|
@@ -48,7 +69,7 @@ export class JupyterGISDoc extends YDocument {
|
|
|
48
69
|
}
|
|
49
70
|
value = value;
|
|
50
71
|
this.transact(() => {
|
|
51
|
-
var _a, _b, _c, _d, _e;
|
|
72
|
+
var _a, _b, _c, _d, _e, _f;
|
|
52
73
|
const layers = (_a = value['layers']) !== null && _a !== void 0 ? _a : {};
|
|
53
74
|
Object.entries(layers).forEach(([key, val]) => this._layers.set(key, val));
|
|
54
75
|
const layerTree = (_b = value['layerTree']) !== null && _b !== void 0 ? _b : [];
|
|
@@ -59,7 +80,9 @@ export class JupyterGISDoc extends YDocument {
|
|
|
59
80
|
Object.entries(options).forEach(([key, val]) => this._options.set(key, val));
|
|
60
81
|
const sources = (_d = value['sources']) !== null && _d !== void 0 ? _d : {};
|
|
61
82
|
Object.entries(sources).forEach(([key, val]) => this._sources.set(key, val));
|
|
62
|
-
const
|
|
83
|
+
const stories = (_e = value['stories']) !== null && _e !== void 0 ? _e : {};
|
|
84
|
+
Object.entries(stories).forEach(([key, val]) => this._stories.set(key, val));
|
|
85
|
+
const metadata = (_f = value['metadata']) !== null && _f !== void 0 ? _f : {};
|
|
63
86
|
Object.entries(metadata).forEach(([key, val]) => this._metadata.set(key, val));
|
|
64
87
|
});
|
|
65
88
|
}
|
|
@@ -89,6 +112,16 @@ export class JupyterGISDoc extends YDocument {
|
|
|
89
112
|
get sources() {
|
|
90
113
|
return JSONExt.deepCopy(this._sources.toJSON());
|
|
91
114
|
}
|
|
115
|
+
set stories(stories) {
|
|
116
|
+
this.transact(() => {
|
|
117
|
+
for (const [key, value] of Object.entries(stories)) {
|
|
118
|
+
this._stories.set(key, value);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
get stories() {
|
|
123
|
+
return JSONExt.deepCopy(this._stories.toJSON());
|
|
124
|
+
}
|
|
92
125
|
get layerTree() {
|
|
93
126
|
return JSONExt.deepCopy(this._layerTree.toJSON());
|
|
94
127
|
}
|
|
@@ -129,6 +162,9 @@ export class JupyterGISDoc extends YDocument {
|
|
|
129
162
|
get sourcesChanged() {
|
|
130
163
|
return this._sourcesChanged;
|
|
131
164
|
}
|
|
165
|
+
get storyMapsChanged() {
|
|
166
|
+
return this._storyMapsChanged;
|
|
167
|
+
}
|
|
132
168
|
get optionsChanged() {
|
|
133
169
|
return this._optionsChanged;
|
|
134
170
|
}
|
|
@@ -201,6 +237,25 @@ export class JupyterGISDoc extends YDocument {
|
|
|
201
237
|
updateSource(id, value) {
|
|
202
238
|
this.transact(() => this._sources.set(id, value));
|
|
203
239
|
}
|
|
240
|
+
removeStoryMap(id) {
|
|
241
|
+
this.transact(() => {
|
|
242
|
+
this._stories.delete(id);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
addStoryMap(id, value) {
|
|
246
|
+
this.transact(() => {
|
|
247
|
+
this._stories.set(id, value);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
updateStoryMap(id, value) {
|
|
251
|
+
this.transact(() => this._stories.set(id, value));
|
|
252
|
+
}
|
|
253
|
+
getStoryMap(id) {
|
|
254
|
+
if (!this._stories.has(id)) {
|
|
255
|
+
return undefined;
|
|
256
|
+
}
|
|
257
|
+
return JSONExt.deepCopy(this._stories.get(id));
|
|
258
|
+
}
|
|
204
259
|
getOption(key) {
|
|
205
260
|
const content = this._options.get(key);
|
|
206
261
|
if (!content) {
|
|
@@ -293,4 +348,23 @@ export class JupyterGISDoc extends YDocument {
|
|
|
293
348
|
this._sourcesChanged.emit({ sourceChange: changes });
|
|
294
349
|
}
|
|
295
350
|
}
|
|
351
|
+
_storyMapsObserver(events) {
|
|
352
|
+
const changes = [];
|
|
353
|
+
let needEmit = false;
|
|
354
|
+
events.forEach(event => {
|
|
355
|
+
event.keys.forEach((change, key) => {
|
|
356
|
+
if (!needEmit) {
|
|
357
|
+
needEmit = true;
|
|
358
|
+
}
|
|
359
|
+
changes.push({
|
|
360
|
+
id: key,
|
|
361
|
+
newValue: JSONExt.deepCopy(event.target.toJSON()[key]),
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
needEmit = changes.length === 0 ? true : needEmit;
|
|
366
|
+
if (needEmit) {
|
|
367
|
+
this._storyMapsChanged.emit({ storyMapChange: changes });
|
|
368
|
+
}
|
|
369
|
+
}
|
|
296
370
|
}
|
package/lib/interfaces.d.ts
CHANGED
|
@@ -9,10 +9,13 @@ import { JSONObject } from '@lumino/coreutils';
|
|
|
9
9
|
import { ISignal, Signal } from '@lumino/signaling';
|
|
10
10
|
import { SplitPanel } from '@lumino/widgets';
|
|
11
11
|
import { FeatureLike } from 'ol/Feature';
|
|
12
|
-
import { IJGISContent, IJGISLayer, IJGISLayerGroup, IJGISLayerItem, IJGISLayers, IJGISLayerTree, IJGISOptions, IJGISSource, IJGISSources, SourceType } from './_interface/project/jgis';
|
|
12
|
+
import { IJGISContent, IJGISLayer, IJGISLayerGroup, IJGISLayerItem, IJGISLayers, IJGISLayerTree, IJGISOptions, IJGISSource, IJGISSources, IJGISStoryMap, SourceType } from './_interface/project/jgis';
|
|
13
13
|
import { IRasterSource } from './_interface/project/sources/rasterSource';
|
|
14
14
|
import { Modes } from './types';
|
|
15
15
|
export { IGeoJSONSource } from './_interface/project/sources/geoJsonSource';
|
|
16
|
+
export interface IJGISStoryMaps {
|
|
17
|
+
[k: string]: IJGISStoryMap;
|
|
18
|
+
}
|
|
16
19
|
export type JgisCoordinates = {
|
|
17
20
|
x: number;
|
|
18
21
|
y: number;
|
|
@@ -40,6 +43,12 @@ export interface IJGISLayerDocChange {
|
|
|
40
43
|
export interface IJGISLayerTreeDocChange {
|
|
41
44
|
layerTreeChange?: Delta<IJGISLayerItem[]>;
|
|
42
45
|
}
|
|
46
|
+
export interface IJGISStoryMapDocChange {
|
|
47
|
+
storyMapChange?: Array<{
|
|
48
|
+
id: string;
|
|
49
|
+
newValue: IJGISStoryMap | undefined;
|
|
50
|
+
}>;
|
|
51
|
+
}
|
|
43
52
|
export interface IJGISSourceDocChange {
|
|
44
53
|
sourceChange?: Array<{
|
|
45
54
|
id: string;
|
|
@@ -84,6 +93,7 @@ export interface IJupyterGISDoc extends YDocument<IJupyterGISDocChange> {
|
|
|
84
93
|
options: IJGISOptions;
|
|
85
94
|
layers: IJGISLayers;
|
|
86
95
|
sources: IJGISSources;
|
|
96
|
+
stories: IJGISStoryMaps;
|
|
87
97
|
layerTree: IJGISLayerTree;
|
|
88
98
|
metadata: any;
|
|
89
99
|
readonly editable: boolean;
|
|
@@ -100,6 +110,10 @@ export interface IJupyterGISDoc extends YDocument<IJupyterGISDocChange> {
|
|
|
100
110
|
removeSource(id: string): void;
|
|
101
111
|
addSource(id: string, value: IJGISSource): void;
|
|
102
112
|
updateSource(id: string, value: IJGISSource): void;
|
|
113
|
+
getStoryMap(id: string): IJGISStoryMap | undefined;
|
|
114
|
+
removeStoryMap(id: string): void;
|
|
115
|
+
addStoryMap(id: string, value: IJGISStoryMap): void;
|
|
116
|
+
updateStoryMap(id: string, value: IJGISStoryMap): void;
|
|
103
117
|
addLayerTreeItem(index: number, item: IJGISLayerItem): void;
|
|
104
118
|
updateLayerTreeItem(index: number, item: IJGISLayerItem): void;
|
|
105
119
|
updateObjectParameters(id: string, value: IJGISLayer['parameters'] | IJGISSource['parameters']): void;
|
|
@@ -112,6 +126,7 @@ export interface IJupyterGISDoc extends YDocument<IJupyterGISDocChange> {
|
|
|
112
126
|
optionsChanged: ISignal<IJupyterGISDoc, MapChange>;
|
|
113
127
|
layersChanged: ISignal<IJupyterGISDoc, IJGISLayerDocChange>;
|
|
114
128
|
sourcesChanged: ISignal<IJupyterGISDoc, IJGISSourceDocChange>;
|
|
129
|
+
storyMapsChanged: ISignal<IJupyterGISDoc, IJGISStoryMapDocChange>;
|
|
115
130
|
layerTreeChanged: ISignal<IJupyterGISDoc, IJGISLayerTreeDocChange>;
|
|
116
131
|
metadataChanged: ISignal<IJupyterGISDoc, MapChange>;
|
|
117
132
|
}
|
|
@@ -151,6 +166,7 @@ export interface IJupyterGISModel extends DocumentRegistry.IModel {
|
|
|
151
166
|
contentsManager: Contents.IManager | undefined;
|
|
152
167
|
filePath: string;
|
|
153
168
|
pathChanged: ISignal<IJupyterGISModel, string>;
|
|
169
|
+
stories: Map<string, IJGISStoryMap>;
|
|
154
170
|
getFeaturesForCurrentTile: ({ sourceId, }: {
|
|
155
171
|
sourceId: string;
|
|
156
172
|
}) => FeatureLike[];
|
|
@@ -212,6 +228,14 @@ export interface IJupyterGISModel extends DocumentRegistry.IModel {
|
|
|
212
228
|
addFeatureAsMs(id: string, selectedFeature: string): void;
|
|
213
229
|
triggerLayerUpdate(layerId: string, layer: IJGISLayer): void;
|
|
214
230
|
disposed: ISignal<any, void>;
|
|
231
|
+
getSelectedStory(): {
|
|
232
|
+
storySegmentId: string;
|
|
233
|
+
story: IJGISStoryMap | undefined;
|
|
234
|
+
};
|
|
235
|
+
addStorySegment(): {
|
|
236
|
+
storySegmentId: string;
|
|
237
|
+
storyMapId: string;
|
|
238
|
+
} | null;
|
|
215
239
|
}
|
|
216
240
|
export interface IUserData {
|
|
217
241
|
userId: number;
|
|
@@ -316,4 +340,5 @@ export interface IJupyterGISSettings {
|
|
|
316
340
|
objectPropertiesDisabled?: boolean;
|
|
317
341
|
annotationsDisabled?: boolean;
|
|
318
342
|
identifyDisabled?: boolean;
|
|
343
|
+
storyMapsDisabled: boolean;
|
|
319
344
|
}
|
package/lib/model.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
|
6
6
|
import { PartialJSONObject } from '@lumino/coreutils';
|
|
7
7
|
import { ISignal, Signal } from '@lumino/signaling';
|
|
8
8
|
import { FeatureLike } from 'ol/Feature';
|
|
9
|
-
import { IJGISContent, IJGISLayer, IJGISLayerGroup, IJGISLayerTree, IJGISLayers, IJGISOptions, IJGISSource, IJGISSources } from './_interface/project/jgis';
|
|
9
|
+
import { IJGISContent, IJGISLayer, IJGISLayerGroup, IJGISLayerTree, IJGISLayers, IJGISOptions, IJGISSource, IJGISSources, IJGISStoryMap } from './_interface/project/jgis';
|
|
10
10
|
import { IAnnotationModel, IDict, IJGISLayerDocChange, IJGISLayerTreeDocChange, IJGISSourceDocChange, IJupyterGISClientState, IJupyterGISDoc, IJupyterGISModel, ISelection, IUserData, IViewPortState, JgisCoordinates, Pointer, IJupyterGISSettings, SelectionType } from './interfaces';
|
|
11
11
|
import { Modes } from './types';
|
|
12
12
|
export declare class JupyterGISModel implements IJupyterGISModel {
|
|
@@ -157,6 +157,22 @@ export declare class JupyterGISModel implements IJupyterGISModel {
|
|
|
157
157
|
itemId: string;
|
|
158
158
|
} | null>;
|
|
159
159
|
getClientId(): number;
|
|
160
|
+
/**
|
|
161
|
+
* Placeholder in case we eventually want to support multiple stories
|
|
162
|
+
* @returns First/only story
|
|
163
|
+
*/
|
|
164
|
+
getSelectedStory(): {
|
|
165
|
+
storySegmentId: string;
|
|
166
|
+
story: IJGISStoryMap | undefined;
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Adds a story segment from the current map view
|
|
170
|
+
* @returns Object with storySegmentId and storyMapId, or null if no extent/zoom found
|
|
171
|
+
*/
|
|
172
|
+
addStorySegment(): {
|
|
173
|
+
storySegmentId: string;
|
|
174
|
+
storyMapId: string;
|
|
175
|
+
} | null;
|
|
160
176
|
/**
|
|
161
177
|
* Add an item in the layer tree.
|
|
162
178
|
*
|
|
@@ -179,7 +195,7 @@ export declare class JupyterGISModel implements IJupyterGISModel {
|
|
|
179
195
|
removeLayerGroup(groupName: string): void;
|
|
180
196
|
/**
|
|
181
197
|
* Toggle a map interaction mode on or off.
|
|
182
|
-
*
|
|
198
|
+
* Toggling off sets the mode to 'panning'.
|
|
183
199
|
* @param mode The mode to be toggled
|
|
184
200
|
*/
|
|
185
201
|
toggleMode(mode: Modes): void;
|
|
@@ -228,6 +244,7 @@ export declare class JupyterGISModel implements IJupyterGISModel {
|
|
|
228
244
|
private _geolocation;
|
|
229
245
|
private _geolocationChanged;
|
|
230
246
|
private _tileFeatureCache;
|
|
247
|
+
stories: Map<string, IJGISStoryMap>;
|
|
231
248
|
}
|
|
232
249
|
export declare namespace JupyterGISModel {
|
|
233
250
|
/**
|
package/lib/model.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { UUID } from '@lumino/coreutils';
|
|
1
2
|
import { Signal } from '@lumino/signaling';
|
|
2
3
|
import Ajv from 'ajv';
|
|
3
4
|
import { JupyterGISDoc } from './doc';
|
|
@@ -13,6 +14,7 @@ const DEFAULT_SETTINGS = {
|
|
|
13
14
|
objectPropertiesDisabled: false,
|
|
14
15
|
annotationsDisabled: false,
|
|
15
16
|
identifyDisabled: false,
|
|
17
|
+
storyMapsDisabled: false,
|
|
16
18
|
};
|
|
17
19
|
export class JupyterGISModel {
|
|
18
20
|
constructor(options) {
|
|
@@ -60,6 +62,7 @@ export class JupyterGISModel {
|
|
|
60
62
|
this._editingChanged = new Signal(this);
|
|
61
63
|
this._geolocationChanged = new Signal(this);
|
|
62
64
|
this._tileFeatureCache = new Map();
|
|
65
|
+
this.stories = new Map();
|
|
63
66
|
const { annotationModel, sharedModel, settingRegistry } = options;
|
|
64
67
|
if (sharedModel) {
|
|
65
68
|
this._sharedModel = sharedModel;
|
|
@@ -409,7 +412,19 @@ export class JupyterGISModel {
|
|
|
409
412
|
const source_id = (_a = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _a === void 0 ? void 0 : _a.source;
|
|
410
413
|
this._removeLayerTreeLayer(this.getLayerTree(), layer_id);
|
|
411
414
|
this.sharedModel.removeLayer(layer_id);
|
|
412
|
-
|
|
415
|
+
if ((layer === null || layer === void 0 ? void 0 : layer.type) === 'StorySegmentLayer') {
|
|
416
|
+
// remove this layer id from story maps
|
|
417
|
+
Object.entries(this.sharedModel.stories).forEach(([storyMapId, storyMap]) => {
|
|
418
|
+
var _a;
|
|
419
|
+
if ((_a = storyMap.storySegments) === null || _a === void 0 ? void 0 : _a.includes(layer_id)) {
|
|
420
|
+
const updatedStorySegments = storyMap.storySegments.filter(id => id !== layer_id);
|
|
421
|
+
this.sharedModel.updateStoryMap(storyMapId, Object.assign(Object.assign({}, storyMap), { storySegments: updatedStorySegments }));
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
this.sharedModel.removeSource(source_id);
|
|
427
|
+
}
|
|
413
428
|
}
|
|
414
429
|
setOptions(value) {
|
|
415
430
|
this._sharedModel.options = value;
|
|
@@ -470,6 +485,65 @@ export class JupyterGISModel {
|
|
|
470
485
|
getClientId() {
|
|
471
486
|
return this.sharedModel.awareness.clientID;
|
|
472
487
|
}
|
|
488
|
+
/**
|
|
489
|
+
* Placeholder in case we eventually want to support multiple stories
|
|
490
|
+
* @returns First/only story
|
|
491
|
+
*/
|
|
492
|
+
getSelectedStory() {
|
|
493
|
+
const stories = this.sharedModel.stories;
|
|
494
|
+
const storyId = Object.keys(stories)[0];
|
|
495
|
+
return {
|
|
496
|
+
storySegmentId: storyId,
|
|
497
|
+
story: this.sharedModel.getStoryMap(storyId),
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Adds a story segment from the current map view
|
|
502
|
+
* @returns Object with storySegmentId and storyMapId, or null if no extent/zoom found
|
|
503
|
+
*/
|
|
504
|
+
addStorySegment() {
|
|
505
|
+
var _a;
|
|
506
|
+
const { zoom, extent } = this.getOptions();
|
|
507
|
+
if (!zoom || !extent) {
|
|
508
|
+
console.warn('No extent or zoom found');
|
|
509
|
+
return null;
|
|
510
|
+
}
|
|
511
|
+
const storyMapId = UUID.uuid4();
|
|
512
|
+
const newStorySegmentId = UUID.uuid4();
|
|
513
|
+
const layerParams = {
|
|
514
|
+
extent,
|
|
515
|
+
zoom,
|
|
516
|
+
transition: { type: 'linear', time: 1 },
|
|
517
|
+
};
|
|
518
|
+
const layerModel = {
|
|
519
|
+
type: 'StorySegmentLayer',
|
|
520
|
+
visible: true,
|
|
521
|
+
name: 'Story Segment',
|
|
522
|
+
parameters: layerParams,
|
|
523
|
+
};
|
|
524
|
+
this.addLayer(newStorySegmentId, layerModel);
|
|
525
|
+
// check for stories
|
|
526
|
+
const isStoriesExist = Object.keys(this.sharedModel.stories).length !== 0;
|
|
527
|
+
// if not stories, then just add simple
|
|
528
|
+
if (!isStoriesExist) {
|
|
529
|
+
const title = 'New Story';
|
|
530
|
+
const storyType = 'guided';
|
|
531
|
+
const storySegments = [newStorySegmentId];
|
|
532
|
+
const storyMap = { title, storyType, storySegments };
|
|
533
|
+
this.sharedModel.addStoryMap(storyMapId, storyMap);
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
536
|
+
// else need to update stories
|
|
537
|
+
const { story } = this.getSelectedStory();
|
|
538
|
+
if (!story) {
|
|
539
|
+
console.warn('No story found, something went wrong');
|
|
540
|
+
return null;
|
|
541
|
+
}
|
|
542
|
+
const newStory = Object.assign(Object.assign({}, story), { storySegments: [...((_a = story.storySegments) !== null && _a !== void 0 ? _a : []), newStorySegmentId] });
|
|
543
|
+
this.sharedModel.updateStoryMap(storyMapId, newStory);
|
|
544
|
+
}
|
|
545
|
+
return { storySegmentId: newStorySegmentId, storyMapId };
|
|
546
|
+
}
|
|
473
547
|
/**
|
|
474
548
|
* Add an item in the layer tree.
|
|
475
549
|
*
|
|
@@ -612,7 +686,7 @@ export class JupyterGISModel {
|
|
|
612
686
|
}
|
|
613
687
|
/**
|
|
614
688
|
* Toggle a map interaction mode on or off.
|
|
615
|
-
*
|
|
689
|
+
* Toggling off sets the mode to 'panning'.
|
|
616
690
|
* @param mode The mode to be toggled
|
|
617
691
|
*/
|
|
618
692
|
toggleMode(mode) {
|
|
@@ -41,7 +41,8 @@
|
|
|
41
41
|
"WebGlLayer",
|
|
42
42
|
"ImageLayer",
|
|
43
43
|
"HeatmapLayer",
|
|
44
|
-
"StacLayer"
|
|
44
|
+
"StacLayer",
|
|
45
|
+
"StorySegmentLayer"
|
|
45
46
|
]
|
|
46
47
|
},
|
|
47
48
|
"sourceType": {
|
|
@@ -136,6 +137,30 @@
|
|
|
136
137
|
}
|
|
137
138
|
]
|
|
138
139
|
},
|
|
140
|
+
"jGISStoryMap": {
|
|
141
|
+
"title": "IJGISStoryMap",
|
|
142
|
+
"type": "object",
|
|
143
|
+
"additionalProperties": false,
|
|
144
|
+
"properties": {
|
|
145
|
+
"title": {
|
|
146
|
+
"type": "string",
|
|
147
|
+
"description": "The title of the story map"
|
|
148
|
+
},
|
|
149
|
+
"storyType": {
|
|
150
|
+
"type": "string",
|
|
151
|
+
"enum": ["guided", "unguided"],
|
|
152
|
+
"description": "The type of story map"
|
|
153
|
+
},
|
|
154
|
+
"storySegments": {
|
|
155
|
+
"type": "array",
|
|
156
|
+
"default": [],
|
|
157
|
+
"description": "Array of story segments for the story map",
|
|
158
|
+
"items": {
|
|
159
|
+
"type": "string"
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
},
|
|
139
164
|
"jGISLayers": {
|
|
140
165
|
"title": "IJGISLayers",
|
|
141
166
|
"type": "object",
|
|
@@ -201,6 +226,11 @@
|
|
|
201
226
|
"useExtent": {
|
|
202
227
|
"type": "boolean",
|
|
203
228
|
"default": false
|
|
229
|
+
},
|
|
230
|
+
"storyMapPresentationMode": {
|
|
231
|
+
"type": "boolean",
|
|
232
|
+
"title": "Whether presentation mode is active",
|
|
233
|
+
"default": false
|
|
204
234
|
}
|
|
205
235
|
}
|
|
206
236
|
},
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "object",
|
|
3
|
+
"description": "StorySegmentLayer",
|
|
4
|
+
"title": "IStorySegmentLayer",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"required": ["zoom", "extent", "transition"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"zoom": {
|
|
9
|
+
"type": "number",
|
|
10
|
+
"default": 0
|
|
11
|
+
},
|
|
12
|
+
"extent": {
|
|
13
|
+
"type": "array",
|
|
14
|
+
"default": null,
|
|
15
|
+
"items": {
|
|
16
|
+
"type": "number"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"content": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"additionalProperties": false,
|
|
22
|
+
"properties": {
|
|
23
|
+
"title": {
|
|
24
|
+
"type": "string"
|
|
25
|
+
},
|
|
26
|
+
"image": {
|
|
27
|
+
"type": "string",
|
|
28
|
+
"description": "Link to image for the story"
|
|
29
|
+
},
|
|
30
|
+
"markdown": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"description": "Markdown string representing the content of the story stop"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"transition": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"description": "Transition configuration between to this story segment",
|
|
39
|
+
"properties": {
|
|
40
|
+
"type": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"enum": ["linear", "immediate", "smooth"],
|
|
43
|
+
"description": "Transition animation style",
|
|
44
|
+
"default": "linear"
|
|
45
|
+
},
|
|
46
|
+
"time": {
|
|
47
|
+
"type": "number",
|
|
48
|
+
"description": "The time in seconds for the transition",
|
|
49
|
+
"default": 1
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"required": ["type", "time"]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
package/lib/types.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export * from './_interface/project/sources/geoParquetSource';
|
|
|
11
11
|
export * from './_interface/project/sources/markerSource';
|
|
12
12
|
export * from './_interface/project/layers/heatmapLayer';
|
|
13
13
|
export * from './_interface/project/layers/hillshadeLayer';
|
|
14
|
+
export * from './_interface/project/layers/storySegmentLayer';
|
|
14
15
|
export * from './_interface/project/layers/rasterLayer';
|
|
15
16
|
export * from './_interface/project/layers/vectorLayer';
|
|
16
17
|
export * from './_interface/project/layers/imageLayer';
|
package/lib/types.js
CHANGED
|
@@ -13,6 +13,7 @@ export * from './_interface/project/sources/markerSource';
|
|
|
13
13
|
// Layers
|
|
14
14
|
export * from './_interface/project/layers/heatmapLayer';
|
|
15
15
|
export * from './_interface/project/layers/hillshadeLayer';
|
|
16
|
+
export * from './_interface/project/layers/storySegmentLayer';
|
|
16
17
|
export * from './_interface/project/layers/rasterLayer';
|
|
17
18
|
export * from './_interface/project/layers/vectorLayer';
|
|
18
19
|
export * from './_interface/project/layers/imageLayer';
|