@jupytergis/schema 0.1.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.
Files changed (44) hide show
  1. package/lib/_interface/forms.json +1987 -0
  2. package/lib/_interface/geoTiffSource.d.ts +31 -0
  3. package/lib/_interface/geojsonsource.d.ts +404 -0
  4. package/lib/_interface/hillshadeLayer.d.ts +20 -0
  5. package/lib/_interface/imageLayer.d.ts +20 -0
  6. package/lib/_interface/imageSource.d.ts +20 -0
  7. package/lib/_interface/jgis.d.ts +140 -0
  8. package/lib/_interface/rasterDemSource.d.ts +28 -0
  9. package/lib/_interface/rasterlayer.d.ts +20 -0
  10. package/lib/_interface/rastersource.d.ts +43 -0
  11. package/lib/_interface/shapefileSource.d.ts +34 -0
  12. package/lib/_interface/vectorTileLayer.d.ts +32 -0
  13. package/lib/_interface/vectorlayer.d.ts +32 -0
  14. package/lib/_interface/vectortilesource.d.ts +35 -0
  15. package/lib/_interface/videoSource.d.ts +20 -0
  16. package/lib/_interface/webGlLayer.d.ts +24 -0
  17. package/lib/doc.d.ts +59 -0
  18. package/lib/doc.js +251 -0
  19. package/lib/index.d.ts +4 -0
  20. package/lib/index.js +4 -0
  21. package/lib/interfaces.d.ts +189 -0
  22. package/lib/interfaces.js +1 -0
  23. package/lib/model.d.ts +142 -0
  24. package/lib/model.js +554 -0
  25. package/lib/schema/geoTiffSource.json +37 -0
  26. package/lib/schema/geojsonsource.json +23 -0
  27. package/lib/schema/hillshadeLayer.json +18 -0
  28. package/lib/schema/imageLayer.json +21 -0
  29. package/lib/schema/imageSource.json +30 -0
  30. package/lib/schema/jgis.json +248 -0
  31. package/lib/schema/rasterDemSource.json +33 -0
  32. package/lib/schema/rasterlayer.json +21 -0
  33. package/lib/schema/rastersource.json +66 -0
  34. package/lib/schema/shapefileSource.json +37 -0
  35. package/lib/schema/vectorTileLayer.json +36 -0
  36. package/lib/schema/vectorlayer.json +36 -0
  37. package/lib/schema/vectortilesource.json +40 -0
  38. package/lib/schema/videoSource.json +33 -0
  39. package/lib/schema/webGlLayer.json +41 -0
  40. package/lib/token.d.ts +6 -0
  41. package/lib/token.js +5 -0
  42. package/lib/types.d.ts +19 -0
  43. package/lib/types.js +22 -0
  44. package/package.json +65 -0
package/lib/model.js ADDED
@@ -0,0 +1,554 @@
1
+ import { PathExt } from '@jupyterlab/coreutils';
2
+ import { Signal } from '@lumino/signaling';
3
+ import Ajv from 'ajv';
4
+ import { JupyterGISDoc } from './doc';
5
+ import jgisSchema from './schema/jgis.json';
6
+ export class JupyterGISModel {
7
+ constructor(options) {
8
+ this._onSharedModelChanged = (sender, changes) => {
9
+ var _a;
10
+ if (changes && ((_a = changes === null || changes === void 0 ? void 0 : changes.objectChange) === null || _a === void 0 ? void 0 : _a.length)) {
11
+ this._contentChanged.emit(void 0);
12
+ this.dirty = true;
13
+ }
14
+ };
15
+ this.collaborative = true;
16
+ this._onClientStateChanged = (changed) => {
17
+ const clients = this.sharedModel.awareness.getStates();
18
+ this._clientStateChanged.emit(clients);
19
+ this._sharedModel.awareness.on('change', (update) => {
20
+ if (update.added.length || update.removed.length) {
21
+ this._userChanged.emit(this.users);
22
+ }
23
+ });
24
+ };
25
+ this.defaultKernelName = '';
26
+ this.defaultKernelLanguage = '';
27
+ this._dirty = false;
28
+ this._readOnly = false;
29
+ this._isDisposed = false;
30
+ this._userChanged = new Signal(this);
31
+ this._disposed = new Signal(this);
32
+ this._contentChanged = new Signal(this);
33
+ this._stateChanged = new Signal(this);
34
+ this._themeChanged = new Signal(this);
35
+ this._clientStateChanged = new Signal(this);
36
+ const { sharedModel } = options;
37
+ if (sharedModel) {
38
+ this._sharedModel = sharedModel;
39
+ }
40
+ else {
41
+ this._sharedModel = JupyterGISDoc.create();
42
+ this._sharedModel.changed.connect(this._onSharedModelChanged);
43
+ }
44
+ this.sharedModel.awareness.on('change', this._onClientStateChanged);
45
+ }
46
+ get sharedModel() {
47
+ return this._sharedModel;
48
+ }
49
+ get isDisposed() {
50
+ return this._isDisposed;
51
+ }
52
+ get contentChanged() {
53
+ return this._contentChanged;
54
+ }
55
+ get stateChanged() {
56
+ return this._stateChanged;
57
+ }
58
+ get themeChanged() {
59
+ return this._themeChanged;
60
+ }
61
+ get currentUserId() {
62
+ var _a;
63
+ return (_a = this.sharedModel) === null || _a === void 0 ? void 0 : _a.awareness.clientID;
64
+ }
65
+ get users() {
66
+ var _a;
67
+ this._usersMap = (_a = this._sharedModel) === null || _a === void 0 ? void 0 : _a.awareness.getStates();
68
+ const users = [];
69
+ if (this._usersMap) {
70
+ this._usersMap.forEach((val, key) => {
71
+ users.push({ userId: key, userData: val.user });
72
+ });
73
+ }
74
+ return users;
75
+ }
76
+ get userChanged() {
77
+ return this._userChanged;
78
+ }
79
+ get dirty() {
80
+ return this._dirty;
81
+ }
82
+ set dirty(value) {
83
+ this._dirty = value;
84
+ }
85
+ get readOnly() {
86
+ return this._readOnly;
87
+ }
88
+ set readOnly(value) {
89
+ this._readOnly = value;
90
+ }
91
+ get localState() {
92
+ return this.sharedModel.awareness.getLocalState();
93
+ }
94
+ get clientStateChanged() {
95
+ return this._clientStateChanged;
96
+ }
97
+ get sharedOptionsChanged() {
98
+ return this.sharedModel.optionsChanged;
99
+ }
100
+ get sharedLayersChanged() {
101
+ return this.sharedModel.layersChanged;
102
+ }
103
+ get sharedLayerTreeChanged() {
104
+ return this.sharedModel.layerTreeChanged;
105
+ }
106
+ get sharedSourcesChanged() {
107
+ return this.sharedModel.sourcesChanged;
108
+ }
109
+ get terrainChanged() {
110
+ return this.sharedModel.terrainChanged;
111
+ }
112
+ get disposed() {
113
+ return this._disposed;
114
+ }
115
+ dispose() {
116
+ if (this._isDisposed) {
117
+ return;
118
+ }
119
+ this._isDisposed = true;
120
+ this._sharedModel.dispose();
121
+ this._disposed.emit();
122
+ Signal.clearData(this);
123
+ }
124
+ toString() {
125
+ return JSON.stringify(this.getContent(), null, 2);
126
+ }
127
+ fromString(data) {
128
+ const jsonData = JSON.parse(data);
129
+ const ajv = new Ajv();
130
+ const validate = ajv.compile(jgisSchema);
131
+ const valid = validate(jsonData);
132
+ if (!valid) {
133
+ let errorMsg = 'File format errors:\n';
134
+ for (const error of validate.errors || []) {
135
+ errorMsg = `${errorMsg}- ${error.instancePath} ${error.message}\n`;
136
+ }
137
+ throw Error(errorMsg);
138
+ }
139
+ this.sharedModel.transact(() => {
140
+ var _a, _b, _c, _d, _e;
141
+ this.sharedModel.sources = (_a = jsonData.sources) !== null && _a !== void 0 ? _a : {};
142
+ this.sharedModel.layers = (_b = jsonData.layers) !== null && _b !== void 0 ? _b : {};
143
+ this.sharedModel.layerTree = (_c = jsonData.layerTree) !== null && _c !== void 0 ? _c : [];
144
+ this.sharedModel.terrain = (_d = jsonData.terrain) !== null && _d !== void 0 ? _d : {
145
+ source: '',
146
+ exaggeration: 0
147
+ };
148
+ this.sharedModel.options = (_e = jsonData.options) !== null && _e !== void 0 ? _e : {
149
+ latitude: 0,
150
+ longitude: 0,
151
+ zoom: 0,
152
+ bearing: 0,
153
+ pitch: 0,
154
+ projection: 'EPSG:3857'
155
+ };
156
+ });
157
+ this.dirty = true;
158
+ }
159
+ toJSON() {
160
+ return JSON.parse(this.toString());
161
+ }
162
+ fromJSON(data) {
163
+ // nothing to do
164
+ }
165
+ initialize() {
166
+ //
167
+ }
168
+ getWorker() {
169
+ return JupyterGISModel.worker;
170
+ }
171
+ getContent() {
172
+ return {
173
+ sources: this.sharedModel.sources,
174
+ layers: this.sharedModel.layers,
175
+ layerTree: this.sharedModel.layerTree,
176
+ options: this.sharedModel.options,
177
+ terrain: this.sharedModel.terrain
178
+ };
179
+ }
180
+ setDrive(value, filePath) {
181
+ this._drive = value;
182
+ this._filePath = filePath;
183
+ }
184
+ getLayers() {
185
+ return this.sharedModel.layers;
186
+ }
187
+ getSources() {
188
+ return this.sharedModel.sources;
189
+ }
190
+ getLayerTree() {
191
+ return this.sharedModel.layerTree;
192
+ }
193
+ getLayer(id) {
194
+ return this.sharedModel.getLayer(id);
195
+ }
196
+ getSource(id) {
197
+ return this.sharedModel.getSource(id);
198
+ }
199
+ /**
200
+ * Get a {[key: id]: name} dictionary of sources for a given source type
201
+ * @param type The required source type
202
+ */
203
+ getSourcesByType(type) {
204
+ const sources = {};
205
+ for (const sourceId of Object.keys(this.getSources() || {})) {
206
+ const source = this.getSource(sourceId);
207
+ if ((source === null || source === void 0 ? void 0 : source.type) === type) {
208
+ sources[sourceId] = source.name;
209
+ }
210
+ }
211
+ return sources;
212
+ }
213
+ /**
214
+ * Get the list of layers using a source.
215
+ *
216
+ * @param id - the source id.
217
+ * @returns a list of layer ids that use the source.
218
+ */
219
+ getLayersBySource(id) {
220
+ const usingLayers = [];
221
+ Object.entries(this.getLayers() || {}).forEach(([layerId, layer]) => {
222
+ var _a;
223
+ if (((_a = layer.parameters) === null || _a === void 0 ? void 0 : _a.source) === id) {
224
+ usingLayers.push(layerId);
225
+ }
226
+ });
227
+ return usingLayers;
228
+ }
229
+ /**
230
+ * Read a GeoJSON file.
231
+ *
232
+ * @param filepath - the path of the GeoJSON file.
233
+ * @returns a promise to the GeoJSON data.
234
+ */
235
+ async readGeoJSON(filepath) {
236
+ if (!this._drive) {
237
+ return;
238
+ }
239
+ let dir = PathExt.dirname(this._filePath);
240
+ if (dir.includes(':')) {
241
+ dir = dir.split(':')[1];
242
+ }
243
+ const absolutePath = PathExt.join(dir, filepath);
244
+ return this._drive
245
+ .get(absolutePath)
246
+ .then(contentModel => {
247
+ return JSON.parse(contentModel.content);
248
+ })
249
+ .catch(e => {
250
+ throw e;
251
+ });
252
+ }
253
+ /**
254
+ * Add a layer group in the layer tree.
255
+ *
256
+ * @param name - the name of the group.
257
+ * @param groupName - (optional) the name of the parent group in which to include the
258
+ * new group.
259
+ * @param position - (optional) the index of the new group in its parent group or
260
+ * from root of layer tree.
261
+ */
262
+ addGroup(name, groupName, position) {
263
+ const indexesPath = Private.findItemPath(this.getLayerTree(), name);
264
+ if (indexesPath.length) {
265
+ console.warn(`The group "${groupName}" already exist in the layer tree`);
266
+ return;
267
+ }
268
+ const item = {
269
+ name,
270
+ layers: []
271
+ };
272
+ this._addLayerTreeItem(item, groupName, position);
273
+ }
274
+ /**
275
+ * Add a layer in the layer tree and the layers list.
276
+ *
277
+ * @param id - the ID of the layer.
278
+ * @param layer - the layer object.
279
+ * @param groupName - (optional) the name of the group in which to include the new
280
+ * layer.
281
+ * @param position - (optional) the index of the new layer in its parent group or
282
+ * from root of layer tree.
283
+ */
284
+ addLayer(id, layer, groupName, position) {
285
+ if (!this.getLayer(id)) {
286
+ this.sharedModel.addLayer(id, layer);
287
+ }
288
+ this._addLayerTreeItem(id, groupName, position);
289
+ }
290
+ removeLayer(layer_id) {
291
+ this._removeLayerTreeLayer(this.getLayerTree(), layer_id);
292
+ this.sharedModel.removeLayer(layer_id);
293
+ }
294
+ setTerrain(terrain) {
295
+ this._sharedModel.terrain = terrain;
296
+ }
297
+ setOptions(value) {
298
+ this._sharedModel.options = value;
299
+ }
300
+ getOptions() {
301
+ return this._sharedModel.options;
302
+ }
303
+ syncSelected(value, emitter) {
304
+ this.sharedModel.awareness.setLocalStateField('selected', {
305
+ value,
306
+ emitter: emitter
307
+ });
308
+ }
309
+ setUserToFollow(userId) {
310
+ if (this._sharedModel) {
311
+ this._sharedModel.awareness.setLocalStateField('remoteUser', userId);
312
+ }
313
+ }
314
+ getClientId() {
315
+ return this.sharedModel.awareness.clientID;
316
+ }
317
+ /**
318
+ * Add an item in the layer tree.
319
+ *
320
+ * @param item - the item to add.
321
+ * @param groupName - (optional) the name of the parent group in which to include the
322
+ * new item.
323
+ * @param index - (optional) the index of the new item in its parent group or
324
+ * from root of layer tree.
325
+ */
326
+ _addLayerTreeItem(item, groupName, index) {
327
+ if (groupName) {
328
+ const layerTreeInfo = this._getLayerTreeInfo(groupName);
329
+ if (layerTreeInfo) {
330
+ layerTreeInfo.workingGroup.layers.splice(index !== null && index !== void 0 ? index : layerTreeInfo.workingGroup.layers.length, 0, item);
331
+ this._sharedModel.updateLayerTreeItem(layerTreeInfo.mainGroupIndex, layerTreeInfo.mainGroup);
332
+ }
333
+ }
334
+ else {
335
+ this.sharedModel.addLayerTreeItem(index !== null && index !== void 0 ? index : this.getLayerTree().length, item);
336
+ }
337
+ }
338
+ moveItemsToGroup(items, groupName, index) {
339
+ const layerTree = this.getLayerTree();
340
+ for (const item of items) {
341
+ if (this.getLayer(item)) {
342
+ // the item is a layer, remove and add it at the correct position.
343
+ this._removeLayerTreeLayer(layerTree, item);
344
+ this._addLayerTreeItem(item, groupName, index);
345
+ }
346
+ else {
347
+ // the item is a group, let's copy it before removing it.
348
+ const treeInfo = this._getLayerTreeInfo(item);
349
+ if (treeInfo === undefined) {
350
+ continue;
351
+ }
352
+ const group = Object.assign({}, treeInfo.workingGroup);
353
+ this._removeLayerTreeGroup(layerTree, item);
354
+ this._addLayerTreeItem(group, groupName, index);
355
+ }
356
+ }
357
+ }
358
+ moveItemRelatedTo(item, relativeItem, after) {
359
+ var _a;
360
+ const layerTree = this.getLayerTree();
361
+ let insertedItem;
362
+ if (this.getLayer(item)) {
363
+ this._removeLayerTreeLayer(layerTree, item);
364
+ insertedItem = item;
365
+ }
366
+ else {
367
+ const treeInfo = this._getLayerTreeInfo(item);
368
+ if (treeInfo === undefined) {
369
+ return;
370
+ }
371
+ insertedItem = Object.assign({}, treeInfo.workingGroup);
372
+ this._removeLayerTreeGroup(layerTree, item);
373
+ }
374
+ const indexesPath = Private.findItemPath(layerTree, relativeItem);
375
+ const insertedIndex = ((_a = indexesPath.pop()) !== null && _a !== void 0 ? _a : 0) + (after ? 1 : 0);
376
+ let parentGroupName = '';
377
+ let workingGroupId = indexesPath.shift();
378
+ if (workingGroupId !== undefined) {
379
+ let workingGroup = layerTree[workingGroupId];
380
+ while (indexesPath.length) {
381
+ workingGroupId = indexesPath.shift();
382
+ if (workingGroupId === undefined) {
383
+ break;
384
+ }
385
+ workingGroup = workingGroup.layers[workingGroupId];
386
+ }
387
+ parentGroupName = workingGroup.name;
388
+ }
389
+ this._addLayerTreeItem(insertedItem, parentGroupName, insertedIndex);
390
+ }
391
+ addNewLayerGroup(selected, group) {
392
+ const layerTree = this.getLayerTree();
393
+ for (const item in selected) {
394
+ this._removeLayerTreeLayer(layerTree, item);
395
+ }
396
+ this._addLayerTreeItem(group);
397
+ }
398
+ _removeLayerTreeLayer(layerTree, layerIdToRemove) {
399
+ // Iterate over each item in the layerTree
400
+ for (let i = 0; i < layerTree.length; i++) {
401
+ const currentItem = layerTree[i];
402
+ // Check if the current item is a string and matches the target
403
+ if (typeof currentItem === 'string' && currentItem === layerIdToRemove) {
404
+ // Remove the item from the array
405
+ layerTree.splice(i, 1);
406
+ // Decrement i to ensure the next iteration processes the remaining items correctly
407
+ i--;
408
+ }
409
+ else if (typeof currentItem !== 'string' && 'layers' in currentItem) {
410
+ // If the current item is a group, recursively call the function on its layers
411
+ this._removeLayerTreeLayer(currentItem.layers, layerIdToRemove);
412
+ }
413
+ }
414
+ this.sharedModel.layerTree = layerTree;
415
+ }
416
+ _removeLayerTreeGroup(layerTree, groupName) {
417
+ // Iterate over each item in the layerTree
418
+ for (let i = 0; i < layerTree.length; i++) {
419
+ const currentItem = layerTree[i];
420
+ // Check if the current item is a string and matches the target
421
+ if (typeof currentItem !== 'string' && currentItem.name === groupName) {
422
+ // Remove the item from the array
423
+ layerTree.splice(i, 1);
424
+ // Decrement i to ensure the next iteration processes the remaining items correctly
425
+ i--;
426
+ }
427
+ else if (typeof currentItem !== 'string' && 'layers' in currentItem) {
428
+ // If the current item is a group, recursively call the function on its layers
429
+ this._removeLayerTreeGroup(currentItem.layers, groupName);
430
+ }
431
+ }
432
+ this.sharedModel.layerTree = layerTree;
433
+ }
434
+ renameLayerGroup(groupName, newName) {
435
+ const layerTreeInfo = this._getLayerTreeInfo(groupName);
436
+ if (layerTreeInfo) {
437
+ layerTreeInfo.workingGroup.name = newName;
438
+ this._sharedModel.updateLayerTreeItem(layerTreeInfo.mainGroupIndex, layerTreeInfo.mainGroup);
439
+ }
440
+ else {
441
+ console.log('Something went wrong when renaming layer');
442
+ }
443
+ }
444
+ removeLayerGroup(groupName) {
445
+ const layerTree = this.getLayerTree();
446
+ const layerTreeInfo = this._getLayerTreeInfo(groupName);
447
+ const updatedLayerTree = removeLayerGroupEntry(layerTree, groupName);
448
+ function removeLayerGroupEntry(layerTree, groupName) {
449
+ const result = [];
450
+ for (const item of layerTree) {
451
+ if (typeof item === 'string') {
452
+ result.push(item); // Push layer IDs directly
453
+ }
454
+ else if (item.name !== groupName) {
455
+ const filteredLayers = removeLayerGroupEntry(item.layers, groupName);
456
+ result.push(Object.assign(Object.assign({}, item), { layers: filteredLayers })); // Update layers with filtered list
457
+ }
458
+ }
459
+ return result;
460
+ }
461
+ if (layerTreeInfo) {
462
+ this._sharedModel.updateLayerTreeItem(layerTreeInfo.mainGroupIndex, updatedLayerTree[layerTreeInfo.mainGroupIndex]);
463
+ }
464
+ }
465
+ _getLayerTreeInfo(groupName) {
466
+ const layerTree = this.getLayerTree();
467
+ const indexesPath = Private.findItemPath(layerTree, groupName);
468
+ if (!indexesPath.length) {
469
+ console.warn(`The group "${groupName}" does not exist in the layer tree`);
470
+ return;
471
+ }
472
+ const mainGroupIndex = indexesPath.shift();
473
+ if (mainGroupIndex === undefined) {
474
+ return;
475
+ }
476
+ const mainGroup = layerTree[mainGroupIndex];
477
+ let workingGroup = mainGroup;
478
+ while (indexesPath.length) {
479
+ const groupIndex = indexesPath.shift();
480
+ if (groupIndex === undefined) {
481
+ break;
482
+ }
483
+ workingGroup = workingGroup.layers[groupIndex];
484
+ }
485
+ return {
486
+ mainGroup,
487
+ workingGroup,
488
+ mainGroupIndex
489
+ };
490
+ }
491
+ }
492
+ (function (JupyterGISModel) {
493
+ /**
494
+ * Function to get the ordered list of layers according to the tree.
495
+ */
496
+ function getOrderedLayerIds(model) {
497
+ return Private.layerTreeRecursion(model.sharedModel.layerTree);
498
+ }
499
+ JupyterGISModel.getOrderedLayerIds = getOrderedLayerIds;
500
+ })(JupyterGISModel || (JupyterGISModel = {}));
501
+ var Private;
502
+ (function (Private) {
503
+ /**
504
+ * Recursive function through the layer tree to retrieve the flattened layers order.
505
+ *
506
+ * @param items - the items list being scanned.
507
+ * @param current - the current flattened layers.
508
+ */
509
+ function layerTreeRecursion(items, current = []) {
510
+ for (const layer of items) {
511
+ if (typeof layer === 'string') {
512
+ current.push(layer);
513
+ }
514
+ else {
515
+ current.push(...layerTreeRecursion(layer.layers));
516
+ }
517
+ }
518
+ return current;
519
+ }
520
+ Private.layerTreeRecursion = layerTreeRecursion;
521
+ /**
522
+ * Recursive function through the layer tree to retrieve the indexes path to a group
523
+ * or a layer.
524
+ *
525
+ * @param items - the items list being scanned.
526
+ * @param itemId - the target group name or layer ID.
527
+ * @param indexes - the current indexes path to the group
528
+ */
529
+ function findItemPath(items, itemId, indexes = []) {
530
+ for (let index = 0; index < items.length; index++) {
531
+ const item = items[index];
532
+ if (typeof item === 'string') {
533
+ if (item === itemId) {
534
+ const workingIndexes = [...indexes];
535
+ workingIndexes.push(index);
536
+ return workingIndexes;
537
+ }
538
+ }
539
+ else {
540
+ const workingIndexes = [...indexes];
541
+ workingIndexes.push(index);
542
+ if (item.name === itemId) {
543
+ return workingIndexes;
544
+ }
545
+ const foundIndexes = findItemPath(item.layers, itemId, workingIndexes);
546
+ if (foundIndexes.length > workingIndexes.length) {
547
+ return foundIndexes;
548
+ }
549
+ }
550
+ }
551
+ return indexes;
552
+ }
553
+ Private.findItemPath = findItemPath;
554
+ })(Private || (Private = {}));
@@ -0,0 +1,37 @@
1
+ {
2
+ "type": "object",
3
+ "description": "GeoTiffSource",
4
+ "title": "IGeoTiffSource",
5
+ "required": ["urls"],
6
+ "additionalProperties": false,
7
+ "properties": {
8
+ "urls": {
9
+ "type": "array",
10
+ "items": {
11
+ "type": "object",
12
+ "properties": {
13
+ "url": {
14
+ "type": "string"
15
+ },
16
+ "min": {
17
+ "type": "number"
18
+ },
19
+ "max": {
20
+ "type": "number"
21
+ }
22
+ }
23
+ },
24
+ "minItems": 1,
25
+ "default": [],
26
+ "description": "URLs"
27
+ },
28
+ "normalize": {
29
+ "type": "boolean",
30
+ "default": true
31
+ },
32
+ "wrapX": {
33
+ "type": "boolean",
34
+ "default": false
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "type": "object",
3
+ "description": "GeoJSONSource",
4
+ "title": "IGeoJSONSource",
5
+ "required": [],
6
+ "additionalProperties": false,
7
+ "properties": {
8
+ "path": {
9
+ "type": "string",
10
+ "description": "The local path to a GeoJSON file"
11
+ },
12
+ "data": {
13
+ "type": "object",
14
+ "description": "The GeoJSON data",
15
+ "$ref": "https://geojson.org/schema/GeoJSON.json"
16
+ },
17
+ "valid": {
18
+ "type": "boolean",
19
+ "description": "Whether the data are valid or not",
20
+ "readOnly": true
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "type": "object",
3
+ "description": "HillshadeLayer",
4
+ "title": "IHillshadeLayer",
5
+ "required": ["source"],
6
+ "additionalProperties": false,
7
+ "properties": {
8
+ "source": {
9
+ "type": "string",
10
+ "description": "The id of the source"
11
+ },
12
+ "shadowColor": {
13
+ "type": "string",
14
+ "description": "The color of the the shadows",
15
+ "default": "#473B24"
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "type": "object",
3
+ "description": "ImageLayer",
4
+ "title": "IImageLayer",
5
+ "required": ["source"],
6
+ "additionalProperties": false,
7
+ "properties": {
8
+ "source": {
9
+ "type": "string",
10
+ "description": "The id of the source"
11
+ },
12
+ "opacity": {
13
+ "type": "number",
14
+ "description": "The opacity of the source",
15
+ "default": 1,
16
+ "multipleOf": 0.1,
17
+ "minimum": 0,
18
+ "maximum": 1
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "type": "object",
3
+ "description": "ImageSource",
4
+ "title": "IImageSource",
5
+ "required": ["url", "coordinates"],
6
+ "additionalProperties": false,
7
+ "properties": {
8
+ "url": {
9
+ "type": "string",
10
+ "readOnly": true,
11
+ "description": "URL that points to an image"
12
+ },
13
+ "coordinates": {
14
+ "type": "array",
15
+ "readOnly": true,
16
+ "items": {
17
+ "type": "array",
18
+ "items": {
19
+ "type": "number"
20
+ },
21
+ "minItems": 2,
22
+ "maxItems": 2
23
+ },
24
+ "minItems": 4,
25
+ "maxItems": 4,
26
+ "default": [],
27
+ "description": "Corners of image specified in longitude, latitude pairs"
28
+ }
29
+ }
30
+ }