Skip to content

Commit 19ed962

Browse files
committed
pre-populating values
1 parent 1af0c01 commit 19ed962

File tree

6 files changed

+146
-33
lines changed

6 files changed

+146
-33
lines changed

packages/base/src/dialogs/symbology/components/color_ramp/ColorRamp.tsx

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,19 @@ interface IColorRampProps {
2424
) => void;
2525
showModeRow: boolean;
2626
showRampSelector: boolean;
27-
renderType?: 'graduated' | 'categorized' | 'heatmap' | 'singleband';
27+
renderType?:
28+
| 'Graduated'
29+
| 'Categorized'
30+
| 'Heatmap'
31+
| 'Singleband PseudoColor';
32+
initialMin?: number;
33+
initialMax?: number;
2834
}
2935

3036
export type ColorRampOptions = {
31-
selectedRamp: string;
32-
numberOfShades: string;
33-
selectedMode: string;
37+
selectedRamp?: string;
38+
numberOfShades?: string;
39+
selectedMode?: string;
3440
minValue?: number;
3541
maxValue?: number;
3642
criticalValue?: number;
@@ -43,12 +49,14 @@ const ColorRamp: React.FC<IColorRampProps> = ({
4349
showModeRow,
4450
showRampSelector,
4551
renderType,
52+
initialMin,
53+
initialMax,
4654
}) => {
4755
const [selectedRamp, setSelectedRamp] = useState('');
4856
const [selectedMode, setSelectedMode] = useState('');
4957
const [numberOfShades, setNumberOfShades] = useState('');
50-
const [minValue, setMinValue] = useState<number | undefined>(-5);
51-
const [maxValue, setMaxValue] = useState<number | undefined>(5);
58+
const [minValue, setMinValue] = useState<number | undefined>(initialMin);
59+
const [maxValue, setMaxValue] = useState<number | undefined>(initialMax);
5260
const [isLoading, setIsLoading] = useState(false);
5361

5462
useEffect(() => {
@@ -62,7 +70,7 @@ const ColorRamp: React.FC<IColorRampProps> = ({
6270
layerParams.symbologyState = {};
6371
}
6472

65-
if (renderType !== 'heatmap') {
73+
if (renderType !== 'Heatmap') {
6674
layerParams.symbologyState.min = minValue;
6775
layerParams.symbologyState.max = maxValue;
6876
layerParams.symbologyState.colorRamp = selectedRamp;
@@ -75,21 +83,30 @@ const ColorRamp: React.FC<IColorRampProps> = ({
7583
}
7684
}, [minValue, maxValue, selectedRamp, selectedMode, numberOfShades]);
7785

86+
useEffect(() => {
87+
if (renderType === 'Graduated') {
88+
if (initialMin !== undefined) {
89+
setMinValue(initialMin);
90+
}
91+
if (initialMax !== undefined) {
92+
setMaxValue(initialMax);
93+
}
94+
}
95+
}, [initialMin, initialMax, renderType]);
96+
7897
const populateOptions = () => {
79-
let nClasses, singleBandMode, colorRamp, min, max;
98+
let nClasses, singleBandMode, colorRamp;
8099

81100
if (layerParams.symbologyState) {
82101
nClasses = layerParams.symbologyState.nClasses;
83102
singleBandMode = layerParams.symbologyState.mode;
84103
colorRamp = layerParams.symbologyState.colorRamp;
85-
min = layerParams.symbologyState.min;
86-
max = layerParams.symbologyState.max;
87104
}
88105
setNumberOfShades(nClasses ? nClasses : '9');
89106
setSelectedMode(singleBandMode ? singleBandMode : 'equal interval');
90107
setSelectedRamp(colorRamp ? colorRamp : 'viridis');
91-
setMinValue(min !== undefined ? min : -5);
92-
setMaxValue(max !== undefined ? max : 5);
108+
setMinValue(initialMin);
109+
setMaxValue(initialMax);
93110
};
94111

95112
const rampDef = COLOR_RAMP_DEFINITIONS[selectedRamp as ColorRampName];
@@ -100,6 +117,23 @@ const ColorRamp: React.FC<IColorRampProps> = ({
100117
? minValue + normalizedCritical * (maxValue - minValue)
101118
: undefined;
102119

120+
let displayMin = minValue;
121+
let displayMax = maxValue;
122+
123+
if (
124+
rampDef?.type === 'Divergent' &&
125+
renderType === 'Graduated' &&
126+
displayMin !== undefined &&
127+
displayMax !== undefined
128+
) {
129+
const absMax = Math.max(
130+
minValue ?? Math.abs(displayMin),
131+
maxValue ?? Math.abs(displayMax),
132+
);
133+
displayMin = -absMax;
134+
displayMax = absMax;
135+
}
136+
103137
return (
104138
<div className="jp-gis-color-ramp-container">
105139
{showRampSelector && (
@@ -122,11 +156,14 @@ const ColorRamp: React.FC<IColorRampProps> = ({
122156
)}
123157
{rampDef && (
124158
<ColorRampValueControls
125-
min={minValue}
159+
min={displayMin}
126160
setMin={setMinValue}
127-
max={maxValue}
161+
max={displayMax}
128162
setMax={setMaxValue}
129163
rampDef={rampDef}
164+
initialMin={initialMin}
165+
initialMax={initialMax}
166+
renderType={renderType}
130167
/>
131168
)}
132169

@@ -135,15 +172,16 @@ const ColorRamp: React.FC<IColorRampProps> = ({
135172
) : (
136173
<Button
137174
className="jp-Dialog-button jp-mod-accept jp-mod-styled"
175+
disabled={minValue === undefined || maxValue === undefined}
138176
onClick={() =>
139177
classifyFunc(
140178
selectedMode,
141179
numberOfShades,
142180
selectedRamp,
143181
setIsLoading,
144182
scaledCritical,
145-
minValue,
146-
maxValue,
183+
displayMin,
184+
displayMax,
147185
)
148186
}
149187
>

packages/base/src/dialogs/symbology/components/color_ramp/ColorRampValueControls.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Button } from '@jupyterlab/ui-components';
12
import React from 'react';
23

34
import { IColorRampValueControlsProps } from '@/src/types';
@@ -8,6 +9,9 @@ export const ColorRampValueControls: React.FC<IColorRampValueControlsProps> = ({
89
max,
910
setMax,
1011
rampDef,
12+
initialMin,
13+
initialMax,
14+
renderType,
1115
}) => {
1216
return (
1317
<>
@@ -27,7 +31,7 @@ export const ColorRampValueControls: React.FC<IColorRampValueControlsProps> = ({
2731
/>
2832
</div>
2933

30-
{rampDef.type === 'Divergent' && (
34+
{rampDef.type === 'Divergent' && renderType === 'Graduated' && (
3135
<div className="jp-gis-symbology-row">
3236
<label htmlFor="critical-value">Critical Value:</label>
3337
<input
@@ -56,6 +60,20 @@ export const ColorRampValueControls: React.FC<IColorRampValueControlsProps> = ({
5660
placeholder="Enter max value"
5761
/>
5862
</div>
63+
{
64+
<div className="jp-gis-symbology-row">
65+
<Button
66+
className="jp-Dialog-button jp-mod-accept jp-mod-styled"
67+
disabled={min === initialMin && max === initialMax}
68+
onClick={() => {
69+
setMin(initialMin);
70+
setMax(initialMax);
71+
}}
72+
>
73+
Use Actual Range
74+
</Button>
75+
</div>
76+
}
5977
</>
6078
);
6179
};

packages/base/src/dialogs/symbology/symbologyUtils.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,27 +105,36 @@ export namespace Utils {
105105
selectedRamp: string,
106106
nClasses: number,
107107
reverse = false,
108-
renderType: 'categorized' | 'graduated' = 'graduated',
108+
renderType:
109+
| 'Categorized'
110+
| 'Graduated'
111+
| 'Heatmap'
112+
| 'Singleband PseudoColor' = 'Graduated',
109113
minValue?: number,
110114
maxValue?: number,
111115
) => {
112116
const rampDef = COLOR_RAMP_DEFINITIONS[selectedRamp as ColorRampName];
113117
let effectiveStops: number[] = [];
114118

115-
if (renderType === 'categorized') {
119+
if (renderType === 'Categorized') {
116120
effectiveStops = stops;
117121
} else {
118-
if (rampDef?.type === 'Divergent') {
119-
const min = minValue ?? Math.min(...stops);
120-
const max = maxValue ?? Math.max(...stops);
122+
if (rampDef?.type === 'Divergent' && renderType === 'Graduated') {
123+
const rawMin = minValue ?? Math.min(...stops);
124+
const rawMax = maxValue ?? Math.max(...stops);
125+
126+
const absMax = Math.max(Math.abs(rawMin), Math.abs(rawMax));
127+
128+
const min = -absMax;
129+
const max = absMax;
121130

122131
effectiveStops = Array.from(
123132
{ length: nClasses },
124133
(_, i) => min + (i / (nClasses - 1)) * (max - min),
125134
);
126135
} else {
127-
const min = Math.min(...stops);
128-
const max = Math.max(...stops);
136+
const min = minValue ?? Math.min(...stops);
137+
const max = maxValue ?? Math.max(...stops);
129138

130139
effectiveStops = Array.from(
131140
{ length: nClasses },

packages/base/src/dialogs/symbology/vector_layer/types/Categorized.tsx

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { IVectorLayer } from '@jupytergis/schema';
2-
import { ReadonlyJSONObject } from '@lumino/coreutils';
32
import { ExpressionValue } from 'ol/expr/expression';
43
import React, { useEffect, useRef, useState } from 'react';
54

6-
import ColorRamp from '@/src/dialogs/symbology/components/color_ramp/ColorRamp';
5+
import ColorRamp, {
6+
ColorRampOptions,
7+
} from '@/src/dialogs/symbology/components/color_ramp/ColorRamp';
78
import StopContainer from '@/src/dialogs/symbology/components/color_stops/StopContainer';
89
import {
910
IStopRow,
@@ -24,12 +25,12 @@ const Categorized: React.FC<ISymbologyTabbedDialogWithAttributesProps> = ({
2425
}) => {
2526
const selectedAttributeRef = useRef<string>();
2627
const stopRowsRef = useRef<IStopRow[]>();
27-
const colorRampOptionsRef = useRef<ReadonlyJSONObject | undefined>();
28+
const colorRampOptionsRef = useRef<ColorRampOptions | undefined>();
2829

2930
const [selectedAttribute, setSelectedAttribute] = useState('');
3031
const [stopRows, setStopRows] = useState<IStopRow[]>([]);
3132
const [colorRampOptions, setColorRampOptions] = useState<
32-
ReadonlyJSONObject | undefined
33+
ColorRampOptions | undefined
3334
>();
3435
const [manualStyle, setManualStyle] = useState({
3536
fillColor: '#3399CC',
@@ -48,6 +49,22 @@ const Categorized: React.FC<ISymbologyTabbedDialogWithAttributesProps> = ({
4849
return;
4950
}
5051

52+
const getInitialAttribute = () => {
53+
const layerParams = layer.parameters as IVectorLayer;
54+
return (
55+
layerParams.symbologyState?.value ??
56+
Object.keys(selectableAttributesAndValues)[0]
57+
);
58+
};
59+
const initialAttribute = getInitialAttribute();
60+
const initialValues = Array.from(
61+
selectableAttributesAndValues[initialAttribute] ?? [],
62+
);
63+
const computedInitialMin =
64+
initialValues.length > 0 ? Math.min(...initialValues) : undefined;
65+
const computedInitialMax =
66+
initialValues.length > 0 ? Math.max(...initialValues) : undefined;
67+
5168
useEffect(() => {
5269
const valueColorPairs = VectorUtils.buildColorInfo(layer);
5370

@@ -107,6 +124,13 @@ const Categorized: React.FC<ISymbologyTabbedDialogWithAttributesProps> = ({
107124
layerParams.symbologyState?.value ??
108125
Object.keys(selectableAttributesAndValues)[0];
109126

127+
if (computedInitialMin !== undefined && computedInitialMax !== undefined) {
128+
setColorRampOptions(prev => ({
129+
...prev,
130+
minValue: computedInitialMin,
131+
maxValue: computedInitialMax,
132+
}));
133+
}
110134
setSelectedAttribute(attribute);
111135
}, [selectableAttributesAndValues]);
112136

@@ -123,10 +147,11 @@ const Categorized: React.FC<ISymbologyTabbedDialogWithAttributesProps> = ({
123147
setIsLoading: (isLoading: boolean) => void,
124148
) => {
125149
setColorRampOptions({
126-
selectedFunction: '',
127150
selectedRamp,
128151
numberOfShades: '',
129152
selectedMode: '',
153+
minValue: computedInitialMin,
154+
maxValue: computedInitialMax,
130155
});
131156

132157
const stops = Array.from(
@@ -138,7 +163,7 @@ const Categorized: React.FC<ISymbologyTabbedDialogWithAttributesProps> = ({
138163
selectedRamp,
139164
stops.length,
140165
reverseRamp,
141-
'categorized',
166+
'Categorized',
142167
);
143168

144169
setStopRows(valueColorPairs);
@@ -337,6 +362,9 @@ const Categorized: React.FC<ISymbologyTabbedDialogWithAttributesProps> = ({
337362
classifyFunc={buildColorInfoFromClassification}
338363
showModeRow={false}
339364
showRampSelector={symbologyTab === 'color'}
365+
renderType="Categorized"
366+
initialMin={computedInitialMin}
367+
initialMax={computedInitialMax}
340368
/>
341369
<StopContainer
342370
selectedMethod={''}

packages/base/src/dialogs/symbology/vector_layer/types/Graduated.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,17 @@ const Graduated: React.FC<ISymbologyTabbedDialogWithAttributesProps> = ({
136136
Object.keys(selectableAttributesAndValues)[0];
137137

138138
setSelectedAttribute(attribute);
139+
140+
const values = Array.from(selectableAttributesAndValues[attribute] ?? []);
141+
if (values.length > 0) {
142+
const min = Math.min(...values);
143+
const max = Math.max(...values);
144+
setColorRampOptions(prev => ({
145+
...prev,
146+
minValue: min,
147+
maxValue: max,
148+
}));
149+
}
139150
}, [selectableAttributesAndValues]);
140151

141152
const updateStopRowsBasedOnLayer = () => {
@@ -280,7 +291,7 @@ const Graduated: React.FC<ISymbologyTabbedDialogWithAttributesProps> = ({
280291
selectedRamp,
281292
+numberOfShades,
282293
reverseRamp,
283-
'graduated',
294+
'Graduated',
284295
minValue,
285296
maxValue,
286297
);
@@ -420,7 +431,9 @@ const Graduated: React.FC<ISymbologyTabbedDialogWithAttributesProps> = ({
420431
classifyFunc={buildColorInfoFromClassification}
421432
showModeRow={true}
422433
showRampSelector={symbologyTab === 'color'}
423-
renderType="graduated"
434+
renderType="Graduated"
435+
initialMin={colorRampOptions?.minValue}
436+
initialMax={colorRampOptions?.maxValue}
424437
/>
425438
<StopContainer
426439
selectedMethod={symbologyTab || 'color'}

packages/base/src/types.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { IDict, IJupyterGISWidget } from '@jupytergis/schema';
22
import { WidgetTracker } from '@jupyterlab/apputils';
33
import { Map } from 'ol';
44

5-
import { COLOR_RAMP_DEFINITIONS } from './dialogs/symbology/colorRampUtils';
5+
import { COLOR_RAMP_DEFINITIONS } from '@/src/dialogs/symbology/colorRampUtils';
66

77
export { IDict };
88
export type ValueOf<T> = T[keyof T];
@@ -89,4 +89,11 @@ export interface IColorRampValueControlsProps {
8989
max: number | undefined;
9090
setMax: (v: number | undefined) => void;
9191
rampDef: IColorRampDefinition;
92+
initialMin?: number;
93+
initialMax?: number;
94+
renderType?:
95+
| 'Categorized'
96+
| 'Graduated'
97+
| 'Heatmap'
98+
| 'Singleband PseudoColor';
9299
}

0 commit comments

Comments
 (0)