@jupytergis/base 0.1.2 → 0.1.4
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/dialogs/components/symbology/Graduated.d.ts +4 -0
- package/lib/dialogs/components/symbology/Graduated.js +188 -0
- package/lib/dialogs/components/symbology/SimpleSymbol.d.ts +4 -0
- package/lib/dialogs/components/symbology/SimpleSymbol.js +108 -0
- package/lib/dialogs/components/symbology/SingleBandPseudoColor.d.ts +0 -4
- package/lib/dialogs/components/symbology/SingleBandPseudoColor.js +19 -23
- package/lib/dialogs/components/symbology/StopRow.d.ts +4 -3
- package/lib/dialogs/components/symbology/StopRow.js +14 -9
- package/lib/dialogs/components/symbology/VectorRendering.d.ts +4 -0
- package/lib/dialogs/components/symbology/VectorRendering.js +55 -0
- package/lib/dialogs/symbologyDialog.d.ts +4 -0
- package/lib/dialogs/symbologyDialog.js +5 -0
- package/lib/formbuilder/objectform/vectorlayerform.js +1 -3
- package/lib/gdal.d.ts +1 -0
- package/lib/gdal.js +15 -0
- package/lib/gdal3WebAssembly.data +97604 -44
- package/lib/gdal3WebAssembly.wasm +0 -0
- package/lib/mainview/mainView.d.ts +13 -10
- package/lib/mainview/mainView.js +92 -146
- package/lib/panelview/components/layers.js +3 -3
- package/lib/tools.d.ts +9 -0
- package/lib/tools.js +38 -0
- package/package.json +6 -5
- package/style/symbologyDialog.css +11 -3
|
Binary file
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { IJGISLayer, IJGISSource } from '@jupytergis/schema';
|
|
2
2
|
import { User } from '@jupyterlab/services';
|
|
3
|
-
import { FeatureLike } from 'ol/Feature';
|
|
4
3
|
import BaseLayer from 'ol/layer/Base';
|
|
5
|
-
import { Style } from 'ol/style';
|
|
6
4
|
import * as React from 'react';
|
|
7
5
|
import { MainViewModel } from './mainviewmodel';
|
|
8
6
|
interface IProps {
|
|
@@ -49,6 +47,14 @@ export declare class MainView extends React.Component<IProps, IStates> {
|
|
|
49
47
|
*/
|
|
50
48
|
updateLayers(layerIds: string[]): void;
|
|
51
49
|
private _updateLayersImpl;
|
|
50
|
+
/**
|
|
51
|
+
* Build the map layer.
|
|
52
|
+
*
|
|
53
|
+
* @param id - id of the layer.
|
|
54
|
+
* @param layer - the layer object.
|
|
55
|
+
* @returns - the map layer.
|
|
56
|
+
*/
|
|
57
|
+
private _buildMapLayer;
|
|
52
58
|
/**
|
|
53
59
|
* Add a layer to the map.
|
|
54
60
|
*
|
|
@@ -57,19 +63,16 @@ export declare class MainView extends React.Component<IProps, IStates> {
|
|
|
57
63
|
* @param index - expected index of the layer.
|
|
58
64
|
*/
|
|
59
65
|
addLayer(id: string, layer: IJGISLayer, index: number): Promise<void>;
|
|
60
|
-
|
|
66
|
+
vectorLayerStyleRuleBuilder: (layer: IJGISLayer) => {
|
|
67
|
+
style: import("ol/style/flat").FlatStyle | Array<import("ol/style/flat").FlatStyle>;
|
|
68
|
+
filter?: import("ol/expr/expression").EncodedExpression | undefined;
|
|
69
|
+
else?: boolean | undefined;
|
|
70
|
+
}[] | undefined;
|
|
61
71
|
/**
|
|
62
72
|
* Taken from https://openlayers.org/en/latest/examples/webgl-shaded-relief.html
|
|
63
73
|
* @returns
|
|
64
74
|
*/
|
|
65
75
|
private hillshadeMath;
|
|
66
|
-
/**
|
|
67
|
-
* Move a layer in the stack.
|
|
68
|
-
*
|
|
69
|
-
* @param id - id of the layer.
|
|
70
|
-
* @param index - expected index of the layer.
|
|
71
|
-
*/
|
|
72
|
-
moveLayer(id: string, index: number | undefined): void;
|
|
73
76
|
/**
|
|
74
77
|
* Update a layer of the map.
|
|
75
78
|
*
|
package/lib/mainview/mainView.js
CHANGED
|
@@ -10,7 +10,6 @@ import { fromLonLat, toLonLat } from 'ol/proj';
|
|
|
10
10
|
import Feature from 'ol/render/Feature';
|
|
11
11
|
import { GeoTIFF as GeoTIFFSource, ImageTile as ImageTileSource, Vector as VectorSource, VectorTile as VectorTileSource, XYZ as XYZSource } from 'ol/source';
|
|
12
12
|
import Static from 'ol/source/ImageStatic';
|
|
13
|
-
import { Circle, Fill, Stroke, Style } from 'ol/style';
|
|
14
13
|
//@ts-expect-error no types for ol-pmtiles
|
|
15
14
|
import { PMTilesRasterSource, PMTilesVectorSource } from 'ol-pmtiles';
|
|
16
15
|
import * as React from 'react';
|
|
@@ -20,73 +19,52 @@ import { Spinner } from './spinner';
|
|
|
20
19
|
export class MainView extends React.Component {
|
|
21
20
|
constructor(props) {
|
|
22
21
|
super(props);
|
|
23
|
-
this.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const operators = {
|
|
37
|
-
'>': (a, b) => a > b,
|
|
38
|
-
'<': (a, b) => a < b,
|
|
39
|
-
'>=': (a, b) => a >= b,
|
|
40
|
-
'<=': (a, b) => a <= b,
|
|
41
|
-
'==': (a, b) => a === b,
|
|
42
|
-
'!=': (a, b) => a !== b
|
|
22
|
+
this.vectorLayerStyleRuleBuilder = (layer) => {
|
|
23
|
+
const layerParams = layer.parameters;
|
|
24
|
+
if (!layerParams) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const defaultStyle = {
|
|
28
|
+
'fill-color': 'rgba(255,255,255,0.4)',
|
|
29
|
+
'stroke-color': '#3399CC',
|
|
30
|
+
'stroke-width': 1.25,
|
|
31
|
+
'circle-radius': 5,
|
|
32
|
+
'circle-fill-color': 'rgba(255,255,255,0.4)',
|
|
33
|
+
'circle-stroke-width': 1.25,
|
|
34
|
+
'circle-stroke-color': '#3399CC'
|
|
43
35
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const style = new Style({
|
|
57
|
-
fill,
|
|
58
|
-
stroke,
|
|
59
|
-
image: new Circle({
|
|
60
|
-
radius: 5,
|
|
61
|
-
fill,
|
|
62
|
-
stroke
|
|
63
|
-
})
|
|
64
|
-
});
|
|
65
|
-
if (layer.filters && ((_a = layer.filters) === null || _a === void 0 ? void 0 : _a.appliedFilters.length) !== 0) {
|
|
66
|
-
const props = currentFeature.getProperties();
|
|
67
|
-
let shouldDisplayFeature = true;
|
|
68
|
-
switch (layer.filters.logicalOp) {
|
|
69
|
-
case 'any': {
|
|
70
|
-
// Display the feature if any filter conditions apply
|
|
71
|
-
shouldDisplayFeature = layer.filters.appliedFilters.some(({ feature, operator, value }) => operators[operator](props[feature], value));
|
|
72
|
-
break;
|
|
73
|
-
}
|
|
74
|
-
case 'all': {
|
|
75
|
-
// Display the feature only if all the filter conditions apply
|
|
76
|
-
shouldDisplayFeature = layer.filters.appliedFilters.every(({ feature, operator, value }) => operators[operator](props[feature], value));
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
if (shouldDisplayFeature) {
|
|
81
|
-
return style;
|
|
36
|
+
const defaultRules = {
|
|
37
|
+
style: defaultStyle
|
|
38
|
+
};
|
|
39
|
+
const layerStyle = Object.assign({}, defaultRules);
|
|
40
|
+
if (layer.filters && layer.filters.appliedFilters.length !== 0) {
|
|
41
|
+
const filterExpr = [];
|
|
42
|
+
// 'Any' and 'All' operators require more than one argument
|
|
43
|
+
// So if there's only one filter, skip that part to avoid error
|
|
44
|
+
if (layer.filters.appliedFilters.length === 1) {
|
|
45
|
+
layer.filters.appliedFilters.forEach(filter => {
|
|
46
|
+
filterExpr.push(filter.operator, ['get', filter.feature], filter.value);
|
|
47
|
+
});
|
|
82
48
|
}
|
|
83
49
|
else {
|
|
84
|
-
|
|
50
|
+
filterExpr.push(layer.filters.logicalOp);
|
|
51
|
+
// Arguments for "Any" and 'All' need to be wrapped in brackets
|
|
52
|
+
layer.filters.appliedFilters.forEach(filter => {
|
|
53
|
+
filterExpr.push([
|
|
54
|
+
filter.operator,
|
|
55
|
+
['get', filter.feature],
|
|
56
|
+
filter.value
|
|
57
|
+
]);
|
|
58
|
+
});
|
|
85
59
|
}
|
|
60
|
+
layerStyle.filter = filterExpr;
|
|
86
61
|
}
|
|
87
|
-
|
|
88
|
-
return
|
|
62
|
+
if (!layerParams.color) {
|
|
63
|
+
return [layerStyle];
|
|
89
64
|
}
|
|
65
|
+
const newStyle = Object.assign(Object.assign({}, defaultStyle), layerParams.color);
|
|
66
|
+
layerStyle.style = newStyle;
|
|
67
|
+
return [layerStyle];
|
|
90
68
|
};
|
|
91
69
|
/**
|
|
92
70
|
* Taken from https://openlayers.org/en/latest/examples/webgl-shaded-relief.html
|
|
@@ -237,16 +215,14 @@ export class MainView extends React.Component {
|
|
|
237
215
|
projection: projection.getCode(),
|
|
238
216
|
zoom
|
|
239
217
|
};
|
|
240
|
-
|
|
241
|
-
if (currentOptions.extent) {
|
|
242
|
-
updatedOptions.extent = view.calculateExtent();
|
|
243
|
-
}
|
|
218
|
+
updatedOptions.extent = view.calculateExtent();
|
|
244
219
|
this._model.setOptions(Object.assign(Object.assign({}, currentOptions), updatedOptions));
|
|
245
220
|
});
|
|
246
221
|
if (JupyterGISModel.getOrderedLayerIds(this._model).length !== 0) {
|
|
247
222
|
await this._updateLayersImpl(JupyterGISModel.getOrderedLayerIds(this._model));
|
|
248
223
|
const options = this._model.getOptions();
|
|
249
224
|
this.updateOptions(options);
|
|
225
|
+
this._initializedPosition = true;
|
|
250
226
|
}
|
|
251
227
|
this.setState(old => (Object.assign(Object.assign({}, old), { loading: false })));
|
|
252
228
|
}
|
|
@@ -447,59 +423,30 @@ export class MainView extends React.Component {
|
|
|
447
423
|
this._updateLayersImpl(layerIds);
|
|
448
424
|
}
|
|
449
425
|
async _updateLayersImpl(layerIds) {
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
// bottom.
|
|
453
|
-
// This is to ensure that the beforeId (layer on top of the one we add/move)
|
|
454
|
-
// is already added/moved in the map.
|
|
455
|
-
const reversedLayerIds = layerIds.slice().reverse();
|
|
456
|
-
for (const layerId of reversedLayerIds) {
|
|
426
|
+
const mapLayers = [];
|
|
427
|
+
for (const layerId of layerIds) {
|
|
457
428
|
const layer = this._model.sharedModel.getLayer(layerId);
|
|
458
429
|
if (!layer) {
|
|
459
430
|
console.log(`Layer id ${layerId} does not exist`);
|
|
460
|
-
|
|
431
|
+
continue;
|
|
461
432
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
const nextLayer = layerIds[layerIds.indexOf(layerId) + 1];
|
|
466
|
-
if (nextLayer !== undefined) {
|
|
467
|
-
indexInMap = currentLayerIds.indexOf(nextLayer);
|
|
468
|
-
if (indexInMap === -1) {
|
|
469
|
-
indexInMap = currentLayerIds.length;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
if (this.getLayer(layerId)) {
|
|
473
|
-
this.moveLayer(layerId, indexInMap);
|
|
474
|
-
}
|
|
475
|
-
else {
|
|
476
|
-
await this.addLayer(layerId, layer, indexInMap);
|
|
477
|
-
}
|
|
478
|
-
// Remove the element of the previous list as treated.
|
|
479
|
-
const index = previousLayerIds.indexOf(layerId);
|
|
480
|
-
if (index > -1) {
|
|
481
|
-
previousLayerIds.splice(index, 1);
|
|
433
|
+
const newMapLayer = await this._buildMapLayer(layerId, layer);
|
|
434
|
+
if (newMapLayer !== undefined) {
|
|
435
|
+
mapLayers.push(newMapLayer);
|
|
482
436
|
}
|
|
483
437
|
}
|
|
484
|
-
|
|
485
|
-
previousLayerIds.forEach(layerId => {
|
|
486
|
-
this._Map.removeLayer(layerId);
|
|
487
|
-
});
|
|
438
|
+
this._Map.setLayers(mapLayers);
|
|
488
439
|
this._ready = true;
|
|
489
440
|
}
|
|
490
441
|
/**
|
|
491
|
-
*
|
|
442
|
+
* Build the map layer.
|
|
492
443
|
*
|
|
493
444
|
* @param id - id of the layer.
|
|
494
445
|
* @param layer - the layer object.
|
|
495
|
-
* @
|
|
446
|
+
* @returns - the map layer.
|
|
496
447
|
*/
|
|
497
|
-
async
|
|
448
|
+
async _buildMapLayer(id, layer) {
|
|
498
449
|
var _a;
|
|
499
|
-
if (this.getLayer(id)) {
|
|
500
|
-
// Layer already exists
|
|
501
|
-
return;
|
|
502
|
-
}
|
|
503
450
|
const sourceId = (_a = layer.parameters) === null || _a === void 0 ? void 0 : _a.source;
|
|
504
451
|
const source = this._model.sharedModel.getSource(sourceId);
|
|
505
452
|
if (!source) {
|
|
@@ -508,14 +455,14 @@ export class MainView extends React.Component {
|
|
|
508
455
|
if (!this._sources[sourceId]) {
|
|
509
456
|
await this.addSource(sourceId, source);
|
|
510
457
|
}
|
|
511
|
-
let
|
|
458
|
+
let newMapLayer;
|
|
512
459
|
let layerParameters;
|
|
513
460
|
// TODO: OpenLayers provides a bunch of sources for specific tile
|
|
514
461
|
// providers, so maybe set up some way to use those
|
|
515
462
|
switch (layer.type) {
|
|
516
463
|
case 'RasterLayer': {
|
|
517
464
|
layerParameters = layer.parameters;
|
|
518
|
-
|
|
465
|
+
newMapLayer = new TileLayer({
|
|
519
466
|
opacity: layerParameters.opacity,
|
|
520
467
|
visible: layer.visible,
|
|
521
468
|
source: this._sources[layerParameters.source]
|
|
@@ -524,26 +471,29 @@ export class MainView extends React.Component {
|
|
|
524
471
|
}
|
|
525
472
|
case 'VectorLayer': {
|
|
526
473
|
layerParameters = layer.parameters;
|
|
527
|
-
|
|
474
|
+
newMapLayer = new VectorLayer({
|
|
528
475
|
opacity: layerParameters.opacity,
|
|
529
476
|
visible: layer.visible,
|
|
530
477
|
source: this._sources[layerParameters.source],
|
|
531
|
-
style:
|
|
478
|
+
style: this.vectorLayerStyleRuleBuilder(layer)
|
|
532
479
|
});
|
|
533
480
|
break;
|
|
534
481
|
}
|
|
535
482
|
case 'VectorTileLayer': {
|
|
536
483
|
layerParameters = layer.parameters;
|
|
537
|
-
|
|
484
|
+
if (!layerParameters.color) {
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
newMapLayer = new VectorTileLayer({
|
|
538
488
|
opacity: layerParameters.opacity,
|
|
539
|
-
source: this._sources[layerParameters.source]
|
|
540
|
-
style: currentFeature => this.vectorLayerStyleFunc(currentFeature, layer)
|
|
489
|
+
source: this._sources[layerParameters.source]
|
|
541
490
|
});
|
|
491
|
+
this.updateLayer(id, layer, newMapLayer);
|
|
542
492
|
break;
|
|
543
493
|
}
|
|
544
494
|
case 'HillshadeLayer': {
|
|
545
495
|
layerParameters = layer.parameters;
|
|
546
|
-
|
|
496
|
+
newMapLayer = new WebGlTileLayer({
|
|
547
497
|
opacity: 0.3,
|
|
548
498
|
source: this._sources[layerParameters.source],
|
|
549
499
|
style: {
|
|
@@ -554,7 +504,7 @@ export class MainView extends React.Component {
|
|
|
554
504
|
}
|
|
555
505
|
case 'ImageLayer': {
|
|
556
506
|
layerParameters = layer.parameters;
|
|
557
|
-
|
|
507
|
+
newMapLayer = new ImageLayer({
|
|
558
508
|
opacity: layerParameters.opacity,
|
|
559
509
|
source: this._sources[layerParameters.source]
|
|
560
510
|
});
|
|
@@ -570,43 +520,32 @@ export class MainView extends React.Component {
|
|
|
570
520
|
if (layerParameters.color) {
|
|
571
521
|
layerOptions['style'] = { color: layerParameters.color };
|
|
572
522
|
}
|
|
573
|
-
|
|
523
|
+
newMapLayer = new WebGlTileLayer(layerOptions);
|
|
574
524
|
break;
|
|
575
525
|
}
|
|
576
526
|
}
|
|
577
527
|
// OpenLayers doesn't have name/id field so add it
|
|
578
|
-
|
|
528
|
+
newMapLayer.set('id', id);
|
|
579
529
|
// we need to keep track of which source has which layers
|
|
580
530
|
this._sourceToLayerMap.set(layerParameters.source, id);
|
|
581
|
-
|
|
531
|
+
return newMapLayer;
|
|
582
532
|
}
|
|
583
533
|
/**
|
|
584
|
-
*
|
|
534
|
+
* Add a layer to the map.
|
|
585
535
|
*
|
|
586
536
|
* @param id - id of the layer.
|
|
537
|
+
* @param layer - the layer object.
|
|
587
538
|
* @param index - expected index of the layer.
|
|
588
539
|
*/
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
let beforeId = undefined;
|
|
593
|
-
if (!(index === undefined) && index < currentLayerIds.length) {
|
|
594
|
-
beforeId = currentLayerIds[index];
|
|
595
|
-
}
|
|
596
|
-
const layerArray = this._Map.getLayers().getArray();
|
|
597
|
-
const movingLayer = this.getLayer(id);
|
|
598
|
-
if (!movingLayer || !index || !beforeId) {
|
|
540
|
+
async addLayer(id, layer, index) {
|
|
541
|
+
if (this.getLayer(id)) {
|
|
542
|
+
// Layer already exists
|
|
599
543
|
return;
|
|
600
544
|
}
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
if (!beforeLayer) {
|
|
605
|
-
return;
|
|
545
|
+
const newMapLayer = await this._buildMapLayer(id, layer);
|
|
546
|
+
if (newMapLayer !== undefined) {
|
|
547
|
+
this._Map.getLayers().insertAt(index, newMapLayer);
|
|
606
548
|
}
|
|
607
|
-
const indexOfBeforeLayer = layerArray.indexOf(beforeLayer);
|
|
608
|
-
layerArray.splice(indexOfBeforeLayer, 0, movingLayer);
|
|
609
|
-
this._Map.setLayers(layerArray);
|
|
610
549
|
}
|
|
611
550
|
/**
|
|
612
551
|
* Update a layer of the map.
|
|
@@ -633,13 +572,13 @@ export class MainView extends React.Component {
|
|
|
633
572
|
case 'VectorLayer': {
|
|
634
573
|
const layerParams = layer.parameters;
|
|
635
574
|
mapLayer.setOpacity(layerParams.opacity || 1);
|
|
636
|
-
mapLayer.setStyle(
|
|
575
|
+
mapLayer.setStyle(this.vectorLayerStyleRuleBuilder(layer));
|
|
637
576
|
break;
|
|
638
577
|
}
|
|
639
578
|
case 'VectorTileLayer': {
|
|
640
579
|
const layerParams = layer.parameters;
|
|
641
580
|
mapLayer.setOpacity(layerParams.opacity || 1);
|
|
642
|
-
mapLayer.setStyle(
|
|
581
|
+
mapLayer.setStyle(this.vectorLayerStyleRuleBuilder(layer));
|
|
643
582
|
break;
|
|
644
583
|
}
|
|
645
584
|
case 'HillshadeLayer': {
|
|
@@ -680,14 +619,19 @@ export class MainView extends React.Component {
|
|
|
680
619
|
}
|
|
681
620
|
updateOptions(options) {
|
|
682
621
|
const view = this._Map.getView();
|
|
683
|
-
//
|
|
684
|
-
if (options.extent) {
|
|
622
|
+
// Use the extent only if explicitly requested (QGIS files).
|
|
623
|
+
if (options.extent && options.useExtent) {
|
|
685
624
|
view.fit(options.extent);
|
|
686
625
|
}
|
|
687
626
|
else {
|
|
688
627
|
const centerCoord = fromLonLat([options.longitude || 0, options.latitude || 0], this._Map.getView().getProjection());
|
|
689
628
|
this._Map.getView().setZoom(options.zoom || 0);
|
|
690
629
|
this._Map.getView().setCenter(centerCoord);
|
|
630
|
+
// Save the extent if it does not exists, to allow proper export to qgis.
|
|
631
|
+
if (options.extent === undefined) {
|
|
632
|
+
options.extent = view.calculateExtent();
|
|
633
|
+
this._model.setOptions(options);
|
|
634
|
+
}
|
|
691
635
|
}
|
|
692
636
|
view.setRotation(options.bearing || 0);
|
|
693
637
|
}
|
|
@@ -727,12 +671,14 @@ export class MainView extends React.Component {
|
|
|
727
671
|
}
|
|
728
672
|
else {
|
|
729
673
|
const mapLayer = this.getLayer(change.id);
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
674
|
+
const layerTree = JupyterGISModel.getOrderedLayerIds(this._model);
|
|
675
|
+
if (mapLayer) {
|
|
676
|
+
if (layerTree.includes(change.id)) {
|
|
677
|
+
this.updateLayer(change.id, layer, mapLayer);
|
|
678
|
+
}
|
|
679
|
+
else {
|
|
680
|
+
this.updateLayers(layerTree);
|
|
681
|
+
}
|
|
736
682
|
}
|
|
737
683
|
}
|
|
738
684
|
});
|
|
@@ -132,8 +132,8 @@ function LayerGroupComponent(props) {
|
|
|
132
132
|
setId(DOMUtils.createDomID());
|
|
133
133
|
const getExpandedState = async () => {
|
|
134
134
|
var _a;
|
|
135
|
-
const groupState = await state.fetch(group.name);
|
|
136
|
-
setOpen(
|
|
135
|
+
const groupState = await state.fetch(`jupytergis:${group.name}`);
|
|
136
|
+
setOpen((_a = groupState.expanded) !== null && _a !== void 0 ? _a : false);
|
|
137
137
|
};
|
|
138
138
|
getExpandedState();
|
|
139
139
|
}, []);
|
|
@@ -156,7 +156,7 @@ function LayerGroupComponent(props) {
|
|
|
156
156
|
onClick({ type: 'group', item: name, nodeId: childId, event });
|
|
157
157
|
};
|
|
158
158
|
const handleExpand = async () => {
|
|
159
|
-
state.save(group.name
|
|
159
|
+
state.save(`jupytergis:${group.name}`, { expanded: !open });
|
|
160
160
|
setOpen(!open);
|
|
161
161
|
};
|
|
162
162
|
return (React.createElement("div", { className: `${LAYER_ITEM_CLASS} ${LAYER_GROUP_CLASS}`, draggable: true, onDragStart: Private.onDragStart, onDragEnd: Private.onDragEnd, "data-id": name },
|
package/lib/tools.d.ts
CHANGED
|
@@ -23,3 +23,12 @@ export declare function deepCopy<T = IDict<any>>(value: T): T;
|
|
|
23
23
|
export declare function createDefaultLayerRegistry(layerBrowserRegistry: IJGISLayerBrowserRegistry): void;
|
|
24
24
|
export declare function getLayerTileInfo(tileUrl: string, mapOptions: Pick<IJGISOptions, 'latitude' | 'longitude' | 'extent' | 'zoom'>, urlParameters?: IDict<string>): Promise<VectorTile>;
|
|
25
25
|
export declare function getSourceLayerNames(tileUrl: string, urlParameters?: IDict<string>): Promise<string[]>;
|
|
26
|
+
export interface IParsedStyle {
|
|
27
|
+
fillColor: string;
|
|
28
|
+
strokeColor: string;
|
|
29
|
+
strokeWidth: number;
|
|
30
|
+
joinStyle: string;
|
|
31
|
+
capStyle: string;
|
|
32
|
+
radius?: number;
|
|
33
|
+
}
|
|
34
|
+
export declare function parseColor(type: string, style: any): IParsedStyle | undefined;
|
package/lib/tools.js
CHANGED
|
@@ -170,6 +170,10 @@ function getTileCoordinates(latDeg, lonDeg, zoom) {
|
|
|
170
170
|
const n = 1 << zoom;
|
|
171
171
|
const xTile = Math.floor(((lonDeg + 180.0) / 360.0) * n);
|
|
172
172
|
const yTile = Math.floor((n * (1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI)) / 2);
|
|
173
|
+
// Check if either xTile or yTile is NaN
|
|
174
|
+
if (isNaN(xTile) || isNaN(yTile)) {
|
|
175
|
+
return { xTile: 0, yTile: 0 };
|
|
176
|
+
}
|
|
173
177
|
return { xTile, yTile };
|
|
174
178
|
}
|
|
175
179
|
export async function getLayerTileInfo(tileUrl, mapOptions, urlParameters) {
|
|
@@ -213,3 +217,37 @@ export async function getSourceLayerNames(tileUrl, urlParameters) {
|
|
|
213
217
|
const layerNames = Object.keys(tile.layers);
|
|
214
218
|
return layerNames;
|
|
215
219
|
}
|
|
220
|
+
export function parseColor(type, style) {
|
|
221
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
222
|
+
if (!type || !style) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
const type2 = type === 'circle' ? 'circle' : 'default';
|
|
226
|
+
const shapeStyles = {
|
|
227
|
+
circle: {
|
|
228
|
+
radius: (_a = style['circle-radius']) !== null && _a !== void 0 ? _a : 5,
|
|
229
|
+
fillColor: (_b = style['circle-fill-color']) !== null && _b !== void 0 ? _b : '#3399CC',
|
|
230
|
+
strokeColor: (_c = style['circle-stroke-color']) !== null && _c !== void 0 ? _c : '#3399CC',
|
|
231
|
+
strokeWidth: (_d = style['circle-stroke-width']) !== null && _d !== void 0 ? _d : 1.25,
|
|
232
|
+
joinStyle: (_e = style['circle-stroke-line-join']) !== null && _e !== void 0 ? _e : 'round',
|
|
233
|
+
capStyle: (_f = style['circle-stroke-line-cap']) !== null && _f !== void 0 ? _f : 'round'
|
|
234
|
+
},
|
|
235
|
+
default: {
|
|
236
|
+
fillColor: (_g = style['fill-color']) !== null && _g !== void 0 ? _g : '[255, 255, 255, 0.4]',
|
|
237
|
+
strokeColor: (_h = style['stroke-color']) !== null && _h !== void 0 ? _h : '#3399CC',
|
|
238
|
+
strokeWidth: (_j = style['stroke-width']) !== null && _j !== void 0 ? _j : 1.25,
|
|
239
|
+
capStyle: (_k = style['stroke-line-cap']) !== null && _k !== void 0 ? _k : 'round',
|
|
240
|
+
joinStyle: (_l = style['stroke-line-join']) !== null && _l !== void 0 ? _l : 'round'
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
const parsedStyle = shapeStyles[type2];
|
|
244
|
+
Object.assign(parsedStyle, {
|
|
245
|
+
radius: parsedStyle.radius,
|
|
246
|
+
fillColor: parsedStyle.fillColor,
|
|
247
|
+
strokeColor: parsedStyle.strokeColor,
|
|
248
|
+
strokeWidth: parsedStyle.strokeWidth,
|
|
249
|
+
joinStyle: parsedStyle.joinStyle,
|
|
250
|
+
capStyle: parsedStyle.capStyle
|
|
251
|
+
});
|
|
252
|
+
return parsedStyle;
|
|
253
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jupytergis/base",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "A JupyterLab extension for 3D modelling.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"name": "JupyterGIS contributors"
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
|
-
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
|
|
19
|
+
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf,data,wasm}",
|
|
20
20
|
"style/**/*.{css,js,eot,gif,html,jpg,json,png,svg,woff2,ttf}"
|
|
21
21
|
],
|
|
22
22
|
"main": "lib/index.js",
|
|
@@ -27,10 +27,11 @@
|
|
|
27
27
|
"url": "https://github.com/geojupyter/jupytergis.git"
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
|
-
"build": "jlpm run build:gallery && tsc -b",
|
|
30
|
+
"build": "jlpm run build:gallery && tsc -b && jlpm run cp:gdal",
|
|
31
31
|
"build:gallery": "python rasterlayer_gallery_generator.py",
|
|
32
|
+
"cp:gdal": "cp ../../node_modules/gdal3.js/dist/package/gdal3WebAssembly.data lib && cp ../../node_modules/gdal3.js/dist/package/gdal3WebAssembly.wasm lib",
|
|
32
33
|
"build:prod": "jlpm run clean && jlpm run build",
|
|
33
|
-
"build:dev": "tsc -b",
|
|
34
|
+
"build:dev": "tsc -b && jlpm run cp:gdal",
|
|
34
35
|
"clean": "rimraf tsconfig.tsbuildinfo",
|
|
35
36
|
"clean:lib": "rimraf lib tsconfig.tsbuildinfo",
|
|
36
37
|
"clean:all": "jlpm run clean:lib",
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
"@deathbeds/jupyterlab-rjsf": "^1.1.0",
|
|
41
42
|
"@jupyter/docprovider": "^2.0.0",
|
|
42
43
|
"@jupyter/ydoc": "^1.0.0",
|
|
43
|
-
"@jupytergis/schema": "^0.1.
|
|
44
|
+
"@jupytergis/schema": "^0.1.4",
|
|
44
45
|
"@jupyterlab/application": "^4.0.0",
|
|
45
46
|
"@jupyterlab/apputils": "^4.0.0",
|
|
46
47
|
"@jupyterlab/completer": "^4.2.4",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
flex: 0 1 20%;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
.jp-gis-symbology-row > .jp-select-wrapper
|
|
24
|
+
.jp-gis-symbology-row > .jp-select-wrapper,
|
|
25
|
+
.jp-gis-symbology-row > .jp-mod-styled {
|
|
25
26
|
flex: 1 0 50%;
|
|
26
27
|
max-width: 50%;
|
|
27
28
|
}
|
|
@@ -35,6 +36,13 @@
|
|
|
35
36
|
.jp-gis-layer-symbology-container {
|
|
36
37
|
display: flex;
|
|
37
38
|
flex-direction: column;
|
|
39
|
+
gap: 13px;
|
|
40
|
+
border-top: 1px solid var(--jp-border-color2);
|
|
41
|
+
padding-top: 8px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.jp-gis-layer-symbology-container .jp-select-wrapper {
|
|
45
|
+
margin-bottom: unset;
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
.jp-gis-band-container .jp-gis-symbology-row:last-child {
|
|
@@ -66,12 +74,12 @@
|
|
|
66
74
|
height: 32px;
|
|
67
75
|
}
|
|
68
76
|
|
|
69
|
-
.jp-gis-color-row
|
|
77
|
+
.jp-gis-color-row-value-input {
|
|
70
78
|
flex: 0 1 18%;
|
|
71
79
|
min-width: 0px;
|
|
72
80
|
}
|
|
73
81
|
|
|
74
|
-
.jp-gis-color-row
|
|
82
|
+
.jp-gis-color-row-output-input {
|
|
75
83
|
flex-grow: 1;
|
|
76
84
|
}
|
|
77
85
|
|