@jupytergis/base 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commands/BaseCommandIDs.d.ts +8 -0
- package/lib/commands/BaseCommandIDs.js +11 -0
- package/lib/commands/index.js +167 -5
- package/lib/dialogs/symbology/hooks/useGetSymbology.d.ts +17 -0
- package/lib/dialogs/symbology/hooks/useGetSymbology.js +65 -0
- package/lib/dialogs/symbology/symbologyUtils.d.ts +1 -1
- package/lib/dialogs/symbology/symbologyUtils.js +4 -1
- package/lib/dialogs/symbology/vector_layer/types/Categorized.js +7 -1
- package/lib/dialogs/symbology/vector_layer/types/Graduated.js +7 -1
- package/lib/dialogs/symbology/vector_layer/types/Heatmap.js +13 -2
- package/lib/gdal.js +0 -2
- package/lib/mainview/mainView.js +6 -8
- package/lib/panelview/components/identify-panel/IdentifyPanel.js +12 -4
- package/lib/panelview/components/layers.js +19 -4
- package/lib/panelview/components/legendItem.d.ts +6 -0
- package/lib/panelview/components/legendItem.js +165 -0
- package/lib/panelview/leftpanel.js +35 -24
- package/lib/panelview/rightpanel.js +55 -27
- package/lib/tools.d.ts +5 -1
- package/lib/tools.js +4 -0
- package/package.json +3 -3
- package/style/base.css +20 -0
- package/style/leftPanel.css +1 -1
|
@@ -31,3 +31,11 @@ export declare const selectCompleter = "jupytergis:selectConsoleCompleter";
|
|
|
31
31
|
export declare const addAnnotation = "jupytergis:addAnnotation";
|
|
32
32
|
export declare const zoomToLayer = "jupytergis:zoomToLayer";
|
|
33
33
|
export declare const downloadGeoJSON = "jupytergis:downloadGeoJSON";
|
|
34
|
+
export declare const toggleLeftPanel = "jupytergis:toggleLeftPanel";
|
|
35
|
+
export declare const toggleRightPanel = "jupytergis:toggleRightPanel";
|
|
36
|
+
export declare const showLayersTab = "jupytergis:showLayersTab";
|
|
37
|
+
export declare const showStacBrowserTab = "jupytergis:showStacBrowserTab";
|
|
38
|
+
export declare const showFiltersTab = "jupytergis:showFiltersTab";
|
|
39
|
+
export declare const showObjectPropertiesTab = "jupytergis:showObjectPropertiesTab";
|
|
40
|
+
export declare const showAnnotationsTab = "jupytergis:showAnnotationsTab";
|
|
41
|
+
export declare const showIdentifyPanelTab = "jupytergis:showIdentifyPanelTab";
|
|
@@ -42,3 +42,14 @@ export const selectCompleter = 'jupytergis:selectConsoleCompleter';
|
|
|
42
42
|
export const addAnnotation = 'jupytergis:addAnnotation';
|
|
43
43
|
export const zoomToLayer = 'jupytergis:zoomToLayer';
|
|
44
44
|
export const downloadGeoJSON = 'jupytergis:downloadGeoJSON';
|
|
45
|
+
// Panel toggles
|
|
46
|
+
export const toggleLeftPanel = 'jupytergis:toggleLeftPanel';
|
|
47
|
+
export const toggleRightPanel = 'jupytergis:toggleRightPanel';
|
|
48
|
+
// Left panel tabs
|
|
49
|
+
export const showLayersTab = 'jupytergis:showLayersTab';
|
|
50
|
+
export const showStacBrowserTab = 'jupytergis:showStacBrowserTab';
|
|
51
|
+
export const showFiltersTab = 'jupytergis:showFiltersTab';
|
|
52
|
+
// Right panel tabs
|
|
53
|
+
export const showObjectPropertiesTab = 'jupytergis:showObjectPropertiesTab';
|
|
54
|
+
export const showAnnotationsTab = 'jupytergis:showAnnotationsTab';
|
|
55
|
+
export const showIdentifyPanelTab = 'jupytergis:showIdentifyPanelTab';
|
package/lib/commands/index.js
CHANGED
|
@@ -87,14 +87,17 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
87
87
|
'WebGlLayer',
|
|
88
88
|
'VectorTileLayer',
|
|
89
89
|
].includes(selectedLayer.type);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
current.model.isIdentifying = false;
|
|
90
|
+
if (current.model.currentMode === 'identifying' && !canIdentify) {
|
|
91
|
+
current.model.currentMode = 'panning';
|
|
93
92
|
current.node.classList.remove('jGIS-identify-tool');
|
|
94
93
|
return false;
|
|
95
94
|
}
|
|
96
|
-
return
|
|
95
|
+
return current.model.currentMode === 'identifying';
|
|
97
96
|
}, isEnabled: () => {
|
|
97
|
+
var _a;
|
|
98
|
+
if ((_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.model.jgisSettings.identifyDisabled) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
98
101
|
const selectedLayer = getSingleSelectedLayer(tracker);
|
|
99
102
|
if (!selectedLayer) {
|
|
100
103
|
return false;
|
|
@@ -114,7 +117,7 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
114
117
|
if (luminoEvent) {
|
|
115
118
|
const keysPressed = luminoEvent.keys;
|
|
116
119
|
if (keysPressed === null || keysPressed === void 0 ? void 0 : keysPressed.includes('Escape')) {
|
|
117
|
-
current.model.
|
|
120
|
+
current.model.currentMode = 'panning';
|
|
118
121
|
current.node.classList.remove('jGIS-identify-tool');
|
|
119
122
|
commands.notifyCommandChanged(CommandIDs.identify);
|
|
120
123
|
return;
|
|
@@ -652,6 +655,165 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
652
655
|
},
|
|
653
656
|
icon: targetWithCenterIcon,
|
|
654
657
|
});
|
|
658
|
+
// Panel visibility commands
|
|
659
|
+
commands.addCommand(CommandIDs.toggleLeftPanel, {
|
|
660
|
+
label: trans.__('Toggle Left Panel'),
|
|
661
|
+
isEnabled: () => Boolean(tracker.currentWidget),
|
|
662
|
+
isToggled: () => {
|
|
663
|
+
const current = tracker.currentWidget;
|
|
664
|
+
return current ? !current.model.jgisSettings.leftPanelDisabled : false;
|
|
665
|
+
},
|
|
666
|
+
execute: async () => {
|
|
667
|
+
var _a, _b, _c;
|
|
668
|
+
const current = tracker.currentWidget;
|
|
669
|
+
if (!current) {
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
try {
|
|
673
|
+
const settings = await current.model.getSettings();
|
|
674
|
+
const currentValue = (_c = (_b = (_a = settings === null || settings === void 0 ? void 0 : settings.composite) === null || _a === void 0 ? void 0 : _a.leftPanelDisabled) !== null && _b !== void 0 ? _b : current.model.jgisSettings.leftPanelDisabled) !== null && _c !== void 0 ? _c : false;
|
|
675
|
+
await (settings === null || settings === void 0 ? void 0 : settings.set('leftPanelDisabled', !currentValue));
|
|
676
|
+
commands.notifyCommandChanged(CommandIDs.toggleLeftPanel);
|
|
677
|
+
}
|
|
678
|
+
catch (err) {
|
|
679
|
+
console.error('Failed to toggle Left Panel:', err);
|
|
680
|
+
}
|
|
681
|
+
},
|
|
682
|
+
});
|
|
683
|
+
commands.addCommand(CommandIDs.toggleRightPanel, {
|
|
684
|
+
label: trans.__('Toggle Right Panel'),
|
|
685
|
+
isEnabled: () => Boolean(tracker.currentWidget),
|
|
686
|
+
isToggled: () => {
|
|
687
|
+
const current = tracker.currentWidget;
|
|
688
|
+
return current ? !current.model.jgisSettings.rightPanelDisabled : false;
|
|
689
|
+
},
|
|
690
|
+
execute: async () => {
|
|
691
|
+
var _a, _b, _c;
|
|
692
|
+
const current = tracker.currentWidget;
|
|
693
|
+
if (!current) {
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
try {
|
|
697
|
+
const settings = await current.model.getSettings();
|
|
698
|
+
const currentValue = (_c = (_b = (_a = settings === null || settings === void 0 ? void 0 : settings.composite) === null || _a === void 0 ? void 0 : _a.rightPanelDisabled) !== null && _b !== void 0 ? _b : current.model.jgisSettings.rightPanelDisabled) !== null && _c !== void 0 ? _c : false;
|
|
699
|
+
await (settings === null || settings === void 0 ? void 0 : settings.set('rightPanelDisabled', !currentValue));
|
|
700
|
+
commands.notifyCommandChanged(CommandIDs.toggleRightPanel);
|
|
701
|
+
}
|
|
702
|
+
catch (err) {
|
|
703
|
+
console.error('Failed to toggle Right Panel:', err);
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
});
|
|
707
|
+
// Left panel tabs
|
|
708
|
+
commands.addCommand(CommandIDs.showLayersTab, {
|
|
709
|
+
label: trans.__('Show Layers Tab'),
|
|
710
|
+
isEnabled: () => Boolean(tracker.currentWidget),
|
|
711
|
+
isToggled: () => tracker.currentWidget
|
|
712
|
+
? !tracker.currentWidget.model.jgisSettings.layersDisabled
|
|
713
|
+
: false,
|
|
714
|
+
execute: async () => {
|
|
715
|
+
var _a, _b, _c;
|
|
716
|
+
const current = tracker.currentWidget;
|
|
717
|
+
if (!current) {
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
const settings = await current.model.getSettings();
|
|
721
|
+
const currentValue = (_c = (_b = (_a = settings === null || settings === void 0 ? void 0 : settings.composite) === null || _a === void 0 ? void 0 : _a.layersDisabled) !== null && _b !== void 0 ? _b : current.model.jgisSettings.layersDisabled) !== null && _c !== void 0 ? _c : false;
|
|
722
|
+
await (settings === null || settings === void 0 ? void 0 : settings.set('layersDisabled', !currentValue));
|
|
723
|
+
commands.notifyCommandChanged(CommandIDs.showLayersTab);
|
|
724
|
+
},
|
|
725
|
+
});
|
|
726
|
+
commands.addCommand(CommandIDs.showStacBrowserTab, {
|
|
727
|
+
label: trans.__('Show STAC Browser Tab'),
|
|
728
|
+
isEnabled: () => Boolean(tracker.currentWidget),
|
|
729
|
+
isToggled: () => tracker.currentWidget
|
|
730
|
+
? !tracker.currentWidget.model.jgisSettings.stacBrowserDisabled
|
|
731
|
+
: false,
|
|
732
|
+
execute: async () => {
|
|
733
|
+
var _a, _b, _c;
|
|
734
|
+
const current = tracker.currentWidget;
|
|
735
|
+
if (!current) {
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
const settings = await current.model.getSettings();
|
|
739
|
+
const currentValue = (_c = (_b = (_a = settings === null || settings === void 0 ? void 0 : settings.composite) === null || _a === void 0 ? void 0 : _a.stacBrowserDisabled) !== null && _b !== void 0 ? _b : current.model.jgisSettings.stacBrowserDisabled) !== null && _c !== void 0 ? _c : false;
|
|
740
|
+
await (settings === null || settings === void 0 ? void 0 : settings.set('stacBrowserDisabled', !currentValue));
|
|
741
|
+
commands.notifyCommandChanged(CommandIDs.showStacBrowserTab);
|
|
742
|
+
},
|
|
743
|
+
});
|
|
744
|
+
commands.addCommand(CommandIDs.showFiltersTab, {
|
|
745
|
+
label: trans.__('Show Filters Tab'),
|
|
746
|
+
isEnabled: () => Boolean(tracker.currentWidget),
|
|
747
|
+
isToggled: () => tracker.currentWidget
|
|
748
|
+
? !tracker.currentWidget.model.jgisSettings.filtersDisabled
|
|
749
|
+
: false,
|
|
750
|
+
execute: async () => {
|
|
751
|
+
var _a, _b, _c;
|
|
752
|
+
const current = tracker.currentWidget;
|
|
753
|
+
if (!current) {
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
const settings = await current.model.getSettings();
|
|
757
|
+
const currentValue = (_c = (_b = (_a = settings === null || settings === void 0 ? void 0 : settings.composite) === null || _a === void 0 ? void 0 : _a.filtersDisabled) !== null && _b !== void 0 ? _b : current.model.jgisSettings.filtersDisabled) !== null && _c !== void 0 ? _c : false;
|
|
758
|
+
await (settings === null || settings === void 0 ? void 0 : settings.set('filtersDisabled', !currentValue));
|
|
759
|
+
commands.notifyCommandChanged(CommandIDs.showFiltersTab);
|
|
760
|
+
},
|
|
761
|
+
});
|
|
762
|
+
// Right panel tabs
|
|
763
|
+
commands.addCommand(CommandIDs.showObjectPropertiesTab, {
|
|
764
|
+
label: trans.__('Show Object Properties Tab'),
|
|
765
|
+
isEnabled: () => Boolean(tracker.currentWidget),
|
|
766
|
+
isToggled: () => tracker.currentWidget
|
|
767
|
+
? !tracker.currentWidget.model.jgisSettings.objectPropertiesDisabled
|
|
768
|
+
: false,
|
|
769
|
+
execute: async () => {
|
|
770
|
+
var _a, _b, _c;
|
|
771
|
+
const current = tracker.currentWidget;
|
|
772
|
+
if (!current) {
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
const settings = await current.model.getSettings();
|
|
776
|
+
const currentValue = (_c = (_b = (_a = settings === null || settings === void 0 ? void 0 : settings.composite) === null || _a === void 0 ? void 0 : _a.objectPropertiesDisabled) !== null && _b !== void 0 ? _b : current.model.jgisSettings.objectPropertiesDisabled) !== null && _c !== void 0 ? _c : false;
|
|
777
|
+
await (settings === null || settings === void 0 ? void 0 : settings.set('objectPropertiesDisabled', !currentValue));
|
|
778
|
+
commands.notifyCommandChanged(CommandIDs.showObjectPropertiesTab);
|
|
779
|
+
},
|
|
780
|
+
});
|
|
781
|
+
commands.addCommand(CommandIDs.showAnnotationsTab, {
|
|
782
|
+
label: trans.__('Show Annotations Tab'),
|
|
783
|
+
isEnabled: () => Boolean(tracker.currentWidget),
|
|
784
|
+
isToggled: () => tracker.currentWidget
|
|
785
|
+
? !tracker.currentWidget.model.jgisSettings.annotationsDisabled
|
|
786
|
+
: false,
|
|
787
|
+
execute: async () => {
|
|
788
|
+
var _a, _b, _c;
|
|
789
|
+
const current = tracker.currentWidget;
|
|
790
|
+
if (!current) {
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
const settings = await current.model.getSettings();
|
|
794
|
+
const currentValue = (_c = (_b = (_a = settings === null || settings === void 0 ? void 0 : settings.composite) === null || _a === void 0 ? void 0 : _a.annotationsDisabled) !== null && _b !== void 0 ? _b : current.model.jgisSettings.annotationsDisabled) !== null && _c !== void 0 ? _c : false;
|
|
795
|
+
await (settings === null || settings === void 0 ? void 0 : settings.set('annotationsDisabled', !currentValue));
|
|
796
|
+
commands.notifyCommandChanged(CommandIDs.showAnnotationsTab);
|
|
797
|
+
},
|
|
798
|
+
});
|
|
799
|
+
commands.addCommand(CommandIDs.showIdentifyPanelTab, {
|
|
800
|
+
label: trans.__('Show Identify Panel Tab'),
|
|
801
|
+
isEnabled: () => Boolean(tracker.currentWidget),
|
|
802
|
+
isToggled: () => tracker.currentWidget
|
|
803
|
+
? !tracker.currentWidget.model.jgisSettings.identifyDisabled
|
|
804
|
+
: false,
|
|
805
|
+
execute: async () => {
|
|
806
|
+
var _a, _b, _c;
|
|
807
|
+
const current = tracker.currentWidget;
|
|
808
|
+
if (!current) {
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
const settings = await current.model.getSettings();
|
|
812
|
+
const currentValue = (_c = (_b = (_a = settings === null || settings === void 0 ? void 0 : settings.composite) === null || _a === void 0 ? void 0 : _a.identifyDisabled) !== null && _b !== void 0 ? _b : current.model.jgisSettings.identifyDisabled) !== null && _c !== void 0 ? _c : false;
|
|
813
|
+
await (settings === null || settings === void 0 ? void 0 : settings.set('identifyDisabled', !currentValue));
|
|
814
|
+
commands.notifyCommandChanged(CommandIDs.showIdentifyPanelTab);
|
|
815
|
+
},
|
|
816
|
+
});
|
|
655
817
|
loadKeybindings(commands, keybindings);
|
|
656
818
|
}
|
|
657
819
|
var Private;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { IJupyterGISModel } from '@jupytergis/schema';
|
|
2
|
+
interface IUseGetSymbologyProps {
|
|
3
|
+
layerId?: string;
|
|
4
|
+
model: IJupyterGISModel;
|
|
5
|
+
}
|
|
6
|
+
interface IUseGetSymbologyResult {
|
|
7
|
+
symbology: Record<string, any> | null;
|
|
8
|
+
isLoading: boolean;
|
|
9
|
+
error?: Error;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Extracts symbology information (paint/layout + symbologyState)
|
|
13
|
+
* for a given layer from the JupyterGIS model.
|
|
14
|
+
* Keeps symbology updated when the layer changes.
|
|
15
|
+
*/
|
|
16
|
+
export declare const useGetSymbology: ({ layerId, model, }: IUseGetSymbologyProps) => IUseGetSymbologyResult;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { useEffect, useState } from 'react';
|
|
13
|
+
/**
|
|
14
|
+
* Extracts symbology information (paint/layout + symbologyState)
|
|
15
|
+
* for a given layer from the JupyterGIS model.
|
|
16
|
+
* Keeps symbology updated when the layer changes.
|
|
17
|
+
*/
|
|
18
|
+
export const useGetSymbology = ({ layerId, model, }) => {
|
|
19
|
+
const [symbology, setSymbology] = useState(null);
|
|
20
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
21
|
+
const [error, setError] = useState();
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (!layerId) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
let disposed = false;
|
|
27
|
+
const fetchSymbology = () => {
|
|
28
|
+
var _a;
|
|
29
|
+
try {
|
|
30
|
+
setIsLoading(true);
|
|
31
|
+
setError(undefined);
|
|
32
|
+
const layer = model.getLayer(layerId);
|
|
33
|
+
if (!layer) {
|
|
34
|
+
throw new Error(`Layer not found: ${layerId}`);
|
|
35
|
+
}
|
|
36
|
+
const params = (_a = layer.parameters) !== null && _a !== void 0 ? _a : {};
|
|
37
|
+
const { symbologyState, color } = params, rest = __rest(params, ["symbologyState", "color"]);
|
|
38
|
+
const result = Object.assign(Object.assign(Object.assign({}, rest), (color ? { color } : {})), (symbologyState ? { symbologyState } : {}));
|
|
39
|
+
if (!disposed) {
|
|
40
|
+
setSymbology(result);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
if (!disposed) {
|
|
45
|
+
setError(err);
|
|
46
|
+
setSymbology(null);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
if (!disposed) {
|
|
51
|
+
setIsLoading(false);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
// initial load
|
|
56
|
+
fetchSymbology();
|
|
57
|
+
model.sharedModel.awareness.on('change', () => {
|
|
58
|
+
fetchSymbology();
|
|
59
|
+
});
|
|
60
|
+
return () => {
|
|
61
|
+
disposed = true;
|
|
62
|
+
};
|
|
63
|
+
}, [layerId, model]);
|
|
64
|
+
return { symbology, isLoading, error };
|
|
65
|
+
};
|
|
@@ -5,5 +5,5 @@ export declare namespace VectorUtils {
|
|
|
5
5
|
const buildRadiusInfo: (layer: IJGISLayer) => IStopRow[];
|
|
6
6
|
}
|
|
7
7
|
export declare namespace Utils {
|
|
8
|
-
const getValueColorPairs: (stops: number[], selectedRamp: string, nClasses: number) => IStopRow[];
|
|
8
|
+
const getValueColorPairs: (stops: number[], selectedRamp: string, nClasses: number, reverse?: boolean) => IStopRow[];
|
|
9
9
|
}
|
|
@@ -75,12 +75,15 @@ export var VectorUtils;
|
|
|
75
75
|
})(VectorUtils || (VectorUtils = {}));
|
|
76
76
|
export var Utils;
|
|
77
77
|
(function (Utils) {
|
|
78
|
-
Utils.getValueColorPairs = (stops, selectedRamp, nClasses) => {
|
|
78
|
+
Utils.getValueColorPairs = (stops, selectedRamp, nClasses, reverse = false) => {
|
|
79
79
|
let colorMap = colormap({
|
|
80
80
|
colormap: selectedRamp,
|
|
81
81
|
nshades: nClasses > 9 ? nClasses : 9,
|
|
82
82
|
format: 'rgba',
|
|
83
83
|
});
|
|
84
|
+
if (reverse) {
|
|
85
|
+
colorMap = [...colorMap].reverse();
|
|
86
|
+
}
|
|
84
87
|
const valueColorPairs = [];
|
|
85
88
|
// colormap requires 9 classes to generate the ramp
|
|
86
89
|
// so we do some tomfoolery to make it work with less than 9 stops
|
|
@@ -17,6 +17,7 @@ const Categorized = ({ model, state, okSignalPromise, cancel, layerId, symbology
|
|
|
17
17
|
radius: 5,
|
|
18
18
|
});
|
|
19
19
|
const manualStyleRef = useRef(manualStyle);
|
|
20
|
+
const [reverseRamp, setReverseRamp] = useState(false);
|
|
20
21
|
if (!layerId) {
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
@@ -85,7 +86,7 @@ const Categorized = ({ model, state, okSignalPromise, cancel, layerId, symbology
|
|
|
85
86
|
selectedMode: '',
|
|
86
87
|
});
|
|
87
88
|
const stops = Array.from(selectableAttributesAndValues[selectedAttribute]).sort((a, b) => a - b);
|
|
88
|
-
const valueColorPairs = Utils.getValueColorPairs(stops, selectedRamp, stops.length);
|
|
89
|
+
const valueColorPairs = Utils.getValueColorPairs(stops, selectedRamp, stops.length, reverseRamp);
|
|
89
90
|
setStopRows(valueColorPairs);
|
|
90
91
|
};
|
|
91
92
|
const handleOk = () => {
|
|
@@ -124,6 +125,7 @@ const Categorized = ({ model, state, okSignalPromise, cancel, layerId, symbology
|
|
|
124
125
|
nClasses: (_b = colorRampOptionsRef.current) === null || _b === void 0 ? void 0 : _b.numberOfShades,
|
|
125
126
|
mode: (_c = colorRampOptionsRef.current) === null || _c === void 0 ? void 0 : _c.selectedMode,
|
|
126
127
|
symbologyTab,
|
|
128
|
+
reverse: reverseRamp,
|
|
127
129
|
};
|
|
128
130
|
layer.parameters.symbologyState = symbologyState;
|
|
129
131
|
layer.parameters.color = newStyle;
|
|
@@ -188,6 +190,10 @@ const Categorized = ({ model, state, okSignalPromise, cancel, layerId, symbology
|
|
|
188
190
|
React.createElement("input", { type: "number", className: "jp-mod-styled", value: manualStyle.radius, onChange: e => {
|
|
189
191
|
setManualStyle(prev => (Object.assign(Object.assign({}, prev), { radius: +e.target.value })));
|
|
190
192
|
} })))),
|
|
193
|
+
symbologyTab === 'color' && (React.createElement("div", { className: "jp-gis-symbology-row" },
|
|
194
|
+
React.createElement("label", null,
|
|
195
|
+
React.createElement("input", { type: "checkbox", checked: reverseRamp, onChange: e => setReverseRamp(e.target.checked) }),
|
|
196
|
+
"Reverse Color Ramp"))),
|
|
191
197
|
React.createElement("div", { className: "jp-gis-layer-symbology-container" },
|
|
192
198
|
React.createElement(ColorRamp, { layerParams: layer.parameters, modeOptions: [], classifyFunc: buildColorInfoFromClassification, showModeRow: false, showRampSelector: symbologyTab === 'color' }),
|
|
193
199
|
React.createElement(StopContainer, { selectedMethod: '', stopRows: stopRows, setStopRows: setStopRows }))));
|
|
@@ -29,6 +29,7 @@ const Graduated = ({ model, state, okSignalPromise, cancel, layerId, symbologyTa
|
|
|
29
29
|
const [radiusManualStyle, setRadiusManualStyle] = useState({
|
|
30
30
|
radius: 5,
|
|
31
31
|
});
|
|
32
|
+
const [reverseRamp, setReverseRamp] = useState(false);
|
|
32
33
|
const colorManualStyleRef = useRef(colorManualStyle);
|
|
33
34
|
const radiusManualStyleRef = useRef(radiusManualStyle);
|
|
34
35
|
if (!layerId) {
|
|
@@ -161,6 +162,7 @@ const Graduated = ({ model, state, okSignalPromise, cancel, layerId, symbologyTa
|
|
|
161
162
|
colorRamp: (_a = colorRampOptionsRef.current) === null || _a === void 0 ? void 0 : _a.selectedRamp,
|
|
162
163
|
nClasses: (_b = colorRampOptionsRef.current) === null || _b === void 0 ? void 0 : _b.numberOfShades,
|
|
163
164
|
mode: (_c = colorRampOptionsRef.current) === null || _c === void 0 ? void 0 : _c.selectedMode,
|
|
165
|
+
reverse: reverseRamp,
|
|
164
166
|
};
|
|
165
167
|
if (layer.type === 'HeatmapLayer') {
|
|
166
168
|
layer.type = 'VectorLayer';
|
|
@@ -198,7 +200,7 @@ const Graduated = ({ model, state, okSignalPromise, cancel, layerId, symbologyTa
|
|
|
198
200
|
}
|
|
199
201
|
const stopOutputPairs = symbologyTab === 'radius'
|
|
200
202
|
? stops.map(v => ({ stop: v, output: v }))
|
|
201
|
-
: Utils.getValueColorPairs(stops, selectedRamp, +numberOfShades);
|
|
203
|
+
: Utils.getValueColorPairs(stops, selectedRamp, +numberOfShades, reverseRamp);
|
|
202
204
|
if (symbologyTab === 'radius') {
|
|
203
205
|
setRadiusStopRows(stopOutputPairs);
|
|
204
206
|
}
|
|
@@ -257,6 +259,10 @@ const Graduated = ({ model, state, okSignalPromise, cancel, layerId, symbologyTa
|
|
|
257
259
|
handleReset('radius');
|
|
258
260
|
setRadiusManualStyle(Object.assign(Object.assign({}, radiusManualStyle), { radius: +e.target.value }));
|
|
259
261
|
} })))),
|
|
262
|
+
symbologyTab === 'color' && (React.createElement("div", { className: "jp-gis-symbology-row" },
|
|
263
|
+
React.createElement("label", null,
|
|
264
|
+
React.createElement("input", { type: "checkbox", checked: reverseRamp, onChange: e => setReverseRamp(e.target.checked) }),
|
|
265
|
+
"Reverse Color Ramp"))),
|
|
260
266
|
React.createElement(ColorRamp, { layerParams: layer.parameters, modeOptions: modeOptions, classifyFunc: buildColorInfoFromClassification, showModeRow: true, showRampSelector: symbologyTab === 'color' }),
|
|
261
267
|
React.createElement(StopContainer, { selectedMethod: symbologyTab || 'color', stopRows: symbologyTab === 'color' ? colorStopRows : radiusStopRows, setStopRows: symbologyTab === 'color' ? setColorStopRows : setRadiusStopRows })));
|
|
262
268
|
}
|
|
@@ -14,11 +14,13 @@ const Heatmap = ({ model, state, okSignalPromise, cancel, layerId, }) => {
|
|
|
14
14
|
radius: 8,
|
|
15
15
|
blur: 15,
|
|
16
16
|
});
|
|
17
|
+
const [reverseRamp, setReverseRamp] = useState(false);
|
|
17
18
|
const selectedRampRef = useRef('viridis');
|
|
18
19
|
const heatmapOptionsRef = useRef({
|
|
19
20
|
radius: 8,
|
|
20
21
|
blur: 15,
|
|
21
22
|
});
|
|
23
|
+
const reverseRampRef = useRef(false);
|
|
22
24
|
useEffect(() => {
|
|
23
25
|
populateOptions();
|
|
24
26
|
okSignalPromise.promise.then(okSignal => {
|
|
@@ -33,7 +35,8 @@ const Heatmap = ({ model, state, okSignalPromise, cancel, layerId, }) => {
|
|
|
33
35
|
useEffect(() => {
|
|
34
36
|
selectedRampRef.current = selectedRamp;
|
|
35
37
|
heatmapOptionsRef.current = heatmapOptions;
|
|
36
|
-
|
|
38
|
+
reverseRampRef.current = reverseRamp;
|
|
39
|
+
}, [selectedRamp, heatmapOptions, reverseRamp]);
|
|
37
40
|
const populateOptions = async () => {
|
|
38
41
|
var _a;
|
|
39
42
|
let colorRamp;
|
|
@@ -46,14 +49,18 @@ const Heatmap = ({ model, state, okSignalPromise, cancel, layerId, }) => {
|
|
|
46
49
|
if (!layer.parameters) {
|
|
47
50
|
return;
|
|
48
51
|
}
|
|
49
|
-
|
|
52
|
+
let colorMap = colormap({
|
|
50
53
|
colormap: selectedRampRef.current,
|
|
51
54
|
nshades: 9,
|
|
52
55
|
format: 'hex',
|
|
53
56
|
});
|
|
57
|
+
if (reverseRampRef.current) {
|
|
58
|
+
colorMap = [...colorMap].reverse();
|
|
59
|
+
}
|
|
54
60
|
const symbologyState = {
|
|
55
61
|
renderType: 'Heatmap',
|
|
56
62
|
colorRamp: selectedRampRef.current,
|
|
63
|
+
reverse: reverseRampRef.current,
|
|
57
64
|
};
|
|
58
65
|
layer.parameters.symbologyState = symbologyState;
|
|
59
66
|
layer.parameters.color = colorMap;
|
|
@@ -68,6 +75,10 @@ const Heatmap = ({ model, state, okSignalPromise, cancel, layerId, }) => {
|
|
|
68
75
|
React.createElement("div", { className: "jp-gis-symbology-row jp-gis-heatmap" },
|
|
69
76
|
React.createElement("label", { htmlFor: "color-ramp-select" }, "Color Ramp:"),
|
|
70
77
|
React.createElement(CanvasSelectComponent, { selectedRamp: selectedRamp, setSelected: setSelectedRamp })),
|
|
78
|
+
React.createElement("div", { className: "jp-gis-symbology-row" },
|
|
79
|
+
React.createElement("label", null,
|
|
80
|
+
React.createElement("input", { type: "checkbox", checked: reverseRamp, onChange: e => setReverseRamp(e.target.checked) }),
|
|
81
|
+
"Reverse Color Ramp")),
|
|
71
82
|
React.createElement("div", { className: "jp-gis-symbology-row" },
|
|
72
83
|
React.createElement("label", { htmlFor: 'vector-value-select' }, "Radius:"),
|
|
73
84
|
React.createElement("input", { type: "number", value: heatmapOptions.radius, className: "jp-mod-styled", onChange: event => setHetamapOptions(prevState => (Object.assign(Object.assign({}, prevState), { radius: +event.target.value }))) })),
|
package/lib/gdal.js
CHANGED
package/lib/mainview/mainView.js
CHANGED
|
@@ -103,7 +103,7 @@ export class MainView extends React.Component {
|
|
|
103
103
|
return layer === this.getLayer(selectedLayerId);
|
|
104
104
|
},
|
|
105
105
|
condition: (event) => {
|
|
106
|
-
return singleClick(event) && this._model.
|
|
106
|
+
return singleClick(event) && this._model.currentMode === 'identifying';
|
|
107
107
|
},
|
|
108
108
|
style: styleFunction,
|
|
109
109
|
});
|
|
@@ -483,8 +483,7 @@ export class MainView extends React.Component {
|
|
|
483
483
|
// Watch isIdentifying and clear the highlight when Identify Tool is turned off
|
|
484
484
|
this._model.sharedModel.awareness.on('change', () => {
|
|
485
485
|
var _a;
|
|
486
|
-
|
|
487
|
-
if (!isIdentifying && this._highlightLayer) {
|
|
486
|
+
if (this._model.currentMode !== 'identifying' && this._highlightLayer) {
|
|
488
487
|
(_a = this._highlightLayer.getSource()) === null || _a === void 0 ? void 0 : _a.clear();
|
|
489
488
|
}
|
|
490
489
|
});
|
|
@@ -740,9 +739,7 @@ export class MainView extends React.Component {
|
|
|
740
739
|
const format = new GeoJSON({
|
|
741
740
|
featureProjection: this._Map.getView().getProjection(),
|
|
742
741
|
});
|
|
743
|
-
// TODO: Don't hardcode projection
|
|
744
742
|
const featureArray = format.readFeatures(data, {
|
|
745
|
-
dataProjection: 'EPSG:4326',
|
|
746
743
|
featureProjection: this._Map.getView().getProjection(),
|
|
747
744
|
});
|
|
748
745
|
const featureCollection = new Collection(featureArray);
|
|
@@ -1580,7 +1577,7 @@ export class MainView extends React.Component {
|
|
|
1580
1577
|
}
|
|
1581
1578
|
_identifyFeature(e) {
|
|
1582
1579
|
var _a, _b;
|
|
1583
|
-
if (
|
|
1580
|
+
if (this._model.currentMode !== 'identifying') {
|
|
1584
1581
|
return;
|
|
1585
1582
|
}
|
|
1586
1583
|
const localState = (_a = this._model) === null || _a === void 0 ? void 0 : _a.sharedModel.awareness.getLocalState();
|
|
@@ -1708,7 +1705,8 @@ export class MainView extends React.Component {
|
|
|
1708
1705
|
height: '100%',
|
|
1709
1706
|
} })),
|
|
1710
1707
|
React.createElement(StatusBar, { jgisModel: this._model, loading: this.state.loadingLayer, projection: this.state.viewProjection, scale: this.state.scale })),
|
|
1711
|
-
|
|
1712
|
-
|
|
1708
|
+
React.createElement("div", { className: "jgis-panels-wrapper" },
|
|
1709
|
+
this._state && (React.createElement(LeftPanel, { model: this._model, commands: this._mainViewModel.commands, state: this._state })),
|
|
1710
|
+
this._formSchemaRegistry && this._annotationModel && (React.createElement(RightPanel, { model: this._model, formSchemaRegistry: this._formSchemaRegistry, annotationModel: this._annotationModel })))));
|
|
1713
1711
|
}
|
|
1714
1712
|
}
|
|
@@ -35,7 +35,8 @@ export const IdentifyPanelComponent = ({ model, }) => {
|
|
|
35
35
|
setFeatures({});
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
|
-
if (model.
|
|
38
|
+
if (model.currentMode === 'identifying' &&
|
|
39
|
+
featuresRef.current !== identifiedFeatures) {
|
|
39
40
|
setFeatures(identifiedFeatures);
|
|
40
41
|
}
|
|
41
42
|
};
|
|
@@ -53,6 +54,15 @@ export const IdentifyPanelComponent = ({ model, }) => {
|
|
|
53
54
|
const toggleFeatureVisibility = (index) => {
|
|
54
55
|
setVisibleFeatures(prev => (Object.assign(Object.assign({}, prev), { [index]: !prev[index] })));
|
|
55
56
|
};
|
|
57
|
+
const getFeatureNameOrId = (feature, featureIndex) => {
|
|
58
|
+
for (const key of Object.keys(feature)) {
|
|
59
|
+
const lowerCase = key.toLowerCase();
|
|
60
|
+
if ((lowerCase.includes('name') || lowerCase === 'id') && feature[key]) {
|
|
61
|
+
return feature[key];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return `Feature ${featureIndex + 1}`;
|
|
65
|
+
};
|
|
56
66
|
return (React.createElement("div", { className: "jgis-identify-wrapper", style: {
|
|
57
67
|
border: ((_a = model === null || model === void 0 ? void 0 : model.localState) === null || _a === void 0 ? void 0 : _a.remoteUser)
|
|
58
68
|
? `solid 3px ${remoteUser === null || remoteUser === void 0 ? void 0 : remoteUser.color}`
|
|
@@ -62,9 +72,7 @@ export const IdentifyPanelComponent = ({ model, }) => {
|
|
|
62
72
|
React.createElement("div", { className: "jgis-identify-grid-item-header" },
|
|
63
73
|
React.createElement("span", { onClick: () => toggleFeatureVisibility(featureIndex) },
|
|
64
74
|
React.createElement(LabIcon.resolveReact, { icon: caretDownIcon, className: `jp-gis-layerGroupCollapser${visibleFeatures[featureIndex] ? ' jp-mod-expanded' : ''}`, tag: 'span' }),
|
|
65
|
-
React.createElement("span", null,
|
|
66
|
-
"Feature ",
|
|
67
|
-
featureIndex + 1)),
|
|
75
|
+
React.createElement("span", null, getFeatureNameOrId(feature, featureIndex))),
|
|
68
76
|
(() => {
|
|
69
77
|
const isRasterFeature = !feature.geometry &&
|
|
70
78
|
!feature._geometry &&
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { DOMUtils } from '@jupyterlab/apputils';
|
|
2
|
-
import { Button, LabIcon, caretDownIcon } from '@jupyterlab/ui-components';
|
|
2
|
+
import { Button, LabIcon, caretDownIcon, caretRightIcon, } from '@jupyterlab/ui-components';
|
|
3
3
|
import { UUID } from '@lumino/coreutils';
|
|
4
4
|
import React, { useEffect, useState, } from 'react';
|
|
5
5
|
import { CommandIDs, icons } from "../../constants";
|
|
6
|
+
import { useGetSymbology } from "../../dialogs/symbology/hooks/useGetSymbology";
|
|
6
7
|
import { nonVisibilityIcon, visibilityIcon } from "../../icons";
|
|
8
|
+
import { LegendItem } from './legendItem';
|
|
7
9
|
const LAYER_GROUP_CLASS = 'jp-gis-layerGroup';
|
|
8
10
|
const LAYER_GROUP_HEADER_CLASS = 'jp-gis-layerGroupHeader';
|
|
9
11
|
const LAYER_GROUP_COLLAPSER_CLASS = 'jp-gis-layerGroupCollapser';
|
|
@@ -213,6 +215,12 @@ const LayerComponent = props => {
|
|
|
213
215
|
const [selected, setSelected] = useState(
|
|
214
216
|
// TODO Support multi-selection as `model?.jGISModel?.localState?.selected.value` does
|
|
215
217
|
isSelected(layerId, gisModel));
|
|
218
|
+
const [expanded, setExpanded] = useState(false);
|
|
219
|
+
const { symbology } = useGetSymbology({
|
|
220
|
+
layerId,
|
|
221
|
+
model: gisModel,
|
|
222
|
+
});
|
|
223
|
+
const hasSupportedSymbology = (symbology === null || symbology === void 0 ? void 0 : symbology.symbologyState) !== undefined;
|
|
216
224
|
const name = layer.name;
|
|
217
225
|
useEffect(() => {
|
|
218
226
|
setId(DOMUtils.createDomID());
|
|
@@ -248,12 +256,19 @@ const LayerComponent = props => {
|
|
|
248
256
|
event,
|
|
249
257
|
});
|
|
250
258
|
};
|
|
251
|
-
return (React.createElement("div", { className: `${LAYER_ITEM_CLASS} ${LAYER_CLASS}${selected ? ' jp-mod-selected' : ''}`, draggable: true, onDragStart: Private.onDragStart, onDragOver: Private.onDragOver, onDragEnd: Private.onDragEnd, "data-id": layerId },
|
|
252
|
-
React.createElement("div", { className: LAYER_TITLE_CLASS, onClick: setSelection, onContextMenu: setSelection },
|
|
259
|
+
return (React.createElement("div", { className: `${LAYER_ITEM_CLASS} ${LAYER_CLASS}${selected ? ' jp-mod-selected' : ''}`, draggable: true, onDragStart: Private.onDragStart, onDragOver: Private.onDragOver, onDragEnd: Private.onDragEnd, "data-id": layerId, style: { display: 'flex', flexDirection: 'column' } },
|
|
260
|
+
React.createElement("div", { className: LAYER_TITLE_CLASS, onClick: setSelection, onContextMenu: setSelection, style: { display: 'flex' } },
|
|
261
|
+
hasSupportedSymbology && (React.createElement(Button, { minimal: true, onClick: e => {
|
|
262
|
+
e.stopPropagation();
|
|
263
|
+
setExpanded(v => !v);
|
|
264
|
+
}, title: expanded ? 'Hide legend' : 'Show legend' },
|
|
265
|
+
React.createElement(LabIcon.resolveReact, { icon: expanded ? caretDownIcon : caretRightIcon, tag: "span" }))),
|
|
253
266
|
React.createElement(Button, { title: layer.visible ? 'Hide layer' : 'Show layer', onClick: toggleVisibility, minimal: true },
|
|
254
267
|
React.createElement(LabIcon.resolveReact, { icon: layer.visible ? visibilityIcon : nonVisibilityIcon, className: `${LAYER_ICON_CLASS}${layer.visible ? '' : ' jp-gis-mod-hidden'}`, tag: "span" })),
|
|
255
268
|
icons.has(layer.type) && (React.createElement(LabIcon.resolveReact, Object.assign({}, icons.get(layer.type), { className: LAYER_ICON_CLASS }))),
|
|
256
|
-
React.createElement("span", { id: id, className: LAYER_TEXT_CLASS, tabIndex: -2 }, name))
|
|
269
|
+
React.createElement("span", { id: id, className: LAYER_TEXT_CLASS, tabIndex: -2 }, name)),
|
|
270
|
+
expanded && gisModel && hasSupportedSymbology && (React.createElement("div", { style: { marginTop: 6, width: '100%' } },
|
|
271
|
+
React.createElement(LegendItem, { layerId: layerId, model: gisModel })))));
|
|
257
272
|
};
|
|
258
273
|
var Private;
|
|
259
274
|
(function (Private) {
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { useGetSymbology } from "../../dialogs/symbology/hooks/useGetSymbology";
|
|
3
|
+
export const LegendItem = ({ layerId, model }) => {
|
|
4
|
+
const { symbology, isLoading, error } = useGetSymbology({ layerId, model });
|
|
5
|
+
const [content, setContent] = useState(null);
|
|
6
|
+
const parseColorStops = (expr) => {
|
|
7
|
+
if (!Array.isArray(expr) || expr[0] !== 'interpolate') {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
const stops = [];
|
|
11
|
+
for (let i = 3; i < expr.length; i += 2) {
|
|
12
|
+
const value = expr[i];
|
|
13
|
+
const rgba = expr[i + 1];
|
|
14
|
+
const color = Array.isArray(rgba)
|
|
15
|
+
? `rgba(${rgba[0]},${rgba[1]},${rgba[2]},${rgba[3]})`
|
|
16
|
+
: String(rgba);
|
|
17
|
+
stops.push({ value, color });
|
|
18
|
+
}
|
|
19
|
+
return stops;
|
|
20
|
+
};
|
|
21
|
+
const parseCaseCategories = (expr) => {
|
|
22
|
+
if (!Array.isArray(expr) || expr[0] !== 'case') {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
const categories = [];
|
|
26
|
+
for (let i = 1; i < expr.length - 1; i += 2) {
|
|
27
|
+
const condition = expr[i];
|
|
28
|
+
const colorExpr = expr[i + 1];
|
|
29
|
+
let category = '';
|
|
30
|
+
if (Array.isArray(condition) && condition[0] === '==') {
|
|
31
|
+
category = condition[2];
|
|
32
|
+
}
|
|
33
|
+
let color = '';
|
|
34
|
+
if (Array.isArray(colorExpr)) {
|
|
35
|
+
color = `rgba(${colorExpr[0]},${colorExpr[1]},${colorExpr[2]},${colorExpr[3]})`;
|
|
36
|
+
}
|
|
37
|
+
else if (typeof colorExpr === 'string') {
|
|
38
|
+
color = colorExpr;
|
|
39
|
+
}
|
|
40
|
+
categories.push({ category, color });
|
|
41
|
+
}
|
|
42
|
+
return categories;
|
|
43
|
+
};
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
46
|
+
if (isLoading) {
|
|
47
|
+
setContent(React.createElement("p", { style: { fontSize: '0.8em' } }, "Loading\u2026"));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (error) {
|
|
51
|
+
setContent(React.createElement("p", { style: { color: 'red', fontSize: '0.8em' } }, error.message));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (!symbology) {
|
|
55
|
+
setContent(React.createElement("p", { style: { fontSize: '0.8em' } }, "No symbology"));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const renderType = (_a = symbology.symbologyState) === null || _a === void 0 ? void 0 : _a.renderType;
|
|
59
|
+
const property = (_b = symbology.symbologyState) === null || _b === void 0 ? void 0 : _b.value;
|
|
60
|
+
const fill = (_d = (_c = symbology.color) === null || _c === void 0 ? void 0 : _c['fill-color']) !== null && _d !== void 0 ? _d : (_e = symbology.color) === null || _e === void 0 ? void 0 : _e['circle-fill-color'];
|
|
61
|
+
const stroke = (_g = (_f = symbology.color) === null || _f === void 0 ? void 0 : _f['stroke-color']) !== null && _g !== void 0 ? _g : (_h = symbology.color) === null || _h === void 0 ? void 0 : _h['circle-stroke-color'];
|
|
62
|
+
// Single Symbol
|
|
63
|
+
if (renderType === 'Single Symbol') {
|
|
64
|
+
setContent(React.createElement("div", { style: { display: 'flex', gap: 12, flexWrap: 'wrap', padding: 6 } },
|
|
65
|
+
fill && (React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 6 } },
|
|
66
|
+
React.createElement("span", { style: {
|
|
67
|
+
width: 16,
|
|
68
|
+
height: 16,
|
|
69
|
+
border: '1px solid #000',
|
|
70
|
+
background: fill,
|
|
71
|
+
} }),
|
|
72
|
+
React.createElement("span", { style: { fontSize: '0.8em' } }, "Fill"))),
|
|
73
|
+
stroke && (React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 6 } },
|
|
74
|
+
React.createElement("span", { style: {
|
|
75
|
+
width: 24,
|
|
76
|
+
height: 2,
|
|
77
|
+
background: stroke,
|
|
78
|
+
border: '1px solid #000',
|
|
79
|
+
} }),
|
|
80
|
+
React.createElement("span", { style: { fontSize: '0.8em' } }, "Stroke"))),
|
|
81
|
+
!fill && !stroke && (React.createElement("span", { style: { fontSize: '0.8em' } }, "No symbol colors"))));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
// Graduated
|
|
85
|
+
if (renderType === 'Graduated') {
|
|
86
|
+
const stops = parseColorStops(fill || stroke);
|
|
87
|
+
if (!stops.length) {
|
|
88
|
+
setContent(React.createElement("p", { style: { fontSize: '0.8em' } }, "No graduated symbology"));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const segments = stops
|
|
92
|
+
.map((s, i) => {
|
|
93
|
+
const pct = (i / (stops.length - 1)) * 100;
|
|
94
|
+
return `${s.color} ${pct}%`;
|
|
95
|
+
})
|
|
96
|
+
.join(', ');
|
|
97
|
+
const gradient = `linear-gradient(to right, ${segments})`;
|
|
98
|
+
setContent(React.createElement("div", { style: { padding: 6, width: '90%' } },
|
|
99
|
+
property && (React.createElement("div", { style: { fontSize: '1em', marginBottom: 20 } },
|
|
100
|
+
React.createElement("strong", null, property))),
|
|
101
|
+
React.createElement("div", { style: {
|
|
102
|
+
position: 'relative',
|
|
103
|
+
height: 12,
|
|
104
|
+
background: gradient,
|
|
105
|
+
border: '1px solid #ccc',
|
|
106
|
+
borderRadius: 3,
|
|
107
|
+
marginBottom: 20,
|
|
108
|
+
marginTop: 10,
|
|
109
|
+
} }, stops.map((s, i) => {
|
|
110
|
+
const left = (i / (stops.length - 1)) * 100;
|
|
111
|
+
const up = i % 2 === 0;
|
|
112
|
+
return (React.createElement("div", { key: i, style: {
|
|
113
|
+
position: 'absolute',
|
|
114
|
+
left: `${left}%`,
|
|
115
|
+
transform: 'translateX(-50%)',
|
|
116
|
+
} },
|
|
117
|
+
React.createElement("div", { style: {
|
|
118
|
+
width: 1,
|
|
119
|
+
height: 8,
|
|
120
|
+
background: '#333',
|
|
121
|
+
margin: '0 auto',
|
|
122
|
+
} }),
|
|
123
|
+
React.createElement("div", { style: {
|
|
124
|
+
position: 'absolute',
|
|
125
|
+
top: up ? -18 : 12,
|
|
126
|
+
fontSize: '0.7em',
|
|
127
|
+
whiteSpace: 'nowrap',
|
|
128
|
+
marginTop: up ? 0 : 4,
|
|
129
|
+
} }, s.value.toFixed(2))));
|
|
130
|
+
}))));
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
// Categorized
|
|
134
|
+
if (renderType === 'Categorized') {
|
|
135
|
+
const cats = parseCaseCategories(fill || stroke);
|
|
136
|
+
if (!cats.length) {
|
|
137
|
+
setContent(React.createElement("p", { style: { fontSize: '0.8em' } }, "No categorized symbology"));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
setContent(React.createElement("div", { style: { padding: 6 } },
|
|
141
|
+
property && (React.createElement("div", { style: { fontSize: '1em', marginBottom: 6 } },
|
|
142
|
+
React.createElement("strong", null, property))),
|
|
143
|
+
React.createElement("div", { style: {
|
|
144
|
+
display: 'grid',
|
|
145
|
+
gap: 6,
|
|
146
|
+
maxHeight: 200,
|
|
147
|
+
overflowY: 'auto',
|
|
148
|
+
paddingRight: 4,
|
|
149
|
+
} }, cats.map((c, i) => (React.createElement("div", { key: i, style: { display: 'flex', alignItems: 'center', gap: 8 } },
|
|
150
|
+
React.createElement("span", { style: {
|
|
151
|
+
width: 16,
|
|
152
|
+
height: 16,
|
|
153
|
+
background: c.color || '#ccc',
|
|
154
|
+
border: '1px solid #000',
|
|
155
|
+
borderRadius: 2,
|
|
156
|
+
} }),
|
|
157
|
+
React.createElement("span", { style: { fontSize: '0.75em' } }, String(c.category))))))));
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
setContent(React.createElement("p", null,
|
|
161
|
+
"Unsupported symbology: ",
|
|
162
|
+
String(renderType)));
|
|
163
|
+
}, [symbology, isLoading, error]);
|
|
164
|
+
return React.createElement("div", null, content);
|
|
165
|
+
};
|
|
@@ -1,34 +1,45 @@
|
|
|
1
|
-
import { PageConfig } from '@jupyterlab/coreutils';
|
|
2
1
|
import * as React from 'react';
|
|
3
2
|
import { LayersBodyComponent } from './components/layers';
|
|
4
3
|
import { PanelTabs, TabsContent, TabsList, TabsTrigger, } from '../shared/components/Tabs';
|
|
5
4
|
import StacPanel from '../stacBrowser/components/StacPanel';
|
|
6
5
|
import FilterComponent from './components/filter-panel/Filter';
|
|
7
6
|
export const LeftPanel = (props) => {
|
|
8
|
-
const
|
|
7
|
+
const [settings, setSettings] = React.useState(props.model.jgisSettings);
|
|
8
|
+
React.useEffect(() => {
|
|
9
|
+
const onSettingsChanged = () => {
|
|
10
|
+
setSettings(Object.assign({}, props.model.jgisSettings));
|
|
11
|
+
};
|
|
12
|
+
props.model.settingsChanged.connect(onSettingsChanged);
|
|
13
|
+
return () => {
|
|
14
|
+
props.model.settingsChanged.disconnect(onSettingsChanged);
|
|
15
|
+
};
|
|
16
|
+
}, [props.model]);
|
|
17
|
+
const allLeftTabsDisabled = settings.layersDisabled &&
|
|
18
|
+
settings.stacBrowserDisabled &&
|
|
19
|
+
settings.filtersDisabled;
|
|
20
|
+
const leftPanelVisible = !settings.leftPanelDisabled && !allLeftTabsDisabled;
|
|
9
21
|
const tabInfo = [
|
|
10
|
-
{ name: 'layers', title: 'Layers' },
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
22
|
+
!settings.layersDisabled ? { name: 'layers', title: 'Layers' } : false,
|
|
23
|
+
!settings.stacBrowserDisabled
|
|
24
|
+
? { name: 'stac', title: 'Stac Browser' }
|
|
25
|
+
: false,
|
|
26
|
+
!settings.filtersDisabled ? { name: 'filters', title: 'Filters' } : false,
|
|
27
|
+
].filter(Boolean);
|
|
28
|
+
const [curTab, setCurTab] = React.useState(tabInfo.length > 0 ? tabInfo[0].name : undefined);
|
|
29
|
+
return (React.createElement("div", { className: "jgis-left-panel-container", style: { display: leftPanelVisible ? 'block' : 'none' } },
|
|
16
30
|
React.createElement(PanelTabs, { curTab: curTab, className: "jgis-panel-tabs" },
|
|
17
|
-
React.createElement(TabsList, null, tabInfo.map(e => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
React.createElement(TabsContent, { value: "
|
|
28
|
-
React.createElement(LayersBodyComponent, { model: props.model, commands: props.commands, state: props.state })),
|
|
29
|
-
!hideStacPanel && (React.createElement(TabsContent, { value: "stac" },
|
|
31
|
+
React.createElement(TabsList, null, tabInfo.map(e => (React.createElement(TabsTrigger, { className: "jGIS-layer-browser-category", value: e.name, onClick: () => {
|
|
32
|
+
if (curTab !== e.name) {
|
|
33
|
+
setCurTab(e.name);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
setCurTab('');
|
|
37
|
+
}
|
|
38
|
+
} }, e.title)))),
|
|
39
|
+
!settings.layersDisabled && (React.createElement(TabsContent, { value: "layers", className: "jgis-panel-tab-content jp-gis-layerPanel" },
|
|
40
|
+
React.createElement(LayersBodyComponent, { model: props.model, commands: props.commands, state: props.state }))),
|
|
41
|
+
!settings.stacBrowserDisabled && (React.createElement(TabsContent, { value: "stac", className: "jgis-panel-tab-content" },
|
|
30
42
|
React.createElement(StacPanel, { model: props.model }))),
|
|
31
|
-
React.createElement(TabsContent, { value: "filters", className: "jgis-panel-tab-content" },
|
|
32
|
-
React.createElement(FilterComponent, { model: props.model })
|
|
33
|
-
","))));
|
|
43
|
+
!settings.filtersDisabled && (React.createElement(TabsContent, { value: "filters", className: "jgis-panel-tab-content" },
|
|
44
|
+
React.createElement(FilterComponent, { model: props.model }))))));
|
|
34
45
|
};
|
|
@@ -1,36 +1,64 @@
|
|
|
1
|
-
import { PageConfig } from '@jupyterlab/coreutils';
|
|
2
1
|
import * as React from 'react';
|
|
3
2
|
import { AnnotationsPanel } from './annotationPanel';
|
|
4
3
|
import { IdentifyPanelComponent } from './components/identify-panel/IdentifyPanel';
|
|
5
4
|
import { ObjectPropertiesReact } from './objectproperties';
|
|
6
5
|
import { PanelTabs, TabsContent, TabsList, TabsTrigger, } from '../shared/components/Tabs';
|
|
7
6
|
export const RightPanel = props => {
|
|
8
|
-
const
|
|
9
|
-
const [selectedObjectProperties, setSelectedObjectProperties] = React.useState(undefined);
|
|
7
|
+
const [settings, setSettings] = React.useState(props.model.jgisSettings);
|
|
10
8
|
const tabInfo = [
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
!settings.objectPropertiesDisabled
|
|
10
|
+
? { name: 'objectProperties', title: 'Object Properties' }
|
|
11
|
+
: false,
|
|
12
|
+
!settings.annotationsDisabled
|
|
13
|
+
? { name: 'annotations', title: 'Annotations' }
|
|
14
|
+
: false,
|
|
15
|
+
!settings.identifyDisabled
|
|
16
|
+
? { name: 'identifyPanel', title: 'Identified Features' }
|
|
17
|
+
: false,
|
|
18
|
+
].filter(Boolean);
|
|
19
|
+
const [curTab, setCurTab] = React.useState(tabInfo.length > 0 ? tabInfo[0].name : undefined);
|
|
20
|
+
React.useEffect(() => {
|
|
21
|
+
const onSettingsChanged = () => {
|
|
22
|
+
setSettings(Object.assign({}, props.model.jgisSettings));
|
|
23
|
+
};
|
|
24
|
+
let currentlyIdentifiedFeatures = undefined;
|
|
25
|
+
const onAwerenessChanged = (_, clients) => {
|
|
26
|
+
var _a;
|
|
27
|
+
const clientId = props.model.getClientId();
|
|
28
|
+
const localState = clientId ? clients.get(clientId) : null;
|
|
29
|
+
if (localState &&
|
|
30
|
+
((_a = localState.identifiedFeatures) === null || _a === void 0 ? void 0 : _a.value) &&
|
|
31
|
+
localState.identifiedFeatures.value !== currentlyIdentifiedFeatures) {
|
|
32
|
+
currentlyIdentifiedFeatures = localState.identifiedFeatures.value;
|
|
33
|
+
setCurTab('identifyPanel');
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
props.model.settingsChanged.connect(onSettingsChanged);
|
|
37
|
+
props.model.clientStateChanged.connect(onAwerenessChanged);
|
|
38
|
+
return () => {
|
|
39
|
+
props.model.settingsChanged.disconnect(onSettingsChanged);
|
|
40
|
+
props.model.clientStateChanged.disconnect(onAwerenessChanged);
|
|
41
|
+
};
|
|
42
|
+
}, [props.model]);
|
|
43
|
+
const allRightTabsDisabled = settings.objectPropertiesDisabled &&
|
|
44
|
+
settings.annotationsDisabled &&
|
|
45
|
+
settings.identifyDisabled;
|
|
46
|
+
const rightPanelVisible = !settings.rightPanelDisabled && !allRightTabsDisabled;
|
|
47
|
+
const [selectedObjectProperties, setSelectedObjectProperties] = React.useState(undefined);
|
|
48
|
+
return (React.createElement("div", { className: "jgis-right-panel-container", style: { display: rightPanelVisible ? 'block' : 'none' } },
|
|
19
49
|
React.createElement(PanelTabs, { className: "jgis-panel-tabs", curTab: curTab },
|
|
20
|
-
React.createElement(TabsList, null, tabInfo.map(e => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
React.createElement(TabsContent, { value: "
|
|
31
|
-
React.createElement(
|
|
32
|
-
React.createElement(TabsContent, { value: "
|
|
33
|
-
React.createElement(
|
|
34
|
-
React.createElement(TabsContent, { value: "identifyPanel", className: "jgis-panel-tab-content" },
|
|
35
|
-
React.createElement(IdentifyPanelComponent, { model: props.model })))));
|
|
50
|
+
React.createElement(TabsList, null, tabInfo.map(e => (React.createElement(TabsTrigger, { className: "jGIS-layer-browser-category", value: e.name, onClick: () => {
|
|
51
|
+
if (curTab !== e.name) {
|
|
52
|
+
setCurTab(e.name);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
setCurTab('');
|
|
56
|
+
}
|
|
57
|
+
} }, e.title)))),
|
|
58
|
+
!settings.objectPropertiesDisabled && (React.createElement(TabsContent, { value: "objectProperties", className: "jgis-panel-tab-content" },
|
|
59
|
+
React.createElement(ObjectPropertiesReact, { setSelectedObject: setSelectedObjectProperties, selectedObject: selectedObjectProperties, formSchemaRegistry: props.formSchemaRegistry, model: props.model }))),
|
|
60
|
+
!settings.annotationsDisabled && (React.createElement(TabsContent, { value: "annotations", className: "jgis-panel-tab-content" },
|
|
61
|
+
React.createElement(AnnotationsPanel, { annotationModel: props.annotationModel, jgisModel: props.model }))),
|
|
62
|
+
!settings.identifyDisabled && (React.createElement(TabsContent, { value: "identifyPanel", className: "jgis-panel-tab-content" },
|
|
63
|
+
React.createElement(IdentifyPanelComponent, { model: props.model }))))));
|
|
36
64
|
};
|
package/lib/tools.d.ts
CHANGED
|
@@ -72,7 +72,11 @@ export declare const loadGeoTiff: (sourceInfo: {
|
|
|
72
72
|
file: any;
|
|
73
73
|
metadata: any;
|
|
74
74
|
sourceUrl: string;
|
|
75
|
-
} |
|
|
75
|
+
} | {
|
|
76
|
+
file: Blob;
|
|
77
|
+
sourceUrl: string;
|
|
78
|
+
metadata?: undefined;
|
|
79
|
+
} | null>;
|
|
76
80
|
/**
|
|
77
81
|
* Generalized file reader for different source types.
|
|
78
82
|
*
|
package/lib/tools.js
CHANGED
|
@@ -353,6 +353,10 @@ export const loadGeoTiff = async (sourceInfo, model, file) => {
|
|
|
353
353
|
else {
|
|
354
354
|
fileBlob = await base64ToBlob(file.content, mimeType);
|
|
355
355
|
}
|
|
356
|
+
return {
|
|
357
|
+
file: fileBlob,
|
|
358
|
+
sourceUrl: url,
|
|
359
|
+
};
|
|
356
360
|
};
|
|
357
361
|
/**
|
|
358
362
|
* Generalized file reader for different source types.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jupytergis/base",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "A JupyterLab extension for 3D modelling.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -40,11 +40,11 @@
|
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@fortawesome/fontawesome-svg-core": "^6.5.2",
|
|
42
42
|
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
|
43
|
-
"@fortawesome/react-fontawesome": "
|
|
43
|
+
"@fortawesome/react-fontawesome": ">=0.2.6 <3.0.0",
|
|
44
44
|
"@jupyter/collaboration": "^3.1.0",
|
|
45
45
|
"@jupyter/react-components": "^0.16.6",
|
|
46
46
|
"@jupyter/ydoc": "^2.0.0 || ^3.0.0",
|
|
47
|
-
"@jupytergis/schema": "^0.
|
|
47
|
+
"@jupytergis/schema": "^0.9.0",
|
|
48
48
|
"@jupyterlab/application": "^4.3.0",
|
|
49
49
|
"@jupyterlab/apputils": "^4.3.0",
|
|
50
50
|
"@jupyterlab/completer": "^4.3.0",
|
package/style/base.css
CHANGED
|
@@ -101,3 +101,23 @@ button.jp-mod-styled.jp-mod-reject {
|
|
|
101
101
|
left: 0px;
|
|
102
102
|
margin: 5px;
|
|
103
103
|
}
|
|
104
|
+
|
|
105
|
+
@media (max-width: 768px) {
|
|
106
|
+
.jgis-panels-wrapper {
|
|
107
|
+
position: fixed;
|
|
108
|
+
top: 30px;
|
|
109
|
+
display: flex;
|
|
110
|
+
flex-direction: column;
|
|
111
|
+
align-items: flex-start;
|
|
112
|
+
gap: 10px;
|
|
113
|
+
margin: 0 5px;
|
|
114
|
+
z-index: 1000;
|
|
115
|
+
width: 60%;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.jgis-left-panel-container,
|
|
119
|
+
.jgis-right-panel-container {
|
|
120
|
+
position: relative;
|
|
121
|
+
margin: 0;
|
|
122
|
+
}
|
|
123
|
+
}
|