@jupytergis/base 0.9.2 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/annotations/components/Annotation.js +1 -1
- package/lib/commands/BaseCommandIDs.d.ts +1 -0
- package/lib/commands/BaseCommandIDs.js +2 -0
- package/lib/commands/index.js +31 -73
- package/lib/constants.js +2 -1
- package/lib/dialogs/ProcessingFormDialog.js +2 -2
- package/lib/dialogs/symbology/colorRampUtils.d.ts +2 -1
- package/lib/dialogs/symbology/colorRampUtils.js +10 -4
- package/lib/dialogs/symbology/components/color_ramp/ColorRampControls.d.ts +36 -0
- package/lib/dialogs/symbology/components/color_ramp/ColorRampControls.js +82 -0
- package/lib/dialogs/symbology/components/color_ramp/ColorRampSelector.d.ts +20 -0
- package/lib/dialogs/symbology/components/color_ramp/{CanvasSelectComponent.js → ColorRampSelector.js} +25 -7
- package/lib/dialogs/symbology/components/color_ramp/ColorRampSelectorEntry.d.ts +20 -0
- package/lib/dialogs/symbology/components/color_ramp/{ColorRampEntry.js → ColorRampSelectorEntry.js} +17 -3
- package/lib/dialogs/symbology/components/color_ramp/ModeSelectRow.d.ts +6 -5
- package/lib/dialogs/symbology/components/color_ramp/ModeSelectRow.js +7 -2
- package/lib/dialogs/symbology/hooks/useGetProperties.js +12 -6
- package/lib/dialogs/symbology/symbologyUtils.d.ts +2 -1
- package/lib/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.js +8 -4
- package/lib/dialogs/symbology/vector_layer/VectorRendering.js +2 -2
- package/lib/dialogs/symbology/vector_layer/types/Categorized.js +4 -5
- package/lib/dialogs/symbology/vector_layer/types/Graduated.js +16 -28
- package/lib/dialogs/symbology/vector_layer/types/Heatmap.js +3 -3
- package/lib/formbuilder/editform.js +4 -3
- package/lib/formbuilder/objectform/layer/heatmapLayerForm.d.ts +2 -1
- package/lib/formbuilder/objectform/layer/heatmapLayerForm.js +4 -0
- package/lib/formbuilder/objectform/layer/vectorlayerform.d.ts +2 -1
- package/lib/formbuilder/objectform/layer/vectorlayerform.js +4 -0
- package/lib/formbuilder/objectform/layer/webGlLayerForm.d.ts +2 -0
- package/lib/formbuilder/objectform/layer/webGlLayerForm.js +4 -0
- package/lib/icons.d.ts +1 -0
- package/lib/icons.js +5 -0
- package/lib/index.d.ts +0 -1
- package/lib/index.js +0 -1
- package/lib/mainview/mainView.d.ts +1 -0
- package/lib/mainview/mainView.js +62 -12
- package/lib/panelview/annotationPanel.js +1 -1
- package/lib/panelview/components/filter-panel/Filter.js +1 -1
- package/lib/panelview/components/layers.js +152 -51
- package/lib/panelview/components/legendItem.js +36 -1
- package/lib/panelview/leftpanel.d.ts +0 -1
- package/lib/panelview/leftpanel.js +4 -4
- package/lib/panelview/rightpanel.js +4 -4
- package/lib/processing/processingFormToParam.js +3 -0
- package/lib/shared/components/ToggleGroup.d.ts +2 -2
- package/lib/stacBrowser/hooks/useStacSearch.js +2 -2
- package/lib/toolbar/widget.js +19 -28
- package/lib/tools.d.ts +1 -0
- package/lib/tools.js +2 -2
- package/lib/types.d.ts +2 -0
- package/lib/types.js +8 -0
- package/package.json +2 -2
- package/style/base.css +2 -0
- package/style/icons/book_open.svg +1 -1
- package/style/icons/clock-solid.svg +1 -1
- package/style/icons/geolocation.svg +1 -1
- package/style/icons/info-solid.svg +1 -1
- package/style/icons/logo_mini.svg +1 -1
- package/style/icons/marker.svg +5 -0
- package/style/icons/target_without_center.svg +1 -1
- package/style/icons/vector_square.svg +1 -1
- package/style/shared/tabs.css +1 -0
- package/style/symbologyDialog.css +12 -4
- package/lib/classificationModes.d.ts +0 -13
- package/lib/classificationModes.js +0 -326
- package/lib/dialogs/symbology/components/color_ramp/CanvasSelectComponent.d.ts +0 -11
- package/lib/dialogs/symbology/components/color_ramp/ColorRamp.d.ts +0 -16
- package/lib/dialogs/symbology/components/color_ramp/ColorRamp.js +0 -34
- package/lib/dialogs/symbology/components/color_ramp/ColorRampEntry.d.ts +0 -9
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { IJGISLayer } from '@jupytergis/schema';
|
|
2
|
+
import { ColorRampName } from './colorRampUtils';
|
|
2
3
|
import { IStopRow } from './symbologyDialog';
|
|
3
4
|
export declare namespace VectorUtils {
|
|
4
5
|
const buildColorInfo: (layer: IJGISLayer) => IStopRow[];
|
|
5
6
|
const buildRadiusInfo: (layer: IJGISLayer) => IStopRow[];
|
|
6
7
|
}
|
|
7
8
|
export declare namespace Utils {
|
|
8
|
-
const getValueColorPairs: (stops: number[], selectedRamp:
|
|
9
|
+
const getValueColorPairs: (stops: number[], selectedRamp: ColorRampName, nClasses: number, reverse?: boolean) => IStopRow[];
|
|
9
10
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Button } from '@jupyterlab/ui-components';
|
|
2
2
|
import React, { useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { GeoTiffClassifications } from "../../classificationModes";
|
|
4
|
-
import
|
|
4
|
+
import ColorRampControls from "../../components/color_ramp/ColorRampControls";
|
|
5
5
|
import StopRow from "../../components/color_stops/StopRow";
|
|
6
6
|
import useGetBandInfo from "../../hooks/useGetBandInfo";
|
|
7
7
|
import { Utils } from "../../symbologyUtils";
|
|
@@ -17,7 +17,11 @@ const SingleBandPseudoColor = ({ model, okSignalPromise, cancel, layerId, }) =>
|
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
19
|
const functions = ['discrete', 'linear', 'exact'];
|
|
20
|
-
const modeOptions = [
|
|
20
|
+
const modeOptions = [
|
|
21
|
+
'continuous',
|
|
22
|
+
'equal interval',
|
|
23
|
+
'quantile',
|
|
24
|
+
];
|
|
21
25
|
const stateDb = GlobalStateDbManager.getInstance().getStateDb();
|
|
22
26
|
const { bandRows, setBandRows, loading } = useGetBandInfo(model, layer);
|
|
23
27
|
const [layerState, setLayerState] = useState();
|
|
@@ -223,7 +227,7 @@ const SingleBandPseudoColor = ({ model, okSignalPromise, cancel, layerId, }) =>
|
|
|
223
227
|
const currentBand = bandRows[selectedBand - 1];
|
|
224
228
|
const source = model.getSource((_a = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _a === void 0 ? void 0 : _a.source);
|
|
225
229
|
const sourceInfo = (_b = source === null || source === void 0 ? void 0 : source.parameters) === null || _b === void 0 ? void 0 : _b.urls[0];
|
|
226
|
-
const nClasses = selectedMode === 'continuous' ? 52 :
|
|
230
|
+
const nClasses = selectedMode === 'continuous' ? 52 : numberOfShades;
|
|
227
231
|
setIsLoading(true);
|
|
228
232
|
switch (selectedMode) {
|
|
229
233
|
case 'quantile':
|
|
@@ -270,7 +274,7 @@ const SingleBandPseudoColor = ({ model, okSignalPromise, cancel, layerId, }) =>
|
|
|
270
274
|
React.createElement("select", { name: "function-select", id: "function-select", className: "jp-mod-styled", value: selectedFunction, style: { textTransform: 'capitalize' }, onChange: event => {
|
|
271
275
|
setSelectedFunction(event.target.value);
|
|
272
276
|
} }, functions.map((func, funcIndex) => (React.createElement("option", { key: func, value: func, style: { textTransform: 'capitalize' } }, func)))))),
|
|
273
|
-
bandRows.length > 0 && (React.createElement(
|
|
277
|
+
bandRows.length > 0 && (React.createElement(ColorRampControls, { layerParams: layer.parameters, modeOptions: modeOptions, classifyFunc: buildColorInfoFromClassification, showModeRow: true, showRampSelector: true })),
|
|
274
278
|
React.createElement("div", { className: "jp-gis-stop-container" },
|
|
275
279
|
React.createElement("div", { className: "jp-gis-stop-labels", style: { display: 'flex', gap: 6 } },
|
|
276
280
|
React.createElement("span", { style: { flex: '0 0 18%' } },
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react';
|
|
2
2
|
import { useGetProperties } from "../hooks/useGetProperties";
|
|
3
|
-
import { getColorCodeFeatureAttributes, getNumericFeatureAttributes, objectEntries, } from "../../../tools";
|
|
3
|
+
import { getColorCodeFeatureAttributes, getFeatureAttributes, getNumericFeatureAttributes, objectEntries, } from "../../../tools";
|
|
4
4
|
import Canonical from './types/Canonical';
|
|
5
5
|
import Categorized from './types/Categorized';
|
|
6
6
|
import Graduated from './types/Graduated';
|
|
@@ -26,7 +26,7 @@ const RENDER_TYPE_OPTIONS = {
|
|
|
26
26
|
},
|
|
27
27
|
Categorized: {
|
|
28
28
|
component: Categorized,
|
|
29
|
-
attributeChecker:
|
|
29
|
+
attributeChecker: getFeatureAttributes,
|
|
30
30
|
supportedLayerTypes: ['VectorLayer', 'VectorTileLayer', 'HeatmapLayer'],
|
|
31
31
|
isTabbed: true,
|
|
32
32
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
-
import
|
|
2
|
+
import ColorRampControls from "../../components/color_ramp/ColorRampControls";
|
|
3
3
|
import StopContainer from "../../components/color_stops/StopContainer";
|
|
4
4
|
import { Utils, VectorUtils } from "../../symbologyUtils";
|
|
5
5
|
import ValueSelect from "../components/ValueSelect";
|
|
@@ -82,8 +82,8 @@ const Categorized = ({ model, state, okSignalPromise, cancel, layerId, symbology
|
|
|
82
82
|
setColorRampOptions({
|
|
83
83
|
selectedFunction: '',
|
|
84
84
|
selectedRamp,
|
|
85
|
-
numberOfShades
|
|
86
|
-
selectedMode
|
|
85
|
+
numberOfShades,
|
|
86
|
+
selectedMode,
|
|
87
87
|
});
|
|
88
88
|
const stops = Array.from(selectableAttributesAndValues[selectedAttribute]).sort((a, b) => a - b);
|
|
89
89
|
const valueColorPairs = Utils.getValueColorPairs(stops, selectedRamp, stops.length, reverseRamp);
|
|
@@ -141,7 +141,6 @@ const Categorized = ({ model, state, okSignalPromise, cancel, layerId, symbology
|
|
|
141
141
|
}
|
|
142
142
|
const newStyle = Object.assign({}, layer.parameters.color);
|
|
143
143
|
if (method === 'color') {
|
|
144
|
-
console.log('delecol');
|
|
145
144
|
delete newStyle['fill-color'];
|
|
146
145
|
delete newStyle['stroke-color'];
|
|
147
146
|
delete newStyle['circle-fill-color'];
|
|
@@ -195,7 +194,7 @@ const Categorized = ({ model, state, okSignalPromise, cancel, layerId, symbology
|
|
|
195
194
|
React.createElement("input", { type: "checkbox", checked: reverseRamp, onChange: e => setReverseRamp(e.target.checked) }),
|
|
196
195
|
"Reverse Color Ramp"))),
|
|
197
196
|
React.createElement("div", { className: "jp-gis-layer-symbology-container" },
|
|
198
|
-
React.createElement(
|
|
197
|
+
React.createElement(ColorRampControls, { layerParams: layer.parameters, modeOptions: [], classifyFunc: buildColorInfoFromClassification, showModeRow: false, showRampSelector: symbologyTab === 'color' }),
|
|
199
198
|
React.createElement(StopContainer, { selectedMethod: '', stopRows: stopRows, setStopRows: setStopRows }))));
|
|
200
199
|
}
|
|
201
200
|
})();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { VectorClassifications } from "../../classificationModes";
|
|
3
|
-
import
|
|
3
|
+
import ColorRampControls from "../../components/color_ramp/ColorRampControls";
|
|
4
4
|
import StopContainer from "../../components/color_stops/StopContainer";
|
|
5
5
|
import { Utils, VectorUtils } from "../../symbologyUtils";
|
|
6
6
|
import ValueSelect from "../components/ValueSelect";
|
|
@@ -22,7 +22,6 @@ const Graduated = ({ model, state, okSignalPromise, cancel, layerId, symbologyTa
|
|
|
22
22
|
const [radiusStopRows, setRadiusStopRows] = useState([]);
|
|
23
23
|
const [colorRampOptions, setColorRampOptions] = useState();
|
|
24
24
|
const [colorManualStyle, setColorManualStyle] = useState({
|
|
25
|
-
fillColor: '#3399CC',
|
|
26
25
|
strokeColor: '#3399CC',
|
|
27
26
|
strokeWidth: 1.25,
|
|
28
27
|
});
|
|
@@ -53,17 +52,10 @@ const Graduated = ({ model, state, okSignalPromise, cancel, layerId, symbologyTa
|
|
|
53
52
|
useEffect(() => {
|
|
54
53
|
var _a;
|
|
55
54
|
if ((_a = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _a === void 0 ? void 0 : _a.color) {
|
|
56
|
-
const fillColor = layer.parameters.color['fill-color'];
|
|
57
|
-
const circleFillColor = layer.parameters.color['circle-fill-color'];
|
|
58
55
|
const strokeColor = layer.parameters.color['stroke-color'];
|
|
59
56
|
const circleStrokeColor = layer.parameters.color['circle-stroke-color'];
|
|
60
57
|
const isSimpleColor = (val) => typeof val === 'string' && /^#?[0-9A-Fa-f]{3,8}$/.test(val);
|
|
61
58
|
setColorManualStyle({
|
|
62
|
-
fillColor: isSimpleColor(fillColor)
|
|
63
|
-
? fillColor
|
|
64
|
-
: isSimpleColor(circleFillColor)
|
|
65
|
-
? circleFillColor
|
|
66
|
-
: '#3399CC',
|
|
67
59
|
strokeColor: isSimpleColor(strokeColor)
|
|
68
60
|
? strokeColor
|
|
69
61
|
: isSimpleColor(circleStrokeColor)
|
|
@@ -131,11 +123,10 @@ const Graduated = ({ model, state, okSignalPromise, cancel, layerId, symbologyTa
|
|
|
131
123
|
newStyle['circle-stroke-color'] = colorExpr;
|
|
132
124
|
}
|
|
133
125
|
else {
|
|
134
|
-
|
|
135
|
-
newStyle['circle-fill-color'] = undefined;
|
|
136
|
-
newStyle['stroke-color'] = colorManualStyleRef.current.strokeColor;
|
|
137
|
-
newStyle['circle-stroke-color'] = colorManualStyleRef.current.strokeColor;
|
|
126
|
+
// use manual style
|
|
138
127
|
}
|
|
128
|
+
newStyle['stroke-color'] = colorManualStyleRef.current.strokeColor;
|
|
129
|
+
newStyle['circle-stroke-color'] = colorManualStyleRef.current.strokeColor;
|
|
139
130
|
newStyle['stroke-width'] = colorManualStyleRef.current.strokeWidth;
|
|
140
131
|
newStyle['circle-stroke-width'] = colorManualStyleRef.current.strokeWidth;
|
|
141
132
|
// Apply radius symbology
|
|
@@ -180,19 +171,19 @@ const Graduated = ({ model, state, okSignalPromise, cancel, layerId, symbologyTa
|
|
|
180
171
|
const values = Array.from(selectableAttributesAndValues[selectedAttribute]);
|
|
181
172
|
switch (selectedMode) {
|
|
182
173
|
case 'quantile':
|
|
183
|
-
stops = VectorClassifications.calculateQuantileBreaks(values,
|
|
174
|
+
stops = VectorClassifications.calculateQuantileBreaks(values, numberOfShades);
|
|
184
175
|
break;
|
|
185
176
|
case 'equal interval':
|
|
186
|
-
stops = VectorClassifications.calculateEqualIntervalBreaks(values,
|
|
177
|
+
stops = VectorClassifications.calculateEqualIntervalBreaks(values, numberOfShades);
|
|
187
178
|
break;
|
|
188
179
|
case 'jenks':
|
|
189
|
-
stops = VectorClassifications.calculateJenksBreaks(values,
|
|
180
|
+
stops = VectorClassifications.calculateJenksBreaks(values, numberOfShades);
|
|
190
181
|
break;
|
|
191
182
|
case 'pretty':
|
|
192
|
-
stops = VectorClassifications.calculatePrettyBreaks(values,
|
|
183
|
+
stops = VectorClassifications.calculatePrettyBreaks(values, numberOfShades);
|
|
193
184
|
break;
|
|
194
185
|
case 'logarithmic':
|
|
195
|
-
stops = VectorClassifications.calculateLogarithmicBreaks(values,
|
|
186
|
+
stops = VectorClassifications.calculateLogarithmicBreaks(values, numberOfShades);
|
|
196
187
|
break;
|
|
197
188
|
default:
|
|
198
189
|
console.warn('No mode selected');
|
|
@@ -200,7 +191,7 @@ const Graduated = ({ model, state, okSignalPromise, cancel, layerId, symbologyTa
|
|
|
200
191
|
}
|
|
201
192
|
const stopOutputPairs = symbologyTab === 'radius'
|
|
202
193
|
? stops.map(v => ({ stop: v, output: v }))
|
|
203
|
-
: Utils.getValueColorPairs(stops, selectedRamp,
|
|
194
|
+
: Utils.getValueColorPairs(stops, selectedRamp, numberOfShades, reverseRamp);
|
|
204
195
|
if (symbologyTab === 'radius') {
|
|
205
196
|
setRadiusStopRows(stopOutputPairs);
|
|
206
197
|
}
|
|
@@ -214,9 +205,7 @@ const Graduated = ({ model, state, okSignalPromise, cancel, layerId, symbologyTa
|
|
|
214
205
|
}
|
|
215
206
|
const newStyle = Object.assign({}, layer.parameters.color);
|
|
216
207
|
if (method === 'color') {
|
|
217
|
-
delete newStyle['fill-color'];
|
|
218
208
|
delete newStyle['stroke-color'];
|
|
219
|
-
delete newStyle['circle-fill-color'];
|
|
220
209
|
setColorStopRows([]);
|
|
221
210
|
setColorRampOptions(undefined);
|
|
222
211
|
}
|
|
@@ -237,12 +226,11 @@ const Graduated = ({ model, state, okSignalPromise, cancel, layerId, symbologyTa
|
|
|
237
226
|
React.createElement(ValueSelect, { featureProperties: selectableAttributesAndValues, selectedValue: selectedAttribute, setSelectedValue: setSelectedAttribute }),
|
|
238
227
|
React.createElement("div", { className: "jp-gis-layer-symbology-container" },
|
|
239
228
|
symbologyTab === 'color' && (React.createElement(React.Fragment, null,
|
|
240
|
-
React.createElement("
|
|
241
|
-
|
|
242
|
-
React.createElement("
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
} })),
|
|
229
|
+
React.createElement("p", { className: "jp-info-text" },
|
|
230
|
+
"Fill color is automatically controlled by the color ramp. To control fill manually, switch to ",
|
|
231
|
+
React.createElement("strong", null, "Simple"),
|
|
232
|
+
' ',
|
|
233
|
+
"symbology."),
|
|
246
234
|
React.createElement("div", { className: "jp-gis-symbology-row" },
|
|
247
235
|
React.createElement("label", null, "Stroke Color:"),
|
|
248
236
|
React.createElement("input", { type: "color", className: "jp-mod-styled", value: colorManualStyle.strokeColor, onChange: e => {
|
|
@@ -263,7 +251,7 @@ const Graduated = ({ model, state, okSignalPromise, cancel, layerId, symbologyTa
|
|
|
263
251
|
React.createElement("label", null,
|
|
264
252
|
React.createElement("input", { type: "checkbox", checked: reverseRamp, onChange: e => setReverseRamp(e.target.checked) }),
|
|
265
253
|
"Reverse Color Ramp"))),
|
|
266
|
-
React.createElement(
|
|
254
|
+
React.createElement(ColorRampControls, { layerParams: layer.parameters, modeOptions: modeOptions, classifyFunc: buildColorInfoFromClassification, showModeRow: true, showRampSelector: symbologyTab === 'color' }),
|
|
267
255
|
React.createElement(StopContainer, { selectedMethod: symbologyTab || 'color', stopRows: symbologyTab === 'color' ? colorStopRows : radiusStopRows, setStopRows: symbologyTab === 'color' ? setColorStopRows : setRadiusStopRows })));
|
|
268
256
|
}
|
|
269
257
|
})();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import colormap from 'colormap';
|
|
2
2
|
import React, { useEffect, useRef, useState } from 'react';
|
|
3
|
-
import
|
|
3
|
+
import ColorRampSelector from "../../components/color_ramp/ColorRampSelector";
|
|
4
4
|
const Heatmap = ({ model, state, okSignalPromise, cancel, layerId, }) => {
|
|
5
5
|
if (!layerId) {
|
|
6
6
|
return;
|
|
@@ -9,7 +9,7 @@ const Heatmap = ({ model, state, okSignalPromise, cancel, layerId, }) => {
|
|
|
9
9
|
if (!(layer === null || layer === void 0 ? void 0 : layer.parameters)) {
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
|
-
const [selectedRamp, setSelectedRamp] = useState('');
|
|
12
|
+
const [selectedRamp, setSelectedRamp] = useState('viridis');
|
|
13
13
|
const [heatmapOptions, setHetamapOptions] = useState({
|
|
14
14
|
radius: 8,
|
|
15
15
|
blur: 15,
|
|
@@ -74,7 +74,7 @@ const Heatmap = ({ model, state, okSignalPromise, cancel, layerId, }) => {
|
|
|
74
74
|
React.createElement("p", null, "Represent features based on their density using a heatmap."),
|
|
75
75
|
React.createElement("div", { className: "jp-gis-symbology-row jp-gis-heatmap" },
|
|
76
76
|
React.createElement("label", { htmlFor: "color-ramp-select" }, "Color Ramp:"),
|
|
77
|
-
React.createElement(
|
|
77
|
+
React.createElement(ColorRampSelector, { selectedRamp: selectedRamp, setSelected: setSelectedRamp })),
|
|
78
78
|
React.createElement("div", { className: "jp-gis-symbology-row" },
|
|
79
79
|
React.createElement("label", null,
|
|
80
80
|
React.createElement("input", { type: "checkbox", checked: reverseRamp, onChange: e => setReverseRamp(e.target.checked) }),
|
|
@@ -20,8 +20,9 @@ export class EditForm extends React.Component {
|
|
|
20
20
|
let layerSchema = undefined;
|
|
21
21
|
let LayerForm = undefined;
|
|
22
22
|
let layerData = undefined;
|
|
23
|
+
let layer = undefined;
|
|
23
24
|
if (this.props.layer) {
|
|
24
|
-
|
|
25
|
+
layer = this.props.model.getLayer(this.props.layer);
|
|
25
26
|
if (!layer) {
|
|
26
27
|
return;
|
|
27
28
|
}
|
|
@@ -53,12 +54,12 @@ export class EditForm extends React.Component {
|
|
|
53
54
|
return (React.createElement("div", null,
|
|
54
55
|
this.props.layer && LayerForm && (React.createElement("div", null,
|
|
55
56
|
React.createElement("h3", { style: { paddingLeft: '5px' } }, "Layer Properties"),
|
|
56
|
-
React.createElement(LayerForm, { formContext: "update", sourceType: (source === null || source === void 0 ? void 0 : source.type) || 'RasterSource', model: this.props.model, filePath: this.props.model.filePath, schema: layerSchema, sourceData: layerData, syncData: (properties) => {
|
|
57
|
+
React.createElement(LayerForm, { key: `${this.props.layer}-${source === null || source === void 0 ? void 0 : source.type}`, formContext: "update", sourceType: (source === null || source === void 0 ? void 0 : source.type) || 'RasterSource', model: this.props.model, filePath: this.props.model.filePath, schema: layerSchema, sourceData: layerData, syncData: (properties) => {
|
|
57
58
|
this.syncObjectProperties(this.props.layer, properties);
|
|
58
59
|
} }))),
|
|
59
60
|
this.props.source && SourceForm && (React.createElement("div", null,
|
|
60
61
|
React.createElement("h3", { style: { paddingLeft: '5px' } }, "Source Properties"),
|
|
61
|
-
React.createElement(SourceForm, { formContext: "update", model: this.props.model, filePath: this.props.model.filePath, schema: sourceSchema, sourceData: sourceData, syncData: (properties) => {
|
|
62
|
+
React.createElement(SourceForm, { key: `${this.props.source}-${layer === null || layer === void 0 ? void 0 : layer.type}`, formContext: "update", model: this.props.model, filePath: this.props.model.filePath, schema: sourceSchema, sourceData: sourceData, syncData: (properties) => {
|
|
62
63
|
this.syncObjectProperties(this.props.source, properties);
|
|
63
64
|
}, formChangedSignal: this.sourceFormChangedSignal, sourceType: (source === null || source === void 0 ? void 0 : source.type) || 'RasterSource' })))));
|
|
64
65
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { IDict, IHeatmapLayer } from '@jupytergis/schema';
|
|
2
|
-
import { IChangeEvent } from '@rjsf/core';
|
|
2
|
+
import { IChangeEvent, ISubmitEvent } from '@rjsf/core';
|
|
3
3
|
import { ILayerProps, LayerPropertiesForm } from './layerform';
|
|
4
4
|
export declare class HeatmapLayerPropertiesForm extends LayerPropertiesForm {
|
|
5
5
|
protected currentFormData: IHeatmapLayer;
|
|
6
6
|
private features;
|
|
7
7
|
constructor(props: ILayerProps);
|
|
8
|
+
protected onFormSubmit(e: ISubmitEvent<any>): void;
|
|
8
9
|
protected onFormChange(e: IChangeEvent): void;
|
|
9
10
|
protected processSchema(data: IDict<any> | undefined, schema: IDict, uiSchema: IDict): void;
|
|
10
11
|
private fetchFeatureNames;
|
|
@@ -13,6 +13,10 @@ export class HeatmapLayerPropertiesForm extends LayerPropertiesForm {
|
|
|
13
13
|
});
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
+
onFormSubmit(e) {
|
|
17
|
+
e.formData.symbologyState = {};
|
|
18
|
+
return super.onFormSubmit(e);
|
|
19
|
+
}
|
|
16
20
|
onFormChange(e) {
|
|
17
21
|
super.onFormChange(e);
|
|
18
22
|
const source = this.props.model.getSource(e.formData.source);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IDict, IVectorLayer } from '@jupytergis/schema';
|
|
2
|
-
import { IChangeEvent } from '@rjsf/core';
|
|
2
|
+
import { IChangeEvent, ISubmitEvent } from '@rjsf/core';
|
|
3
3
|
import { ILayerProps, LayerPropertiesForm } from './layerform';
|
|
4
4
|
/**
|
|
5
5
|
* The form to modify a vector layer.
|
|
@@ -8,6 +8,7 @@ export declare class VectorLayerPropertiesForm extends LayerPropertiesForm {
|
|
|
8
8
|
protected currentFormData: IVectorLayer;
|
|
9
9
|
private currentSourceId;
|
|
10
10
|
constructor(props: ILayerProps);
|
|
11
|
+
protected onFormSubmit(e: ISubmitEvent<any>): void;
|
|
11
12
|
protected onFormChange(e: IChangeEvent): void;
|
|
12
13
|
protected processSchema(data: IVectorLayer | undefined, schema: IDict, uiSchema: IDict): void;
|
|
13
14
|
}
|
|
@@ -6,6 +6,10 @@ export class VectorLayerPropertiesForm extends LayerPropertiesForm {
|
|
|
6
6
|
constructor(props) {
|
|
7
7
|
super(props);
|
|
8
8
|
}
|
|
9
|
+
onFormSubmit(e) {
|
|
10
|
+
e.formData.symbologyState = {};
|
|
11
|
+
return super.onFormSubmit(e);
|
|
12
|
+
}
|
|
9
13
|
onFormChange(e) {
|
|
10
14
|
super.onFormChange(e);
|
|
11
15
|
// We only force update if we just updated the source
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { IDict } from '@jupytergis/schema';
|
|
2
|
+
import { ISubmitEvent } from '@rjsf/core';
|
|
2
3
|
import { LayerPropertiesForm } from './layerform';
|
|
3
4
|
/**
|
|
4
5
|
* The form to modify a hillshade layer.
|
|
5
6
|
*/
|
|
6
7
|
export declare class WebGlLayerPropertiesForm extends LayerPropertiesForm {
|
|
8
|
+
protected onFormSubmit(e: ISubmitEvent<any>): void;
|
|
7
9
|
protected processSchema(data: IDict<any> | undefined, schema: IDict, uiSchema: IDict): void;
|
|
8
10
|
}
|
|
@@ -3,6 +3,10 @@ import { LayerPropertiesForm } from './layerform';
|
|
|
3
3
|
* The form to modify a hillshade layer.
|
|
4
4
|
*/
|
|
5
5
|
export class WebGlLayerPropertiesForm extends LayerPropertiesForm {
|
|
6
|
+
onFormSubmit(e) {
|
|
7
|
+
e.formData.symbologyState = {};
|
|
8
|
+
return super.onFormSubmit(e);
|
|
9
|
+
}
|
|
6
10
|
processSchema(data, schema, uiSchema) {
|
|
7
11
|
this.removeFormEntry('color', data, schema, uiSchema);
|
|
8
12
|
this.removeFormEntry('symbologyState', data, schema, uiSchema);
|
package/lib/icons.d.ts
CHANGED
package/lib/icons.js
CHANGED
|
@@ -13,6 +13,7 @@ import logoSvgStr from '../style/icons/logo.svg';
|
|
|
13
13
|
import logoMiniSvgStr from '../style/icons/logo_mini.svg';
|
|
14
14
|
import logoMiniAlternativeSvgStr from '../style/icons/logo_mini_alternative.svg';
|
|
15
15
|
import logoMiniQGZ from '../style/icons/logo_mini_qgz.svg';
|
|
16
|
+
import markerSvgStr from '../style/icons/marker.svg';
|
|
16
17
|
import moundSvgStr from '../style/icons/mound.svg';
|
|
17
18
|
import nonVisibilitySvgStr from '../style/icons/nonvisibility.svg';
|
|
18
19
|
import rasterSvgStr from '../style/icons/raster.svg';
|
|
@@ -89,3 +90,7 @@ export const targetWithCenterIcon = new LabIcon({
|
|
|
89
90
|
name: 'jupytergis::targetWithoutCenter',
|
|
90
91
|
svgstr: targetWithoutCenterSvgStr,
|
|
91
92
|
});
|
|
93
|
+
export const markerIcon = new LabIcon({
|
|
94
|
+
name: 'jupytergis::marker',
|
|
95
|
+
svgstr: markerSvgStr,
|
|
96
|
+
});
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -175,6 +175,7 @@ export declare class MainView extends React.Component<IProps, IStates> {
|
|
|
175
175
|
private _flyToPosition;
|
|
176
176
|
private _onPointerMove;
|
|
177
177
|
private _syncPointer;
|
|
178
|
+
private _addMarker;
|
|
178
179
|
private _identifyFeature;
|
|
179
180
|
private _triggerLayerUpdate;
|
|
180
181
|
private _convertFeatureToMs;
|
package/lib/mainview/mainView.js
CHANGED
|
@@ -28,7 +28,7 @@ import { register } from 'ol/proj/proj4.js';
|
|
|
28
28
|
import RenderFeature, { toGeometry } from 'ol/render/Feature';
|
|
29
29
|
import { GeoTIFF as GeoTIFFSource, ImageTile as ImageTileSource, Vector as VectorSource, VectorTile as VectorTileSource, XYZ as XYZSource, Tile as TileSource, } from 'ol/source';
|
|
30
30
|
import Static from 'ol/source/ImageStatic';
|
|
31
|
-
import { Circle, Fill, Stroke, Style } from 'ol/style';
|
|
31
|
+
import { Circle, Fill, Icon, Stroke, Style } from 'ol/style';
|
|
32
32
|
//@ts-expect-error no types for ol-pmtiles
|
|
33
33
|
import { PMTilesRasterSource, PMTilesVectorSource } from 'ol-pmtiles';
|
|
34
34
|
import StacLayer from 'ol-stac';
|
|
@@ -43,6 +43,7 @@ import { debounce, isLightTheme, loadFile, throttle } from "../tools";
|
|
|
43
43
|
import CollaboratorPointers from './CollaboratorPointers';
|
|
44
44
|
import { FollowIndicator } from './FollowIndicator';
|
|
45
45
|
import TemporalSlider from './TemporalSlider';
|
|
46
|
+
import { markerIcon } from '../icons';
|
|
46
47
|
import { LeftPanel, RightPanel } from '../panelview';
|
|
47
48
|
export class MainView extends React.Component {
|
|
48
49
|
constructor(props) {
|
|
@@ -642,6 +643,7 @@ export class MainView extends React.Component {
|
|
|
642
643
|
}
|
|
643
644
|
});
|
|
644
645
|
this._Map.on('click', this._identifyFeature.bind(this));
|
|
646
|
+
this._Map.on('click', this._addMarker.bind(this));
|
|
645
647
|
this._Map
|
|
646
648
|
.getViewport()
|
|
647
649
|
.addEventListener('pointermove', this._onPointerMove.bind(this));
|
|
@@ -860,6 +862,27 @@ export class MainView extends React.Component {
|
|
|
860
862
|
});
|
|
861
863
|
break;
|
|
862
864
|
}
|
|
865
|
+
case 'MarkerSource': {
|
|
866
|
+
const parameters = source.parameters;
|
|
867
|
+
const point = new Point(parameters.feature.coords);
|
|
868
|
+
const marker = new Feature({
|
|
869
|
+
type: 'icon',
|
|
870
|
+
geometry: point,
|
|
871
|
+
});
|
|
872
|
+
// Replace color placeholder in SVG with the parameter color
|
|
873
|
+
const markerColor = parameters.color || '#3463a0';
|
|
874
|
+
const svgString = markerIcon.svgstr.replace('{{COLOR}}', markerColor);
|
|
875
|
+
const iconStyle = new Style({
|
|
876
|
+
image: new Icon({
|
|
877
|
+
src: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`,
|
|
878
|
+
scale: 0.25,
|
|
879
|
+
}),
|
|
880
|
+
});
|
|
881
|
+
marker.setStyle(iconStyle);
|
|
882
|
+
newSource = new VectorSource({
|
|
883
|
+
features: [marker],
|
|
884
|
+
});
|
|
885
|
+
}
|
|
863
886
|
}
|
|
864
887
|
newSource.set('id', id);
|
|
865
888
|
// _sources is a list of OpenLayers sources
|
|
@@ -1429,15 +1452,11 @@ export class MainView extends React.Component {
|
|
|
1429
1452
|
return;
|
|
1430
1453
|
}
|
|
1431
1454
|
const layer = this.getLayer(id);
|
|
1432
|
-
let nextIndex = index;
|
|
1433
1455
|
// should not be undefined since the id exists above
|
|
1434
1456
|
if (layer === undefined) {
|
|
1435
1457
|
return;
|
|
1436
1458
|
}
|
|
1437
1459
|
this._Map.getLayers().removeAt(currentIndex);
|
|
1438
|
-
if (currentIndex < index) {
|
|
1439
|
-
nextIndex -= 1;
|
|
1440
|
-
}
|
|
1441
1460
|
// Adjust index to ensure it's within bounds
|
|
1442
1461
|
const numLayers = this._Map.getLayers().getLength();
|
|
1443
1462
|
const safeIndex = Math.min(index, numLayers);
|
|
@@ -1587,6 +1606,37 @@ export class MainView extends React.Component {
|
|
|
1587
1606
|
const coordinates = this._Map.getCoordinateFromPixel(pixel);
|
|
1588
1607
|
this._syncPointer(coordinates);
|
|
1589
1608
|
}
|
|
1609
|
+
async _addMarker(e) {
|
|
1610
|
+
if (this._model.currentMode !== 'marking') {
|
|
1611
|
+
return;
|
|
1612
|
+
}
|
|
1613
|
+
const coordinate = this._Map.getCoordinateFromPixel(e.pixel);
|
|
1614
|
+
const sourceId = UUID.uuid4();
|
|
1615
|
+
const layerId = UUID.uuid4();
|
|
1616
|
+
const sourceParameters = {
|
|
1617
|
+
feature: { coords: [coordinate[0], coordinate[1]] },
|
|
1618
|
+
};
|
|
1619
|
+
const layerParams = {
|
|
1620
|
+
opacity: 1.0,
|
|
1621
|
+
source: sourceId,
|
|
1622
|
+
symbologyState: { renderType: 'Single Symbol' },
|
|
1623
|
+
};
|
|
1624
|
+
const sourceModel = {
|
|
1625
|
+
type: 'MarkerSource',
|
|
1626
|
+
name: 'Marker',
|
|
1627
|
+
parameters: sourceParameters,
|
|
1628
|
+
};
|
|
1629
|
+
const layerModel = {
|
|
1630
|
+
type: 'VectorLayer',
|
|
1631
|
+
visible: true,
|
|
1632
|
+
name: 'Marker',
|
|
1633
|
+
parameters: layerParams,
|
|
1634
|
+
};
|
|
1635
|
+
this._model.sharedModel.addSource(sourceId, sourceModel);
|
|
1636
|
+
await this.addSource(sourceId, sourceModel);
|
|
1637
|
+
this._model.addLayer(layerId, layerModel);
|
|
1638
|
+
await this.addLayer(layerId, layerModel, this.getLayerIDs().length);
|
|
1639
|
+
}
|
|
1590
1640
|
_identifyFeature(e) {
|
|
1591
1641
|
var _a, _b;
|
|
1592
1642
|
if (this._model.currentMode !== 'identifying') {
|
|
@@ -1619,7 +1669,7 @@ export class MainView extends React.Component {
|
|
|
1619
1669
|
const rawProps = feature.getProperties();
|
|
1620
1670
|
const fid = (_b = (_a = feature.getId) === null || _a === void 0 ? void 0 : _a.call(feature)) !== null && _b !== void 0 ? _b : rawProps === null || rawProps === void 0 ? void 0 : rawProps.fid;
|
|
1621
1671
|
if (rawProps && Object.keys(rawProps).length > 1) {
|
|
1622
|
-
const
|
|
1672
|
+
const clean = __rest(rawProps, []);
|
|
1623
1673
|
props = clean;
|
|
1624
1674
|
if (fid !== null) {
|
|
1625
1675
|
// TODO Clean the cache under some condition?
|
|
@@ -1684,7 +1734,7 @@ export class MainView extends React.Component {
|
|
|
1684
1734
|
const { layerId, layer: jgisLayer } = json;
|
|
1685
1735
|
const olLayer = this.getLayer(layerId);
|
|
1686
1736
|
if (!jgisLayer || !olLayer) {
|
|
1687
|
-
console.
|
|
1737
|
+
console.error('Failed to update layer -- layer not found');
|
|
1688
1738
|
return;
|
|
1689
1739
|
}
|
|
1690
1740
|
this.updateLayer(layerId, jgisLayer, olLayer);
|
|
@@ -1736,10 +1786,10 @@ export class MainView extends React.Component {
|
|
|
1736
1786
|
React.createElement("div", { ref: this.divRef, style: {
|
|
1737
1787
|
width: '100%',
|
|
1738
1788
|
height: '100%',
|
|
1739
|
-
} }
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1789
|
+
} },
|
|
1790
|
+
React.createElement("div", { className: "jgis-panels-wrapper" },
|
|
1791
|
+
this._state && (React.createElement(LeftPanel, { model: this._model, commands: this._mainViewModel.commands, state: this._state })),
|
|
1792
|
+
this._formSchemaRegistry && this._annotationModel && (React.createElement(RightPanel, { model: this._model, formSchemaRegistry: this._formSchemaRegistry, annotationModel: this._annotationModel }))))),
|
|
1793
|
+
React.createElement(StatusBar, { jgisModel: this._model, loading: this.state.loadingLayer, projection: this.state.viewProjection, scale: this.state.scale }))));
|
|
1744
1794
|
}
|
|
1745
1795
|
}
|
|
@@ -19,7 +19,7 @@ export class AnnotationsPanel extends Component {
|
|
|
19
19
|
return React.createElement("div", null);
|
|
20
20
|
}
|
|
21
21
|
const annotations = annotationIds.map((id) => {
|
|
22
|
-
return (React.createElement("div",
|
|
22
|
+
return (React.createElement("div", { className: "jgis-annotation-panel" },
|
|
23
23
|
React.createElement(Annotation, { jgisModel: this._jgisModel, annotationModel: this._annotationModel, itemId: id }),
|
|
24
24
|
React.createElement("hr", { className: "jGIS-Annotations-Separator" })));
|
|
25
25
|
});
|
|
@@ -166,7 +166,7 @@ const FilterComponent = ({ model }) => {
|
|
|
166
166
|
React.createElement("div", { style: {
|
|
167
167
|
justifyContent: 'flex-start',
|
|
168
168
|
} },
|
|
169
|
-
React.createElement(Button, { className: "jp-Dialog-button jp-mod-accept jp-mod-styled", onClick: addFilterRow }, "Add"),
|
|
169
|
+
React.createElement(Button, { className: "jp-Dialog-button jp-mod-accept jp-mod-styled", onClick: addFilterRow, "data-testid": "add-filter-button" }, "Add"),
|
|
170
170
|
React.createElement(Button, { className: "jp-Dialog-button jp-mod-reject jp-mod-styled", onClick: clearFilters }, "Clear")),
|
|
171
171
|
React.createElement(Button, { className: "jp-Dialog-button jp-mod-accept jp-mod-styled", onClick: submitFilter }, "Submit")))),
|
|
172
172
|
!shouldDisplay && (React.createElement("div", { style: { textAlign: 'center' } }, "No layer selected"))));
|