@jupytergis/base 0.1.6 → 0.1.7
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/classificationModes.d.ts +13 -0
- package/lib/classificationModes.js +326 -0
- package/lib/commands.js +1 -1
- package/lib/dialogs/symbology/classificationModes.d.ts +13 -0
- package/lib/dialogs/symbology/classificationModes.js +326 -0
- package/lib/dialogs/symbology/components/color_ramp/CanvasSelectComponent.d.ts +11 -0
- package/lib/dialogs/symbology/components/color_ramp/CanvasSelectComponent.js +119 -0
- package/lib/dialogs/symbology/components/color_ramp/ColorRamp.d.ts +15 -0
- package/lib/dialogs/symbology/components/color_ramp/ColorRamp.js +33 -0
- package/lib/dialogs/symbology/components/color_ramp/ColorRampEntry.d.ts +9 -0
- package/lib/dialogs/symbology/components/color_ramp/ColorRampEntry.js +24 -0
- package/lib/dialogs/symbology/components/color_ramp/ModeSelectRow.d.ts +10 -0
- package/lib/dialogs/symbology/components/color_ramp/ModeSelectRow.js +11 -0
- package/lib/dialogs/symbology/components/color_stops/StopContainer.d.ts +9 -0
- package/lib/dialogs/symbology/components/color_stops/StopContainer.js +28 -0
- package/lib/dialogs/{components/symbology → symbology/components/color_stops}/StopRow.js +9 -2
- package/lib/dialogs/symbology/hooks/useGetProperties.d.ts +12 -0
- package/lib/dialogs/symbology/hooks/useGetProperties.js +47 -0
- package/lib/dialogs/{symbologyDialog.js → symbology/symbologyDialog.js} +3 -3
- package/lib/dialogs/symbology/symbologyUtils.d.ts +9 -0
- package/lib/dialogs/symbology/symbologyUtils.js +94 -0
- package/lib/dialogs/symbology/tiff_layer/TiffRendering.d.ts +4 -0
- package/lib/dialogs/{components/symbology/BandRendering.js → symbology/tiff_layer/TiffRendering.js} +3 -3
- package/lib/dialogs/{components/symbology → symbology/tiff_layer/components}/BandRow.d.ts +1 -1
- package/lib/dialogs/{components/symbology → symbology/tiff_layer/types}/SingleBandPseudoColor.d.ts +9 -1
- package/lib/dialogs/{components/symbology → symbology/tiff_layer/types}/SingleBandPseudoColor.js +113 -57
- package/lib/dialogs/{components/symbology → symbology/vector_layer}/VectorRendering.d.ts +1 -1
- package/lib/dialogs/{components/symbology → symbology/vector_layer}/VectorRendering.js +10 -13
- package/lib/dialogs/symbology/vector_layer/components/ValueSelect.d.ts +8 -0
- package/lib/dialogs/symbology/vector_layer/components/ValueSelect.js +7 -0
- package/lib/dialogs/symbology/vector_layer/types/Categorized.d.ts +4 -0
- package/lib/dialogs/symbology/vector_layer/types/Categorized.js +94 -0
- package/lib/dialogs/symbology/vector_layer/types/Graduated.js +169 -0
- package/lib/dialogs/{components/symbology → symbology/vector_layer/types}/SimpleSymbol.js +8 -13
- package/lib/formbuilder/objectform/vectorlayerform.js +1 -0
- package/lib/formbuilder/objectform/webGlLayerForm.js +1 -0
- package/lib/index.d.ts +6 -4
- package/lib/index.js +6 -4
- package/lib/mainview/mainView.d.ts +3 -1
- package/lib/mainview/mainView.js +66 -18
- package/lib/store.d.ts +9 -0
- package/lib/store.js +25 -0
- package/lib/toolbar/widget.js +1 -1
- package/lib/types.d.ts +14 -0
- package/package.json +16 -17
- package/style/symbologyDialog.css +104 -3
- package/lib/dialogs/components/symbology/BandRendering.d.ts +0 -4
- package/lib/dialogs/components/symbology/Graduated.js +0 -188
- /package/lib/dialogs/{components/symbology → symbology/components/color_stops}/StopRow.d.ts +0 -0
- /package/lib/dialogs/{symbologyDialog.d.ts → symbology/symbologyDialog.d.ts} +0 -0
- /package/lib/dialogs/{components/symbology → symbology/tiff_layer/components}/BandRow.js +0 -0
- /package/lib/dialogs/{components/symbology → symbology/vector_layer/types}/Graduated.d.ts +0 -0
- /package/lib/dialogs/{components/symbology → symbology/vector_layer/types}/SimpleSymbol.d.ts +0 -0
package/lib/dialogs/{components/symbology → symbology/tiff_layer/types}/SingleBandPseudoColor.js
RENAMED
|
@@ -1,57 +1,71 @@
|
|
|
1
|
-
import { faSpinner } from '@fortawesome/free-solid-svg-icons';
|
|
2
|
-
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
3
1
|
import { Button } from '@jupyterlab/ui-components';
|
|
4
2
|
import React, { useEffect, useRef, useState } from 'react';
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
|
|
3
|
+
import { GeoTiffClassifications } from '../../classificationModes';
|
|
4
|
+
import { GlobalStateDbManager } from '../../../../store';
|
|
5
|
+
import BandRow from '../components/BandRow';
|
|
6
|
+
import ColorRamp from '../../components/color_ramp/ColorRamp';
|
|
7
|
+
import StopRow from '../../components/color_stops/StopRow';
|
|
8
|
+
import { Utils } from '../../symbologyUtils';
|
|
9
|
+
import { getGdal } from '../../../../gdal';
|
|
10
|
+
import { Spinner } from '../../../../mainview/spinner';
|
|
11
|
+
const SingleBandPseudoColor = ({ context, okSignalPromise, cancel, layerId }) => {
|
|
9
12
|
const functions = ['discrete', 'linear', 'exact'];
|
|
13
|
+
const modeOptions = ['continuous', 'equal interval', 'quantile'];
|
|
10
14
|
const stopRowsRef = useRef();
|
|
11
15
|
const bandRowsRef = useRef([]);
|
|
12
16
|
const selectedFunctionRef = useRef();
|
|
13
|
-
const
|
|
17
|
+
const colorRampOptionsRef = useRef();
|
|
18
|
+
const layerStateRef = useRef();
|
|
19
|
+
const selectedBandRef = useRef();
|
|
20
|
+
const [layerState, setLayerState] = useState();
|
|
14
21
|
const [selectedBand, setSelectedBand] = useState(1);
|
|
15
22
|
const [stopRows, setStopRows] = useState([]);
|
|
16
23
|
const [bandRows, setBandRows] = useState([]);
|
|
24
|
+
const [selectedFunction, setSelectedFunction] = useState('linear');
|
|
25
|
+
const [colorRampOptions, setColorRampOptions] = useState();
|
|
17
26
|
if (!layerId) {
|
|
18
27
|
return;
|
|
19
28
|
}
|
|
20
29
|
const layer = context.model.getLayer(layerId);
|
|
21
|
-
if (!layer) {
|
|
30
|
+
if (!(layer === null || layer === void 0 ? void 0 : layer.parameters)) {
|
|
22
31
|
return;
|
|
23
32
|
}
|
|
33
|
+
const stateDb = GlobalStateDbManager.getInstance().getStateDb();
|
|
24
34
|
useEffect(() => {
|
|
25
|
-
|
|
26
|
-
|
|
35
|
+
populateOptions();
|
|
36
|
+
okSignalPromise.promise.then(okSignal => {
|
|
37
|
+
okSignal.connect(handleOk);
|
|
38
|
+
});
|
|
39
|
+
return () => {
|
|
40
|
+
okSignalPromise.promise.then(okSignal => {
|
|
41
|
+
okSignal.disconnect(handleOk, this);
|
|
42
|
+
});
|
|
43
|
+
};
|
|
27
44
|
}, []);
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
layerStateRef.current = layerState;
|
|
47
|
+
getBandInfo();
|
|
48
|
+
}, [layerState]);
|
|
28
49
|
useEffect(() => {
|
|
29
50
|
bandRowsRef.current = bandRows;
|
|
30
51
|
buildColorInfo();
|
|
31
52
|
}, [bandRows]);
|
|
32
53
|
useEffect(() => {
|
|
33
54
|
stopRowsRef.current = stopRows;
|
|
34
|
-
}, [stopRows]);
|
|
35
|
-
useEffect(() => {
|
|
36
55
|
selectedFunctionRef.current = selectedFunction;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// Looking at fourth element because second is for nodata
|
|
51
|
-
const operator = color[3][0];
|
|
52
|
-
operator === '<='
|
|
53
|
-
? setSelectedFunction('discrete')
|
|
54
|
-
: setSelectedFunction('exact');
|
|
56
|
+
colorRampOptionsRef.current = colorRampOptions;
|
|
57
|
+
selectedBandRef.current = selectedBand;
|
|
58
|
+
layerStateRef.current = layerState;
|
|
59
|
+
}, [stopRows, selectedFunction, colorRampOptions, selectedBand, layerState]);
|
|
60
|
+
const populateOptions = async () => {
|
|
61
|
+
var _a, _b, _c, _d;
|
|
62
|
+
const layerState = (await (stateDb === null || stateDb === void 0 ? void 0 : stateDb.fetch(`jupytergis:${layerId}`)));
|
|
63
|
+
setLayerState(layerState);
|
|
64
|
+
const layerParams = layer.parameters;
|
|
65
|
+
const band = (_b = (_a = layerParams.symbologyState) === null || _a === void 0 ? void 0 : _a.band) !== null && _b !== void 0 ? _b : 1;
|
|
66
|
+
const interpolation = (_d = (_c = layerParams.symbologyState) === null || _c === void 0 ? void 0 : _c.interpolation) !== null && _d !== void 0 ? _d : 'linear';
|
|
67
|
+
setSelectedBand(band);
|
|
68
|
+
setSelectedFunction(interpolation);
|
|
55
69
|
};
|
|
56
70
|
const getBandInfo = async () => {
|
|
57
71
|
var _a, _b;
|
|
@@ -62,8 +76,7 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
62
76
|
return;
|
|
63
77
|
}
|
|
64
78
|
let tifData;
|
|
65
|
-
|
|
66
|
-
if (layerState) {
|
|
79
|
+
if (layerState && layerState.tifData) {
|
|
67
80
|
tifData = JSON.parse(layerState.tifData);
|
|
68
81
|
}
|
|
69
82
|
else {
|
|
@@ -74,7 +87,9 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
74
87
|
const tifDataset = result.datasets[0];
|
|
75
88
|
tifData = await Gdal.gdalinfo(tifDataset, ['-stats']);
|
|
76
89
|
Gdal.close(tifDataset);
|
|
77
|
-
|
|
90
|
+
await (stateDb === null || stateDb === void 0 ? void 0 : stateDb.save(`jupytergis:${layerId}`, {
|
|
91
|
+
tifData: JSON.stringify(tifData)
|
|
92
|
+
}));
|
|
78
93
|
}
|
|
79
94
|
tifData['bands'].forEach((bandData) => {
|
|
80
95
|
var _a, _b;
|
|
@@ -87,7 +102,8 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
87
102
|
mean: bandData.mean,
|
|
88
103
|
stdDev: bandData.stdDev
|
|
89
104
|
},
|
|
90
|
-
metadata: bandData.metadata
|
|
105
|
+
metadata: bandData.metadata,
|
|
106
|
+
histogram: bandData.histogram
|
|
91
107
|
});
|
|
92
108
|
});
|
|
93
109
|
setBandRows(bandsArr);
|
|
@@ -95,7 +111,7 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
95
111
|
const buildColorInfo = () => {
|
|
96
112
|
var _a;
|
|
97
113
|
// This it to parse a color object on the layer
|
|
98
|
-
if (!((_a = layer.parameters) === null || _a === void 0 ? void 0 : _a.color)) {
|
|
114
|
+
if (!((_a = layer.parameters) === null || _a === void 0 ? void 0 : _a.color) || !layerState) {
|
|
99
115
|
return;
|
|
100
116
|
}
|
|
101
117
|
const color = layer.parameters.color;
|
|
@@ -103,6 +119,7 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
103
119
|
if (typeof color === 'string') {
|
|
104
120
|
return;
|
|
105
121
|
}
|
|
122
|
+
const isQuantile = layerState.selectedMode === 'quantile';
|
|
106
123
|
const valueColorPairs = [];
|
|
107
124
|
// So if it's not a string then it's an array and we parse
|
|
108
125
|
// Color[0] is the operator used for the color expression
|
|
@@ -115,7 +132,7 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
115
132
|
// Sixth and on is value:color pairs
|
|
116
133
|
for (let i = 5; i < color.length; i += 2) {
|
|
117
134
|
const obj = {
|
|
118
|
-
stop: scaleValue(color[i]),
|
|
135
|
+
stop: scaleValue(color[i], isQuantile),
|
|
119
136
|
output: color[i + 1]
|
|
120
137
|
};
|
|
121
138
|
valueColorPairs.push(obj);
|
|
@@ -132,7 +149,7 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
132
149
|
// Last element is fallback value
|
|
133
150
|
for (let i = 3; i < color.length - 1; i += 2) {
|
|
134
151
|
const obj = {
|
|
135
|
-
stop: scaleValue(color[i][2]),
|
|
152
|
+
stop: scaleValue(color[i][2], isQuantile),
|
|
136
153
|
output: color[i + 1]
|
|
137
154
|
};
|
|
138
155
|
valueColorPairs.push(obj);
|
|
@@ -143,7 +160,7 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
143
160
|
setStopRows(valueColorPairs);
|
|
144
161
|
};
|
|
145
162
|
const handleOk = () => {
|
|
146
|
-
var _a, _b, _c, _d;
|
|
163
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
147
164
|
// Update source
|
|
148
165
|
const bandRow = bandRowsRef.current[selectedBand - 1];
|
|
149
166
|
if (!bandRow) {
|
|
@@ -154,6 +171,7 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
154
171
|
if (!source || !source.parameters) {
|
|
155
172
|
return;
|
|
156
173
|
}
|
|
174
|
+
const isQuantile = ((_b = colorRampOptionsRef.current) === null || _b === void 0 ? void 0 : _b.selectedMode) === 'quantile';
|
|
157
175
|
const sourceInfo = source.parameters.urls[0];
|
|
158
176
|
sourceInfo.min = bandRow.stats.minimum;
|
|
159
177
|
sourceInfo.max = bandRow.stats.maximum;
|
|
@@ -171,8 +189,8 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
171
189
|
colorExpr.push(['band', selectedBand]);
|
|
172
190
|
// Set NoData values to transparent
|
|
173
191
|
colorExpr.push(0.0, [0.0, 0.0, 0.0, 0.0]);
|
|
174
|
-
(
|
|
175
|
-
colorExpr.push(unscaleValue(stop.stop));
|
|
192
|
+
(_c = stopRowsRef.current) === null || _c === void 0 ? void 0 : _c.map(stop => {
|
|
193
|
+
colorExpr.push(unscaleValue(stop.stop, isQuantile));
|
|
176
194
|
colorExpr.push(stop.output);
|
|
177
195
|
});
|
|
178
196
|
break;
|
|
@@ -182,11 +200,11 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
182
200
|
// Set NoData values to transparent
|
|
183
201
|
colorExpr.push(['==', ['band', selectedBand], 0]);
|
|
184
202
|
colorExpr.push([0.0, 0.0, 0.0, 0.0]);
|
|
185
|
-
(
|
|
203
|
+
(_d = stopRowsRef.current) === null || _d === void 0 ? void 0 : _d.map(stop => {
|
|
186
204
|
colorExpr.push([
|
|
187
205
|
'<=',
|
|
188
206
|
['band', selectedBand],
|
|
189
|
-
unscaleValue(stop.stop)
|
|
207
|
+
unscaleValue(stop.stop, isQuantile)
|
|
190
208
|
]);
|
|
191
209
|
colorExpr.push(stop.output);
|
|
192
210
|
});
|
|
@@ -199,11 +217,11 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
199
217
|
// Set NoData values to transparent
|
|
200
218
|
colorExpr.push(['==', ['band', selectedBand], 0]);
|
|
201
219
|
colorExpr.push([0.0, 0.0, 0.0, 0.0]);
|
|
202
|
-
(
|
|
220
|
+
(_e = stopRowsRef.current) === null || _e === void 0 ? void 0 : _e.map(stop => {
|
|
203
221
|
colorExpr.push([
|
|
204
222
|
'==',
|
|
205
223
|
['band', selectedBand],
|
|
206
|
-
unscaleValue(stop.stop)
|
|
224
|
+
unscaleValue(stop.stop, isQuantile)
|
|
207
225
|
]);
|
|
208
226
|
colorExpr.push(stop.output);
|
|
209
227
|
});
|
|
@@ -212,13 +230,19 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
212
230
|
break;
|
|
213
231
|
}
|
|
214
232
|
}
|
|
233
|
+
const symbologyState = {
|
|
234
|
+
renderType: 'Singleband Pseudocolor',
|
|
235
|
+
band: selectedBandRef.current,
|
|
236
|
+
interpolation: selectedFunctionRef.current,
|
|
237
|
+
colorRamp: (_f = colorRampOptionsRef.current) === null || _f === void 0 ? void 0 : _f.selectedRamp,
|
|
238
|
+
nClasses: (_g = colorRampOptionsRef.current) === null || _g === void 0 ? void 0 : _g.numberOfShades,
|
|
239
|
+
mode: (_h = colorRampOptionsRef.current) === null || _h === void 0 ? void 0 : _h.selectedMode
|
|
240
|
+
};
|
|
241
|
+
layer.parameters.symbologyState = symbologyState;
|
|
215
242
|
layer.parameters.color = colorExpr;
|
|
216
243
|
context.model.sharedModel.updateLayer(layerId, layer);
|
|
217
244
|
cancel();
|
|
218
245
|
};
|
|
219
|
-
okSignalPromise.promise.then(okSignal => {
|
|
220
|
-
okSignal.connect(handleOk);
|
|
221
|
-
});
|
|
222
246
|
const addStopRow = () => {
|
|
223
247
|
setStopRows([
|
|
224
248
|
{
|
|
@@ -233,24 +257,55 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
233
257
|
newFilters.splice(index, 1);
|
|
234
258
|
setStopRows(newFilters);
|
|
235
259
|
};
|
|
236
|
-
const
|
|
260
|
+
const buildColorInfoFromClassification = async (selectedMode, numberOfShades, selectedRamp, setIsLoading) => {
|
|
261
|
+
var _a, _b;
|
|
262
|
+
// Update layer state with selected options
|
|
263
|
+
setColorRampOptions({
|
|
264
|
+
selectedRamp,
|
|
265
|
+
numberOfShades,
|
|
266
|
+
selectedMode
|
|
267
|
+
});
|
|
268
|
+
let stops = [];
|
|
269
|
+
const currentBand = bandRows[selectedBand - 1];
|
|
270
|
+
const source = context.model.getSource((_a = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _a === void 0 ? void 0 : _a.source);
|
|
271
|
+
const sourceInfo = (_b = source === null || source === void 0 ? void 0 : source.parameters) === null || _b === void 0 ? void 0 : _b.urls[0];
|
|
272
|
+
const nClasses = selectedMode === 'continuous' ? 52 : +numberOfShades;
|
|
273
|
+
setIsLoading(true);
|
|
274
|
+
switch (selectedMode) {
|
|
275
|
+
case 'quantile':
|
|
276
|
+
stops = await GeoTiffClassifications.classifyQuantileBreaks(nClasses, selectedBand, sourceInfo.url, selectedFunction);
|
|
277
|
+
break;
|
|
278
|
+
case 'continuous':
|
|
279
|
+
stops = GeoTiffClassifications.classifyContinuousBreaks(nClasses, currentBand.stats.minimum, currentBand.stats.maximum, selectedFunction);
|
|
280
|
+
break;
|
|
281
|
+
case 'equal interval':
|
|
282
|
+
stops = GeoTiffClassifications.classifyEqualIntervalBreaks(nClasses, currentBand.stats.minimum, currentBand.stats.maximum, selectedFunction);
|
|
283
|
+
break;
|
|
284
|
+
default:
|
|
285
|
+
console.warn('No mode selected');
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
setIsLoading(false);
|
|
289
|
+
const valueColorPairs = Utils.getValueColorPairs(stops, selectedRamp, nClasses);
|
|
290
|
+
setStopRows(valueColorPairs);
|
|
291
|
+
};
|
|
292
|
+
const scaleValue = (bandValue, isQuantile) => {
|
|
237
293
|
const currentBand = bandRows[selectedBand - 1];
|
|
238
294
|
if (!currentBand) {
|
|
239
295
|
return bandValue;
|
|
240
296
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
297
|
+
const min = isQuantile ? 1 : currentBand.stats.minimum;
|
|
298
|
+
const max = isQuantile ? 65535 : currentBand.stats.maximum;
|
|
299
|
+
return (bandValue * (max - min)) / (1 - 0) + min;
|
|
244
300
|
};
|
|
245
|
-
const unscaleValue = (value) => {
|
|
301
|
+
const unscaleValue = (value, isQuantile) => {
|
|
246
302
|
const currentBand = bandRowsRef.current[selectedBand - 1];
|
|
247
|
-
|
|
248
|
-
|
|
303
|
+
const min = isQuantile ? 1 : currentBand.stats.minimum;
|
|
304
|
+
const max = isQuantile ? 65535 : currentBand.stats.maximum;
|
|
305
|
+
return (value * (1 - 0) - min * (1 - 0)) / (max - min);
|
|
249
306
|
};
|
|
250
307
|
return (React.createElement("div", { className: "jp-gis-layer-symbology-container" },
|
|
251
|
-
React.createElement("div", { className: "jp-gis-band-container" }, bandRows.length === 0 ? (React.createElement(
|
|
252
|
-
React.createElement("span", null, "Fetching band info..."),
|
|
253
|
-
React.createElement(FontAwesomeIcon, { icon: faSpinner, className: "jp-gis-loading-spinner" }))) : (React.createElement(BandRow
|
|
308
|
+
React.createElement("div", { className: "jp-gis-band-container" }, bandRows.length === 0 ? (React.createElement(Spinner, { loading: bandRows.length === 0 })) : (React.createElement(BandRow
|
|
254
309
|
// Band numbers are 1 indexed
|
|
255
310
|
, {
|
|
256
311
|
// Band numbers are 1 indexed
|
|
@@ -261,6 +316,7 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
261
316
|
React.createElement("select", { name: "function-select", id: "function-select", className: "jp-mod-styled", value: selectedFunction, style: { textTransform: 'capitalize' }, onChange: event => {
|
|
262
317
|
setSelectedFunction(event.target.value);
|
|
263
318
|
} }, functions.map((func, funcIndex) => (React.createElement("option", { key: func, value: func, style: { textTransform: 'capitalize' } }, func)))))),
|
|
319
|
+
bandRows.length > 0 && (React.createElement(ColorRamp, { layerParams: layer.parameters, modeOptions: modeOptions, classifyFunc: buildColorInfoFromClassification, showModeRow: true })),
|
|
264
320
|
React.createElement("div", { className: "jp-gis-stop-container" },
|
|
265
321
|
React.createElement("div", { className: "jp-gis-stop-labels", style: { display: 'flex', gap: 6 } },
|
|
266
322
|
React.createElement("span", { style: { flex: '0 0 18%' } },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ISymbologyDialogProps } from '
|
|
2
|
+
import { ISymbologyDialogProps } from '../symbologyDialog';
|
|
3
3
|
declare const VectorRendering: ({ context, state, okSignalPromise, cancel, layerId }: ISymbologyDialogProps) => React.JSX.Element | undefined;
|
|
4
4
|
export default VectorRendering;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react';
|
|
2
|
-
import Graduated from './Graduated';
|
|
3
|
-
import SimpleSymbol from './SimpleSymbol';
|
|
2
|
+
import Graduated from './types/Graduated';
|
|
3
|
+
import SimpleSymbol from './types/SimpleSymbol';
|
|
4
|
+
import Categorized from './types/Categorized';
|
|
4
5
|
const VectorRendering = ({ context, state, okSignalPromise, cancel, layerId }) => {
|
|
5
6
|
const [selectedRenderType, setSelectedRenderType] = useState('Single Symbol');
|
|
6
7
|
const [componentToRender, setComponentToRender] = useState(null);
|
|
@@ -16,20 +17,13 @@ const VectorRendering = ({ context, state, okSignalPromise, cancel, layerId }) =
|
|
|
16
17
|
return;
|
|
17
18
|
}
|
|
18
19
|
useEffect(() => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
const renderType = layerState
|
|
25
|
-
.renderType;
|
|
26
|
-
setSelectedRenderType(renderType !== null && renderType !== void 0 ? renderType : 'Single Symbol');
|
|
27
|
-
};
|
|
20
|
+
var _a, _b;
|
|
21
|
+
const renderType = (_b = (_a = layer.parameters) === null || _a === void 0 ? void 0 : _a.symbologyState) === null || _b === void 0 ? void 0 : _b.renderType;
|
|
22
|
+
setSelectedRenderType(renderType !== null && renderType !== void 0 ? renderType : 'Single Symbol');
|
|
28
23
|
if (layer.type === 'VectorLayer') {
|
|
29
|
-
const options = ['Single Symbol', 'Graduated'];
|
|
24
|
+
const options = ['Single Symbol', 'Graduated', 'Categorized'];
|
|
30
25
|
setRenderTypeOptions(options);
|
|
31
26
|
}
|
|
32
|
-
getSelectedRenderType();
|
|
33
27
|
}, []);
|
|
34
28
|
useEffect(() => {
|
|
35
29
|
switch (selectedRenderType) {
|
|
@@ -39,6 +33,9 @@ const VectorRendering = ({ context, state, okSignalPromise, cancel, layerId }) =
|
|
|
39
33
|
case 'Graduated':
|
|
40
34
|
RenderComponent = (React.createElement(Graduated, { context: context, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: layerId }));
|
|
41
35
|
break;
|
|
36
|
+
case 'Categorized':
|
|
37
|
+
RenderComponent = (React.createElement(Categorized, { context: context, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: layerId }));
|
|
38
|
+
break;
|
|
42
39
|
default:
|
|
43
40
|
RenderComponent = React.createElement("div", null, "Render Type Not Implemented (yet)");
|
|
44
41
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface IValueSelectProps {
|
|
3
|
+
featureProperties: any;
|
|
4
|
+
selectedValue: string;
|
|
5
|
+
setSelectedValue: (value: string) => void;
|
|
6
|
+
}
|
|
7
|
+
declare const ValueSelect: ({ featureProperties, selectedValue, setSelectedValue }: IValueSelectProps) => React.JSX.Element;
|
|
8
|
+
export default ValueSelect;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
const ValueSelect = ({ featureProperties, selectedValue, setSelectedValue }) => {
|
|
3
|
+
return (React.createElement("div", { className: "jp-gis-symbology-row" },
|
|
4
|
+
React.createElement("label", { htmlFor: 'vector-value-select' }, "Value:"),
|
|
5
|
+
React.createElement("select", { name: 'vector-value-select', onChange: event => setSelectedValue(event.target.value), className: "jp-mod-styled" }, Object.keys(featureProperties).map((feature, index) => (React.createElement("option", { key: index, value: feature, selected: feature === selectedValue, className: "jp-mod-styled" }, feature))))));
|
|
6
|
+
};
|
|
7
|
+
export default ValueSelect;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import ValueSelect from '../components/ValueSelect';
|
|
3
|
+
import { useGetProperties } from '../../hooks/useGetProperties';
|
|
4
|
+
import StopContainer from '../../components/color_stops/StopContainer';
|
|
5
|
+
import { Utils, VectorUtils } from '../../symbologyUtils';
|
|
6
|
+
import ColorRamp from '../../components/color_ramp/ColorRamp';
|
|
7
|
+
const Categorized = ({ context, state, okSignalPromise, cancel, layerId }) => {
|
|
8
|
+
const selectedValueRef = useRef();
|
|
9
|
+
const stopRowsRef = useRef();
|
|
10
|
+
const colorRampOptionsRef = useRef();
|
|
11
|
+
const [selectedValue, setSelectedValue] = useState('');
|
|
12
|
+
const [stopRows, setStopRows] = useState([]);
|
|
13
|
+
const [colorRampOptions, setColorRampOptions] = useState();
|
|
14
|
+
if (!layerId) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const layer = context.model.getLayer(layerId);
|
|
18
|
+
if (!(layer === null || layer === void 0 ? void 0 : layer.parameters)) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const { featureProps } = useGetProperties({
|
|
22
|
+
layerId,
|
|
23
|
+
model: context.model
|
|
24
|
+
});
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const valueColorPairs = VectorUtils.buildColorInfo(layer);
|
|
27
|
+
setStopRows(valueColorPairs);
|
|
28
|
+
okSignalPromise.promise.then(okSignal => {
|
|
29
|
+
okSignal.connect(handleOk, this);
|
|
30
|
+
});
|
|
31
|
+
return () => {
|
|
32
|
+
okSignalPromise.promise.then(okSignal => {
|
|
33
|
+
okSignal.disconnect(handleOk, this);
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
}, []);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
populateOptions();
|
|
39
|
+
}, [featureProps]);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
selectedValueRef.current = selectedValue;
|
|
42
|
+
stopRowsRef.current = stopRows;
|
|
43
|
+
colorRampOptionsRef.current = colorRampOptions;
|
|
44
|
+
}, [selectedValue, stopRows, colorRampOptions]);
|
|
45
|
+
const populateOptions = async () => {
|
|
46
|
+
var _a, _b;
|
|
47
|
+
const layerParams = layer.parameters;
|
|
48
|
+
const value = (_b = (_a = layerParams.symbologyState) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : Object.keys(featureProps)[0];
|
|
49
|
+
setSelectedValue(value);
|
|
50
|
+
};
|
|
51
|
+
const buildColorInfoFromClassification = (selectedMode, numberOfShades, selectedRamp, setIsLoading) => {
|
|
52
|
+
setColorRampOptions({
|
|
53
|
+
selectedFunction: '',
|
|
54
|
+
selectedRamp,
|
|
55
|
+
numberOfShades: '',
|
|
56
|
+
selectedMode: ''
|
|
57
|
+
});
|
|
58
|
+
const stops = Array.from(featureProps[selectedValue]).sort((a, b) => a - b);
|
|
59
|
+
const valueColorPairs = Utils.getValueColorPairs(stops, selectedRamp, stops.length);
|
|
60
|
+
setStopRows(valueColorPairs);
|
|
61
|
+
};
|
|
62
|
+
const handleOk = () => {
|
|
63
|
+
var _a, _b, _c, _d;
|
|
64
|
+
if (!layer.parameters) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const colorExpr = [];
|
|
68
|
+
colorExpr.push('case');
|
|
69
|
+
(_a = stopRowsRef.current) === null || _a === void 0 ? void 0 : _a.map(stop => {
|
|
70
|
+
colorExpr.push(['==', ['get', selectedValueRef.current], stop.stop]);
|
|
71
|
+
colorExpr.push(stop.output);
|
|
72
|
+
});
|
|
73
|
+
// fallback value
|
|
74
|
+
colorExpr.push([0, 0, 0, 0.0]);
|
|
75
|
+
const newStyle = Object.assign({}, layer.parameters.color);
|
|
76
|
+
newStyle['circle-fill-color'] = colorExpr;
|
|
77
|
+
const symbologyState = {
|
|
78
|
+
renderType: 'Categorized',
|
|
79
|
+
value: selectedValueRef.current,
|
|
80
|
+
colorRamp: (_b = colorRampOptionsRef.current) === null || _b === void 0 ? void 0 : _b.selectedRamp,
|
|
81
|
+
nClasses: (_c = colorRampOptionsRef.current) === null || _c === void 0 ? void 0 : _c.numberOfShades,
|
|
82
|
+
mode: (_d = colorRampOptionsRef.current) === null || _d === void 0 ? void 0 : _d.selectedMode
|
|
83
|
+
};
|
|
84
|
+
layer.parameters.symbologyState = symbologyState;
|
|
85
|
+
layer.parameters.color = newStyle;
|
|
86
|
+
context.model.sharedModel.updateLayer(layerId, layer);
|
|
87
|
+
cancel();
|
|
88
|
+
};
|
|
89
|
+
return (React.createElement("div", { className: "jp-gis-layer-symbology-container" },
|
|
90
|
+
React.createElement(ValueSelect, { featureProperties: featureProps, selectedValue: selectedValue, setSelectedValue: setSelectedValue }),
|
|
91
|
+
React.createElement(ColorRamp, { layerParams: layer.parameters, modeOptions: [], classifyFunc: buildColorInfoFromClassification, showModeRow: false }),
|
|
92
|
+
React.createElement(StopContainer, { selectedMethod: '', stopRows: stopRows, setStopRows: setStopRows })));
|
|
93
|
+
};
|
|
94
|
+
export default Categorized;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { VectorClassifications } from '../../classificationModes';
|
|
3
|
+
import ColorRamp from '../../components/color_ramp/ColorRamp';
|
|
4
|
+
import ValueSelect from '../components/ValueSelect';
|
|
5
|
+
import StopContainer from '../../components/color_stops/StopContainer';
|
|
6
|
+
import { useGetProperties } from '../../hooks/useGetProperties';
|
|
7
|
+
import { Utils, VectorUtils } from '../../symbologyUtils';
|
|
8
|
+
const Graduated = ({ context, state, okSignalPromise, cancel, layerId }) => {
|
|
9
|
+
const modeOptions = [
|
|
10
|
+
'quantile',
|
|
11
|
+
'equal interval',
|
|
12
|
+
'jenks',
|
|
13
|
+
'pretty',
|
|
14
|
+
'logarithmic'
|
|
15
|
+
];
|
|
16
|
+
const selectedValueRef = useRef();
|
|
17
|
+
const selectedMethodRef = useRef();
|
|
18
|
+
const stopRowsRef = useRef();
|
|
19
|
+
const colorRampOptionsRef = useRef();
|
|
20
|
+
const [selectedValue, setSelectedValue] = useState('');
|
|
21
|
+
const [selectedMethod, setSelectedMethod] = useState('color');
|
|
22
|
+
const [stopRows, setStopRows] = useState([]);
|
|
23
|
+
const [methodOptions, setMethodOptions] = useState(['color']);
|
|
24
|
+
const [colorRampOptions, setColorRampOptions] = useState();
|
|
25
|
+
if (!layerId) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const layer = context.model.getLayer(layerId);
|
|
29
|
+
if (!(layer === null || layer === void 0 ? void 0 : layer.parameters)) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const { featureProps } = useGetProperties({
|
|
33
|
+
layerId,
|
|
34
|
+
model: context.model
|
|
35
|
+
});
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
var _a, _b;
|
|
38
|
+
let stopOutputPairs = [];
|
|
39
|
+
const layerParams = layer.parameters;
|
|
40
|
+
const method = (_b = (_a = layerParams.symbologyState) === null || _a === void 0 ? void 0 : _a.method) !== null && _b !== void 0 ? _b : 'color';
|
|
41
|
+
if (method === 'color') {
|
|
42
|
+
stopOutputPairs = VectorUtils.buildColorInfo(layer);
|
|
43
|
+
}
|
|
44
|
+
if (method === 'radius') {
|
|
45
|
+
stopOutputPairs = VectorUtils.buildRadiusInfo(layer);
|
|
46
|
+
}
|
|
47
|
+
setStopRows(stopOutputPairs);
|
|
48
|
+
okSignalPromise.promise.then(okSignal => {
|
|
49
|
+
okSignal.connect(handleOk, this);
|
|
50
|
+
});
|
|
51
|
+
return () => {
|
|
52
|
+
okSignalPromise.promise.then(okSignal => {
|
|
53
|
+
okSignal.disconnect(handleOk, this);
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
}, []);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
selectedValueRef.current = selectedValue;
|
|
59
|
+
selectedMethodRef.current = selectedMethod;
|
|
60
|
+
stopRowsRef.current = stopRows;
|
|
61
|
+
colorRampOptionsRef.current = colorRampOptions;
|
|
62
|
+
}, [selectedValue, selectedMethod, stopRows, colorRampOptions]);
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
populateOptions();
|
|
65
|
+
}, [featureProps]);
|
|
66
|
+
const populateOptions = async () => {
|
|
67
|
+
var _a, _b, _c, _d, _e;
|
|
68
|
+
// Set up method options
|
|
69
|
+
if (((_a = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _a === void 0 ? void 0 : _a.type) === 'circle') {
|
|
70
|
+
const options = ['color', 'radius'];
|
|
71
|
+
setMethodOptions(options);
|
|
72
|
+
}
|
|
73
|
+
const layerParams = layer.parameters;
|
|
74
|
+
const value = (_c = (_b = layerParams.symbologyState) === null || _b === void 0 ? void 0 : _b.value) !== null && _c !== void 0 ? _c : Object.keys(featureProps)[0];
|
|
75
|
+
const method = (_e = (_d = layerParams.symbologyState) === null || _d === void 0 ? void 0 : _d.method) !== null && _e !== void 0 ? _e : 'color';
|
|
76
|
+
setSelectedValue(value);
|
|
77
|
+
setSelectedMethod(method);
|
|
78
|
+
};
|
|
79
|
+
const handleOk = () => {
|
|
80
|
+
var _a, _b, _c, _d;
|
|
81
|
+
if (!layer.parameters) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const colorExpr = [];
|
|
85
|
+
colorExpr.push('interpolate');
|
|
86
|
+
colorExpr.push(['linear']);
|
|
87
|
+
colorExpr.push(['get', selectedValueRef.current]);
|
|
88
|
+
(_a = stopRowsRef.current) === null || _a === void 0 ? void 0 : _a.map(stop => {
|
|
89
|
+
colorExpr.push(stop.stop);
|
|
90
|
+
colorExpr.push(stop.output);
|
|
91
|
+
});
|
|
92
|
+
const newStyle = Object.assign({}, layer.parameters.color);
|
|
93
|
+
if (selectedMethodRef.current === 'color') {
|
|
94
|
+
if (layer.parameters.type === 'fill') {
|
|
95
|
+
newStyle['fill-color'] = colorExpr;
|
|
96
|
+
}
|
|
97
|
+
if (layer.parameters.type === 'line') {
|
|
98
|
+
newStyle['stroke-color'] = colorExpr;
|
|
99
|
+
}
|
|
100
|
+
if (layer.parameters.type === 'circle') {
|
|
101
|
+
newStyle['circle-fill-color'] = colorExpr;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (selectedMethodRef.current === 'radius') {
|
|
105
|
+
if (layer.parameters.type === 'circle') {
|
|
106
|
+
newStyle['circle-radius'] = colorExpr;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const symbologyState = {
|
|
110
|
+
renderType: 'Graduated',
|
|
111
|
+
value: selectedValueRef.current,
|
|
112
|
+
method: selectedMethodRef.current,
|
|
113
|
+
colorRamp: (_b = colorRampOptionsRef.current) === null || _b === void 0 ? void 0 : _b.selectedRamp,
|
|
114
|
+
nClasses: (_c = colorRampOptionsRef.current) === null || _c === void 0 ? void 0 : _c.numberOfShades,
|
|
115
|
+
mode: (_d = colorRampOptionsRef.current) === null || _d === void 0 ? void 0 : _d.selectedMode
|
|
116
|
+
};
|
|
117
|
+
layer.parameters.symbologyState = symbologyState;
|
|
118
|
+
layer.parameters.color = newStyle;
|
|
119
|
+
context.model.sharedModel.updateLayer(layerId, layer);
|
|
120
|
+
cancel();
|
|
121
|
+
};
|
|
122
|
+
const buildColorInfoFromClassification = (selectedMode, numberOfShades, selectedRamp) => {
|
|
123
|
+
setColorRampOptions({
|
|
124
|
+
selectedRamp,
|
|
125
|
+
numberOfShades,
|
|
126
|
+
selectedMode
|
|
127
|
+
});
|
|
128
|
+
let stops;
|
|
129
|
+
const values = Array.from(featureProps[selectedValue]);
|
|
130
|
+
switch (selectedMode) {
|
|
131
|
+
case 'quantile':
|
|
132
|
+
stops = VectorClassifications.calculateQuantileBreaks(values, +numberOfShades);
|
|
133
|
+
break;
|
|
134
|
+
case 'equal interval':
|
|
135
|
+
stops = VectorClassifications.calculateEqualIntervalBreaks(values, +numberOfShades);
|
|
136
|
+
break;
|
|
137
|
+
case 'jenks':
|
|
138
|
+
stops = VectorClassifications.calculateJenksBreaks(values, +numberOfShades);
|
|
139
|
+
break;
|
|
140
|
+
case 'pretty':
|
|
141
|
+
stops = VectorClassifications.calculatePrettyBreaks(values, +numberOfShades);
|
|
142
|
+
break;
|
|
143
|
+
case 'logarithmic':
|
|
144
|
+
stops = VectorClassifications.calculateLogarithmicBreaks(values, +numberOfShades);
|
|
145
|
+
break;
|
|
146
|
+
default:
|
|
147
|
+
console.warn('No mode selected');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
let stopOutputPairs = [];
|
|
151
|
+
if (selectedMethod === 'radius') {
|
|
152
|
+
for (let i = 0; i < +numberOfShades; i++) {
|
|
153
|
+
stopOutputPairs.push({ stop: stops[i], output: stops[i] });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
stopOutputPairs = Utils.getValueColorPairs(stops, selectedRamp, +numberOfShades);
|
|
158
|
+
}
|
|
159
|
+
setStopRows(stopOutputPairs);
|
|
160
|
+
};
|
|
161
|
+
return (React.createElement("div", { className: "jp-gis-layer-symbology-container" },
|
|
162
|
+
React.createElement(ValueSelect, { featureProperties: featureProps, selectedValue: selectedValue, setSelectedValue: setSelectedValue }),
|
|
163
|
+
React.createElement("div", { className: "jp-gis-symbology-row" },
|
|
164
|
+
React.createElement("label", { htmlFor: 'vector-method-select' }, "Method:"),
|
|
165
|
+
React.createElement("select", { name: 'vector-method-select', onChange: event => setSelectedMethod(event.target.value), className: "jp-mod-styled" }, methodOptions.map((method, index) => (React.createElement("option", { key: index, value: method, selected: method === selectedMethod, className: "jp-mod-styled" }, method))))),
|
|
166
|
+
React.createElement(ColorRamp, { layerParams: layer.parameters, modeOptions: modeOptions, classifyFunc: buildColorInfoFromClassification, showModeRow: true }),
|
|
167
|
+
React.createElement(StopContainer, { selectedMethod: selectedMethod, stopRows: stopRows, setStopRows: setStopRows })));
|
|
168
|
+
};
|
|
169
|
+
export default Graduated;
|