From 7624e213a3a765435b61d8e20e70173c60926b60 Mon Sep 17 00:00:00 2001 From: Dan Toloudis Date: Mon, 14 Oct 2024 16:48:34 -0700 Subject: [PATCH 1/8] refactor to allow multiple channel settings changes in one --- .../components/App/index.tsx | 12 ++-- .../components/ChannelsWidget.tsx | 14 ++-- .../components/ChannelsWidgetRow/index.tsx | 28 ++++---- .../components/TfEditor/index.tsx | 10 +-- .../components/ViewerStateProvider/index.tsx | 64 +++++++++++-------- .../components/ViewerStateProvider/types.ts | 9 ++- 6 files changed, 75 insertions(+), 62 deletions(-) diff --git a/src/aics-image-viewer/components/App/index.tsx b/src/aics-image-viewer/components/App/index.tsx index be0ad457..d46db77b 100644 --- a/src/aics-image-viewer/components/App/index.tsx +++ b/src/aics-image-viewer/components/App/index.tsx @@ -280,8 +280,8 @@ const App: React.FC = (props) => { // If this is the first load of this image, auto-generate initial LUTs if (initialLoadRef.current || !thisChannelsSettings.controlPoints || !thisChannelsSettings.ramp) { const { ramp, controlPoints } = initializeLut(aimg, channelIndex, props.viewerChannelSettings); - changeChannelSetting(channelIndex, "controlPoints", controlPoints); - changeChannelSetting(channelIndex, "ramp", controlPointsToRamp(ramp)); + changeChannelSetting(channelIndex, {"controlPoints": controlPoints}); + changeChannelSetting(channelIndex, {"ramp": controlPointsToRamp(ramp)}); } else { // try not to update lut from here if we are in play mode // if (playingAxis !== null) { @@ -292,19 +292,19 @@ const App: React.FC = (props) => { const oldRange = channelRangesRef.current[channelIndex]; if (thisChannelsSettings.useControlPoints) { // control points were just automatically remapped - update in state - changeChannelSetting(channelIndex, "controlPoints", thisChannel.lut.controlPoints); + changeChannelSetting(channelIndex, {"controlPoints": thisChannel.lut.controlPoints}); // now manually remap ramp using the channel's old range const controlPoints = rampToControlPoints(thisChannelsSettings.ramp); const newControlPoints = remapControlPointsForChannel(controlPoints, oldRange, thisChannel); - changeChannelSetting(channelIndex, "ramp", controlPointsToRamp(newControlPoints)); + changeChannelSetting(channelIndex, {"ramp": controlPointsToRamp(newControlPoints)}); } else { // ramp was just automatically remapped - update in state const ramp = controlPointsToRamp(thisChannel.lut.controlPoints); - changeChannelSetting(channelIndex, "ramp", ramp); + changeChannelSetting(channelIndex, {"ramp": ramp}); // now manually remap control points using the channel's old range const { controlPoints } = thisChannelsSettings; const newControlPoints = remapControlPointsForChannel(controlPoints, oldRange, thisChannel); - changeChannelSetting(channelIndex, "controlPoints", newControlPoints); + changeChannelSetting(channelIndex, {"controlPoints": newControlPoints}); } } // save the channel's new range for remapping next time diff --git a/src/aics-image-viewer/components/ChannelsWidget.tsx b/src/aics-image-viewer/components/ChannelsWidget.tsx index cfe746c8..1e0eb11e 100644 --- a/src/aics-image-viewer/components/ChannelsWidget.tsx +++ b/src/aics-image-viewer/components/ChannelsWidget.tsx @@ -36,7 +36,7 @@ const ChannelsWidget: React.FC = (props: ChannelsWidgetProp const { channelGroupedByType, channelSettings, channelDataChannels, filterFunc, viewerChannelSettings } = props; const createCheckboxHandler = (key: ChannelStateKey, value: boolean) => (channelArray: number[]) => { - props.changeChannelSetting(channelArray, key, value); + props.changeChannelSetting(channelArray, {[key]: value}); }; const showVolumes = createCheckboxHandler("volumeEnabled", true); @@ -132,18 +132,18 @@ const ChannelsWidget: React.FC = (props: ChannelsWidgetProp for (let i = 0; i < channelDataChannels.length; i++) { const channelData = channelDataChannels[i]; const defaultLut = getDefaultLut(channelData.getHistogram()); - props.changeChannelSetting(i, "controlPoints", defaultLut.controlPoints); - props.changeChannelSetting(i, "ramp", controlPointsToRamp(defaultLut.controlPoints)); - props.changeChannelSetting(i, "useControlPoints", false); + props.changeChannelSetting(i, {"controlPoints": defaultLut.controlPoints}); + props.changeChannelSetting(i, {"ramp": controlPointsToRamp(defaultLut.controlPoints)}); + props.changeChannelSetting(i, {"useControlPoints": false}); } // Reset all other settings. Also, enable volumes on only the first three channels. channelSettings.forEach((_channelSetting, index) => { for (const key of channelStateKeysToReset) { if (key === "volumeEnabled" && index < 3) { - props.changeChannelSetting(index, key, true); + props.changeChannelSetting(index, {[key]: true}); continue; } - props.changeChannelSetting(index, key, defaultChannelState[key]); + props.changeChannelSetting(index, {[key]: defaultChannelState[key]}); } }); @@ -153,7 +153,7 @@ const ChannelsWidget: React.FC = (props: ChannelsWidgetProp // the color map length, so we need to reset the colors manually. if (channelDataChannels.length > PRESET_COLOR_MAP[0].colors.length) { for (let i = PRESET_COLOR_MAP[0].colors.length; i < channelDataChannels.length; i++) { - props.changeChannelSetting(i, "color", defaultChannelState["color"]); + props.changeChannelSetting(i, {"color": defaultChannelState["color"]}); } } }; diff --git a/src/aics-image-viewer/components/ChannelsWidgetRow/index.tsx b/src/aics-image-viewer/components/ChannelsWidgetRow/index.tsx index d119bbb6..c30008c5 100644 --- a/src/aics-image-viewer/components/ChannelsWidgetRow/index.tsx +++ b/src/aics-image-viewer/components/ChannelsWidgetRow/index.tsx @@ -36,25 +36,25 @@ const ChannelsWidgetRow: React.FC = (props: ChannelsWidg const [controlsOpen, setControlsOpen] = useState(false); const changeSettingForThisChannel = useCallback( - (key, value) => changeChannelSetting(index, key, value), + (value) => changeChannelSetting(index, value), [changeChannelSetting, index] ); const volumeCheckHandler = ({ target }: CheckboxChangeEvent): void => { - changeChannelSetting(index, "volumeEnabled", target.checked); + changeChannelSetting(index, {"volumeEnabled": target.checked}); }; const isosurfaceCheckHandler = ({ target }: CheckboxChangeEvent): void => { - changeChannelSetting(index, "isosurfaceEnabled", target.checked); + changeChannelSetting(index, {"isosurfaceEnabled": target.checked}); }; - const onIsovalueChange = ([newValue]: number[]): void => changeSettingForThisChannel("isovalue", newValue); + const onIsovalueChange = ([newValue]: number[]): void => changeSettingForThisChannel({"isovalue": newValue}); const onOpacityChange = ([newValue]: number[]): void => - changeSettingForThisChannel("opacity", newValue / ISOSURFACE_OPACITY_SLIDER_MAX); + changeSettingForThisChannel({"opacity": newValue / ISOSURFACE_OPACITY_SLIDER_MAX}); const onColorChange = (newRGB: ColorObject, _oldRGB?: ColorObject, index?: number): void => { const color = colorObjectToArray(newRGB); - props.changeChannelSetting(index!, "color", color); + props.changeChannelSetting(index!, {"color": color}); }; const createColorPicker = (): React.ReactNode => ( @@ -93,20 +93,20 @@ const ChannelsWidgetRow: React.FC = (props: ChannelsWidg const defaultChannelState = getDefaultChannelState(); if (props.channelState.volumeEnabled) { const defaultLut = getDefaultLut(props.channelDataForChannel.histogram); - props.changeChannelSetting(index, "controlPoints", defaultLut.controlPoints); - props.changeChannelSetting(index, "ramp", controlPointsToRamp(defaultLut.controlPoints)); - props.changeChannelSetting(index, "useControlPoints", defaultChannelState.useControlPoints); + props.changeChannelSetting(index, {"controlPoints": defaultLut.controlPoints}); + props.changeChannelSetting(index, {"ramp": controlPointsToRamp(defaultLut.controlPoints)}); + props.changeChannelSetting(index, {"useControlPoints": defaultChannelState.useControlPoints}); - props.changeChannelSetting(index, "colorizeAlpha", defaultChannelState.colorizeAlpha); - props.changeChannelSetting(index, "colorizeEnabled", defaultChannelState.colorizeEnabled); + props.changeChannelSetting(index, {"colorizeAlpha": defaultChannelState.colorizeAlpha}); + props.changeChannelSetting(index, {"colorizeEnabled": defaultChannelState.colorizeEnabled}); } if (props.channelState.isosurfaceEnabled) { - props.changeChannelSetting(index, "isovalue", defaultChannelState.isovalue); - props.changeChannelSetting(index, "opacity", defaultChannelState.opacity); + props.changeChannelSetting(index, {"isovalue": defaultChannelState.isovalue}); + props.changeChannelSetting(index, {"opacity": defaultChannelState.opacity}); } - props.changeChannelSetting(index, "color", PRESET_COLOR_MAP[0].colors[index] ?? defaultChannelState.color); + props.changeChannelSetting(index, {"color": PRESET_COLOR_MAP[0].colors[index] ?? defaultChannelState.color}); }; const createTFEditor = (): React.ReactNode => { diff --git a/src/aics-image-viewer/components/TfEditor/index.tsx b/src/aics-image-viewer/components/TfEditor/index.tsx index a097d570..9a111fe7 100644 --- a/src/aics-image-viewer/components/TfEditor/index.tsx +++ b/src/aics-image-viewer/components/TfEditor/index.tsx @@ -152,8 +152,8 @@ const TfEditor: React.FC = (props) => { const [selectedPointIdx, setSelectedPointIdx] = useState(null); const [draggedPointIdx, _setDraggedPointIdx] = useState(null); - const _setCPs = useCallback((p: ControlPoint[]) => changeChannelSetting("controlPoints", p), [changeChannelSetting]); - const setRamp = useCallback((ramp: [number, number]) => changeChannelSetting("ramp", ramp), [changeChannelSetting]); + const _setCPs = useCallback((p: ControlPoint[]) => changeChannelSetting({"controlPoints": p}), [changeChannelSetting]); + const setRamp = useCallback((ramp: [number, number]) => changeChannelSetting({"ramp": ramp}), [changeChannelSetting]); // these bits of state need their freshest, most up-to-date values available in mouse event handlers. make refs! const [controlPointsRef, setControlPoints] = useRefWithSetter(_setCPs, props.controlPoints); @@ -425,7 +425,7 @@ const TfEditor: React.FC = (props) => { {createTFGeneratorButton("bestFitXF", "Auto 2", "Ramp over the middle 80% of data.")} changeChannelSetting("useControlPoints", e.target.checked)} + onChange={(e) => changeChannelSetting({"useControlPoints": e.target.checked})} style={{ marginLeft: "auto" }} > Advanced @@ -521,14 +521,14 @@ const TfEditor: React.FC = (props) => { label={ changeChannelSetting("colorizeEnabled", e.target.checked)} + onChange={(e) => changeChannelSetting({"colorizeEnabled": e.target.checked})} > Colorize } max={1} start={props.colorizeAlpha} - onUpdate={(values) => changeChannelSetting("colorizeAlpha", values[0])} + onUpdate={(values) => changeChannelSetting({"colorizeAlpha": values[0]})} hideSlider={!props.colorizeEnabled} /> diff --git a/src/aics-image-viewer/components/ViewerStateProvider/index.tsx b/src/aics-image-viewer/components/ViewerStateProvider/index.tsx index dc9a71e4..47dc6143 100644 --- a/src/aics-image-viewer/components/ViewerStateProvider/index.tsx +++ b/src/aics-image-viewer/components/ViewerStateProvider/index.tsx @@ -12,6 +12,7 @@ import type { import { RenderMode, ViewMode } from "../../shared/enums"; import { ColorArray } from "../../shared/utils/colorRepresentations"; import { getDefaultViewerState } from "../../shared/constants"; +import type { ChannelStateKey } from "./types"; const isObject = (val: T): val is Extract> => typeof val === "object" && val !== null && !Array.isArray(val); @@ -68,52 +69,61 @@ const viewerSettingsReducer = ( } }; -/** Utility type to explicitly assert that one or more properties will *not* be defined on an object */ -type WithExplicitlyUndefined = T & { [key in K]?: never }; +enum ChannelSettingActionType { + UniformUpdate = "UniformUpdate", + ArrayUpdate = "ArrayUpdate", + Init = "Init", +} /** Set channel setting `key` on one or more channels specified by `index` to value `value`. */ -type ChannelSettingUniformUpdateAction = { +type ChannelSettingUniformUpdateAction = { + type: ChannelSettingActionType.UniformUpdate; index: number | number[]; - key: K; - value: ChannelState[K]; + value: Record; }; /** Set the values of channel setting `key` for all channels from an array of values ordered by channel index */ -type ChannelSettingArrayUpdateAction = { +type ChannelSettingArrayUpdateAction = { + type: ChannelSettingActionType.ArrayUpdate; key: K; value: ChannelState[K][]; }; /** Initialize list of channel states */ type ChannelSettingInitAction = { + type: ChannelSettingActionType.Init; value: ChannelState[]; }; -type ChannelStateAction = + +type ChannelStateAction = | ChannelSettingUniformUpdateAction - | WithExplicitlyUndefined<"index", ChannelSettingArrayUpdateAction> - | WithExplicitlyUndefined<"index" | "key", ChannelSettingInitAction>; + | ChannelSettingArrayUpdateAction + | ChannelSettingInitAction; -const channelSettingsReducer = ( +const channelSettingsReducer = ( channelSettings: ChannelState[], - { index, key, value }: ChannelStateAction + payload: ChannelStateAction ): ChannelState[] => { - if (key === undefined) { + if (payload.type === ChannelSettingActionType.Init) { // ChannelSettingInitAction - return value as ChannelState[]; - } else if (index === undefined) { + return payload.value as ChannelState[]; + } else if (payload.type === ChannelSettingActionType.ArrayUpdate) { // ChannelSettingArrayUpdateAction return channelSettings.map((channel, idx) => { - return value[idx] ? { ...channel, [key]: value[idx] } : channel; + return payload.value[idx] ? { ...channel, [payload.key]: payload.value[idx] } : channel; }); - } else if (Array.isArray(index)) { - // ChannelSettingUniformUpdateAction on potentially multiple channels - return channelSettings.map((channel, idx) => (index.includes(idx) ? { ...channel, [key]: value } : channel)); } else { - // ChannelSettingUniformUpdateAction on a single channel - const newSettings = channelSettings.slice(); - if (index >= 0 && index < channelSettings.length) { - newSettings[index] = { ...newSettings[index], [key]: value }; + // type is ChannelSettingActionType.UniformUpdate + if (Array.isArray(payload.index)) { + // ChannelSettingUniformUpdateAction on potentially multiple channels + return channelSettings.map((channel, idx) => ((payload.index as number[]).includes(idx) ? { ...channel, ...payload.value } : channel)); + } else { + // ChannelSettingUniformUpdateAction on a single channel + const newSettings = channelSettings.slice(); + if (payload.index >= 0 && payload.index < channelSettings.length) { + newSettings[payload.index] = { ...newSettings[payload.index], ...payload.value }; + } + return newSettings; } - return newSettings; } }; @@ -147,13 +157,13 @@ const ViewerStateProvider: React.FC<{ viewerSettings?: Partial }> = const changeViewerSetting = useCallback((key, value) => viewerDispatch({ key, value }), []); - const changeChannelSetting = useCallback((index, key, value) => { - channelDispatch({ index, key, value }); + const changeChannelSetting = useCallback((index, value) => { + channelDispatch({ type: ChannelSettingActionType.UniformUpdate, index, value } as ChannelSettingUniformUpdateAction); }, []); - const applyColorPresets = useCallback((value: ColorArray[]): void => channelDispatch({ key: "color", value }), []); + const applyColorPresets = useCallback((value: ColorArray[]): void => channelDispatch({ type: ChannelSettingActionType.ArrayUpdate, key:"color", value}), []); - const setChannelSettings = useCallback((channels: ChannelState[]) => channelDispatch({ value: channels }), []); + const setChannelSettings = useCallback((channels: ChannelState[]) => channelDispatch({ type: ChannelSettingActionType.Init, value: channels }), []); // Sync viewer settings prop with state // React docs seem to be fine with syncing state with props directly in the render function, but that caused an diff --git a/src/aics-image-viewer/components/ViewerStateProvider/types.ts b/src/aics-image-viewer/components/ViewerStateProvider/types.ts index c8bfadb3..60e6b512 100644 --- a/src/aics-image-viewer/components/ViewerStateProvider/types.ts +++ b/src/aics-image-viewer/components/ViewerStateProvider/types.ts @@ -71,10 +71,13 @@ export interface ChannelState { export type ChannelStateKey = keyof ChannelState; export type ChannelSettingUpdater = ( index: number | number[], - key: K, - value: ChannelState[K] + value: Partial> +) => void; + +export type SingleChannelSettingUpdater = ( + value: Partial> + // key: K, value: ChannelState[K]) => void; ) => void; -export type SingleChannelSettingUpdater = (key: K, value: ChannelState[K]) => void; export type ViewerStateContextType = ViewerState & { channelSettings: ChannelState[]; From bd47b1fe1bf91b430ecadcc4e9b8aeaca100ab90 Mon Sep 17 00:00:00 2001 From: Dan Toloudis Date: Wed, 16 Oct 2024 14:02:47 -0700 Subject: [PATCH 2/8] post-merge fixup --- src/aics-image-viewer/components/App/index.tsx | 4 ++-- .../components/ViewerStateProvider/index.tsx | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/aics-image-viewer/components/App/index.tsx b/src/aics-image-viewer/components/App/index.tsx index bc549af2..c6da6870 100644 --- a/src/aics-image-viewer/components/App/index.tsx +++ b/src/aics-image-viewer/components/App/index.tsx @@ -610,8 +610,8 @@ const App: React.FC = (props) => { for (let i = 0; i < channelSettings.length; i++) { if (channelsAwaitingReset.has(i)) { const { ramp, controlPoints } = initializeLut(image, i, getCurrentViewerChannelSettings()); - changeChannelSetting(i, "controlPoints", controlPoints); - changeChannelSetting(i, "ramp", controlPointsToRamp(ramp)); + changeChannelSetting(i, {"controlPoints": controlPoints}); + changeChannelSetting(i, {"ramp": controlPointsToRamp(ramp)}); onResetChannel(i); } } diff --git a/src/aics-image-viewer/components/ViewerStateProvider/index.tsx b/src/aics-image-viewer/components/ViewerStateProvider/index.tsx index 0375a0e7..961c5f4d 100644 --- a/src/aics-image-viewer/components/ViewerStateProvider/index.tsx +++ b/src/aics-image-viewer/components/ViewerStateProvider/index.tsx @@ -7,6 +7,7 @@ import type { ViewerSettingUpdater, ChannelSettingUpdater, ChannelState, + ChannelStateKey, PartialIfObject, } from "./types"; import { RenderMode, ViewMode } from "../../shared/enums"; From b670620b1f2dd079ca1e867adf27e3fb08344d05 Mon Sep 17 00:00:00 2001 From: Dan Toloudis Date: Wed, 16 Oct 2024 15:39:19 -0700 Subject: [PATCH 3/8] rename payload to action --- .../components/ViewerStateProvider/index.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/aics-image-viewer/components/ViewerStateProvider/index.tsx b/src/aics-image-viewer/components/ViewerStateProvider/index.tsx index 961c5f4d..13f136a0 100644 --- a/src/aics-image-viewer/components/ViewerStateProvider/index.tsx +++ b/src/aics-image-viewer/components/ViewerStateProvider/index.tsx @@ -109,26 +109,26 @@ type ChannelStateAction = const channelSettingsReducer = ( channelSettings: ChannelState[], - payload: ChannelStateAction + action: ChannelStateAction ): ChannelState[] => { - if (payload.type === ChannelSettingActionType.Init) { + if (action.type === ChannelSettingActionType.Init) { // ChannelSettingInitAction - return payload.value as ChannelState[]; - } else if (payload.type === ChannelSettingActionType.ArrayUpdate) { + return action.value as ChannelState[]; + } else if (action.type === ChannelSettingActionType.ArrayUpdate) { // ChannelSettingArrayUpdateAction return channelSettings.map((channel, idx) => { - return payload.value[idx] ? { ...channel, [payload.key]: payload.value[idx] } : channel; + return action.value[idx] ? { ...channel, [action.key]: action.value[idx] } : channel; }); } else { // type is ChannelSettingActionType.UniformUpdate - if (Array.isArray(payload.index)) { + if (Array.isArray(action.index)) { // ChannelSettingUniformUpdateAction on potentially multiple channels - return channelSettings.map((channel, idx) => ((payload.index as number[]).includes(idx) ? { ...channel, ...payload.value } : channel)); + return channelSettings.map((channel, idx) => ((action.index as number[]).includes(idx) ? { ...channel, ...action.value } : channel)); } else { // ChannelSettingUniformUpdateAction on a single channel const newSettings = channelSettings.slice(); - if (payload.index >= 0 && payload.index < channelSettings.length) { - newSettings[payload.index] = { ...newSettings[payload.index], ...payload.value }; + if (action.index >= 0 && action.index < channelSettings.length) { + newSettings[action.index] = { ...newSettings[action.index], ...action.value }; } return newSettings; } From 88773947aa27ebd162a5b3ea74f6a6d03add0853 Mon Sep 17 00:00:00 2001 From: Dan Toloudis Date: Wed, 16 Oct 2024 15:50:31 -0700 Subject: [PATCH 4/8] add partial to be able to skip a type coercion --- .../components/ViewerStateProvider/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aics-image-viewer/components/ViewerStateProvider/index.tsx b/src/aics-image-viewer/components/ViewerStateProvider/index.tsx index 13f136a0..952b7e0a 100644 --- a/src/aics-image-viewer/components/ViewerStateProvider/index.tsx +++ b/src/aics-image-viewer/components/ViewerStateProvider/index.tsx @@ -87,7 +87,7 @@ enum ChannelSettingActionType { type ChannelSettingUniformUpdateAction = { type: ChannelSettingActionType.UniformUpdate; index: number | number[]; - value: Record; + value: Partial>; }; /** Set the values of channel setting `key` for all channels from an array of values ordered by channel index */ type ChannelSettingArrayUpdateAction = { @@ -178,7 +178,7 @@ const ViewerStateProvider: React.FC<{ viewerSettings?: Partial }> = const changeViewerSetting = useCallback((key, value) => viewerDispatch({ key, value }), []); const changeChannelSetting = useCallback((index, value) => { - channelDispatch({ type: ChannelSettingActionType.UniformUpdate, index, value } as ChannelSettingUniformUpdateAction); + channelDispatch({ type: ChannelSettingActionType.UniformUpdate, index, value }); }, []); const applyColorPresets = useCallback((value: ColorArray[]): void => channelDispatch({ type: ChannelSettingActionType.ArrayUpdate, key:"color", value}), []); From 50b844ae5d69479f01f4eb570b91af3377d36c88 Mon Sep 17 00:00:00 2001 From: Dan Toloudis Date: Wed, 16 Oct 2024 15:52:22 -0700 Subject: [PATCH 5/8] cleanup --- src/aics-image-viewer/components/ViewerStateProvider/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/aics-image-viewer/components/ViewerStateProvider/types.ts b/src/aics-image-viewer/components/ViewerStateProvider/types.ts index c60d2e2b..53b8609d 100644 --- a/src/aics-image-viewer/components/ViewerStateProvider/types.ts +++ b/src/aics-image-viewer/components/ViewerStateProvider/types.ts @@ -78,7 +78,6 @@ export type ChannelSettingUpdater = ( export type SingleChannelSettingUpdater = ( value: Partial> - // key: K, value: ChannelState[K]) => void; ) => void; export type ResetState = { From 2aae2e17f54280eb3a24aae86b919ed0498fdd5d Mon Sep 17 00:00:00 2001 From: Dan Toloudis Date: Fri, 18 Oct 2024 09:13:55 -0700 Subject: [PATCH 6/8] combine changes --- src/aics-image-viewer/components/App/index.tsx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/aics-image-viewer/components/App/index.tsx b/src/aics-image-viewer/components/App/index.tsx index c6da6870..33087d4d 100644 --- a/src/aics-image-viewer/components/App/index.tsx +++ b/src/aics-image-viewer/components/App/index.tsx @@ -266,8 +266,7 @@ const App: React.FC = (props) => { ) { const viewerChannelSettings = getCurrentViewerChannelSettings(); const { ramp, controlPoints } = initializeLut(aimg, channelIndex, viewerChannelSettings); - changeChannelSetting(channelIndex, {"controlPoints": controlPoints}); - changeChannelSetting(channelIndex, {"ramp": controlPointsToRamp(ramp)}); + changeChannelSetting(channelIndex, {"controlPoints": controlPoints, "ramp":controlPointsToRamp(ramp)}); onResetChannel(channelIndex); } else { // try not to update lut from here if we are in play mode @@ -279,19 +278,17 @@ const App: React.FC = (props) => { const oldRange = channelRangesRef.current[channelIndex]; if (thisChannelsSettings.useControlPoints) { // control points were just automatically remapped - update in state - changeChannelSetting(channelIndex, {"controlPoints": thisChannel.lut.controlPoints}); // now manually remap ramp using the channel's old range const rampControlPoints = rampToControlPoints(thisChannelsSettings.ramp); const remappedRampControlPoints = remapControlPointsForChannel(rampControlPoints, oldRange, thisChannel); - changeChannelSetting(channelIndex, {"ramp": controlPointsToRamp(remappedRampControlPoints)}); + changeChannelSetting(channelIndex, {"ramp": controlPointsToRamp(remappedRampControlPoints), "controlPoints": thisChannel.lut.controlPoints}); } else { // ramp was just automatically remapped - update in state const ramp = controlPointsToRamp(thisChannel.lut.controlPoints); - changeChannelSetting(channelIndex, {"ramp": ramp}); // now manually remap control points using the channel's old range const { controlPoints } = thisChannelsSettings; const remappedControlPoints = remapControlPointsForChannel(controlPoints, oldRange, thisChannel); - changeChannelSetting(channelIndex, {"controlPoints": remappedControlPoints}); + changeChannelSetting(channelIndex, {"controlPoints": remappedControlPoints, "ramp": ramp}); } } }; @@ -610,8 +607,7 @@ const App: React.FC = (props) => { for (let i = 0; i < channelSettings.length; i++) { if (channelsAwaitingReset.has(i)) { const { ramp, controlPoints } = initializeLut(image, i, getCurrentViewerChannelSettings()); - changeChannelSetting(i, {"controlPoints": controlPoints}); - changeChannelSetting(i, {"ramp": controlPointsToRamp(ramp)}); + changeChannelSetting(i, {"controlPoints": controlPoints, "ramp": controlPointsToRamp(ramp)}); onResetChannel(i); } } From 3e39c7d50452d4d8fe185ca13f777d4841220894 Mon Sep 17 00:00:00 2001 From: toloudis Date: Fri, 18 Oct 2024 09:31:11 -0700 Subject: [PATCH 7/8] autoformat and remove unneeded type coercion --- .../components/ViewerStateProvider/index.tsx | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/aics-image-viewer/components/ViewerStateProvider/index.tsx b/src/aics-image-viewer/components/ViewerStateProvider/index.tsx index 952b7e0a..21a90dc5 100644 --- a/src/aics-image-viewer/components/ViewerStateProvider/index.tsx +++ b/src/aics-image-viewer/components/ViewerStateProvider/index.tsx @@ -1,20 +1,21 @@ import React, { useCallback, useContext, useEffect, useMemo, useReducer, useRef } from "react"; +import { getDefaultViewerChannelSettings, getDefaultViewerState } from "../../shared/constants"; +import { RenderMode, ViewMode } from "../../shared/enums"; +import { ColorArray } from "../../shared/utils/colorRepresentations"; +import { useConstructor } from "../../shared/utils/hooks"; import type { - ViewerStateContextType, - ViewerState, - ViewerSettingChangeHandlers, - ViewerSettingUpdater, ChannelSettingUpdater, ChannelState, ChannelStateKey, PartialIfObject, + ViewerSettingChangeHandlers, + ViewerSettingUpdater, + ViewerState, + ViewerStateContextType, } from "./types"; -import { RenderMode, ViewMode } from "../../shared/enums"; -import { ColorArray } from "../../shared/utils/colorRepresentations"; -import { getDefaultViewerChannelSettings, getDefaultViewerState } from "../../shared/constants"; + import ResetStateProvider from "./ResetStateProvider"; -import { useConstructor } from "../../shared/utils/hooks"; const isObject = (val: T): val is Extract> => typeof val === "object" && val !== null && !Array.isArray(val); @@ -101,7 +102,6 @@ type ChannelSettingInitAction = { value: ChannelState[]; }; - type ChannelStateAction = | ChannelSettingUniformUpdateAction | ChannelSettingArrayUpdateAction @@ -113,7 +113,7 @@ const channelSettingsReducer = ( ): ChannelState[] => { if (action.type === ChannelSettingActionType.Init) { // ChannelSettingInitAction - return action.value as ChannelState[]; + return action.value; } else if (action.type === ChannelSettingActionType.ArrayUpdate) { // ChannelSettingArrayUpdateAction return channelSettings.map((channel, idx) => { @@ -123,7 +123,9 @@ const channelSettingsReducer = ( // type is ChannelSettingActionType.UniformUpdate if (Array.isArray(action.index)) { // ChannelSettingUniformUpdateAction on potentially multiple channels - return channelSettings.map((channel, idx) => ((action.index as number[]).includes(idx) ? { ...channel, ...action.value } : channel)); + return channelSettings.map((channel, idx) => + (action.index as number[]).includes(idx) ? { ...channel, ...action.value } : channel + ); } else { // ChannelSettingUniformUpdateAction on a single channel const newSettings = channelSettings.slice(); @@ -181,9 +183,15 @@ const ViewerStateProvider: React.FC<{ viewerSettings?: Partial }> = channelDispatch({ type: ChannelSettingActionType.UniformUpdate, index, value }); }, []); - const applyColorPresets = useCallback((value: ColorArray[]): void => channelDispatch({ type: ChannelSettingActionType.ArrayUpdate, key:"color", value}), []); + const applyColorPresets = useCallback( + (value: ColorArray[]): void => channelDispatch({ type: ChannelSettingActionType.ArrayUpdate, key: "color", value }), + [] + ); - const setChannelSettings = useCallback((channels: ChannelState[]) => channelDispatch({ type: ChannelSettingActionType.Init, value: channels }), []); + const setChannelSettings = useCallback( + (channels: ChannelState[]) => channelDispatch({ type: ChannelSettingActionType.Init, value: channels }), + [] + ); // Sync viewer settings prop with state // React docs seem to be fine with syncing state with props directly in the render function, but that caused an @@ -243,7 +251,7 @@ const ViewerStateProvider: React.FC<{ viewerSettings?: Partial }> = */ export function connectToViewerState< Keys extends keyof ViewerStateContextType, - Props extends Pick + Props extends Pick, >(component: React.ComponentType, keys: Keys[]): React.FC> { const MemoedComponent = React.memo(component); From 39ae75292c378c8d31b6d51f4131624a3b93cb03 Mon Sep 17 00:00:00 2001 From: toloudis Date: Fri, 18 Oct 2024 09:40:48 -0700 Subject: [PATCH 8/8] autoformat --- .../components/App/index.tsx | 70 ++++++++++--------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/src/aics-image-viewer/components/App/index.tsx b/src/aics-image-viewer/components/App/index.tsx index 33087d4d..ad587db9 100644 --- a/src/aics-image-viewer/components/App/index.tsx +++ b/src/aics-image-viewer/components/App/index.tsx @@ -1,61 +1,60 @@ // 3rd Party Imports import { CreateLoaderOptions, + IVolumeLoader, LoadSpec, - VolumeLoaderContext, + PrefetchDirection, RENDERMODE_PATHTRACE, RENDERMODE_RAYMARCH, View3d, Volume, - IVolumeLoader, - PrefetchDirection, VolumeFileFormat, + VolumeLoaderContext, } from "@aics/volume-viewer"; import { Layout } from "antd"; -import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react"; import { debounce } from "lodash"; +import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react"; import { Box3, Vector3 } from "three"; -import type { AppProps, ControlVisibilityFlags, UseImageEffectType } from "./types"; -import type { ChannelState } from "../ViewerStateProvider/types"; - -import { useStateWithGetter, useConstructor } from "../../shared/utils/hooks"; +import { + AXIS_MARGIN_DEFAULT, + CACHE_MAX_SIZE, + CONTROL_PANEL_CLOSE_WIDTH, + getDefaultChannelColor, + getDefaultViewerState, + QUEUE_MAX_LOW_PRIORITY_SIZE, + QUEUE_MAX_SIZE, + SCALE_BAR_MARGIN_DEFAULT, +} from "../../shared/constants"; +import { ImageType, RenderMode, ViewMode } from "../../shared/enums"; +import { activeAxisMap, AxisName, IsosurfaceFormat, MetadataRecord, PerAxis } from "../../shared/types"; +import { colorArrayToFloats } from "../../shared/utils/colorRepresentations"; import { controlPointsToRamp, initializeLut, rampToControlPoints, remapControlPointsForChannel, } from "../../shared/utils/controlPointsToLut"; -import { makeChannelIndexGrouping, ChannelGrouping } from "../../shared/utils/viewerChannelSettings"; -import { activeAxisMap, AxisName, IsosurfaceFormat, MetadataRecord, PerAxis } from "../../shared/types"; -import { ImageType, RenderMode, ViewMode } from "../../shared/enums"; -import { - CONTROL_PANEL_CLOSE_WIDTH, - AXIS_MARGIN_DEFAULT, - SCALE_BAR_MARGIN_DEFAULT, - CACHE_MAX_SIZE, - QUEUE_MAX_SIZE, - QUEUE_MAX_LOW_PRIORITY_SIZE, - getDefaultViewerState, - getDefaultChannelColor, -} from "../../shared/constants"; +import { useConstructor, useStateWithGetter } from "../../shared/utils/hooks"; import PlayControls from "../../shared/utils/playControls"; -import { colorArrayToFloats } from "../../shared/utils/colorRepresentations"; import { - gammaSliderToImageValues, - densitySliderToImageValue, - brightnessSliderToImageValue, alphaSliderToImageValue, + brightnessSliderToImageValue, + densitySliderToImageValue, + gammaSliderToImageValues, } from "../../shared/utils/sliderValuesToImageValues"; +import { ChannelGrouping, makeChannelIndexGrouping } from "../../shared/utils/viewerChannelSettings"; import { initializeOneChannelSetting } from "../../shared/utils/viewerState"; +import type { ChannelState } from "../ViewerStateProvider/types"; +import type { AppProps, ControlVisibilityFlags, UseImageEffectType } from "./types"; -import { ViewerStateContext } from "../ViewerStateProvider"; -import ChannelUpdater from "./ChannelUpdater"; -import ControlPanel from "../ControlPanel"; -import Toolbar from "../Toolbar"; import CellViewerCanvasWrapper from "../CellViewerCanvasWrapper"; -import StyleProvider from "../StyleProvider"; +import ControlPanel from "../ControlPanel"; import { useErrorAlert } from "../ErrorAlert"; +import StyleProvider from "../StyleProvider"; +import Toolbar from "../Toolbar"; +import { ViewerStateContext } from "../ViewerStateProvider"; +import ChannelUpdater from "./ChannelUpdater"; import "../../assets/styles/globals.css"; import "./styles.css"; @@ -266,7 +265,7 @@ const App: React.FC = (props) => { ) { const viewerChannelSettings = getCurrentViewerChannelSettings(); const { ramp, controlPoints } = initializeLut(aimg, channelIndex, viewerChannelSettings); - changeChannelSetting(channelIndex, {"controlPoints": controlPoints, "ramp":controlPointsToRamp(ramp)}); + changeChannelSetting(channelIndex, { controlPoints: controlPoints, ramp: controlPointsToRamp(ramp) }); onResetChannel(channelIndex); } else { // try not to update lut from here if we are in play mode @@ -281,14 +280,17 @@ const App: React.FC = (props) => { // now manually remap ramp using the channel's old range const rampControlPoints = rampToControlPoints(thisChannelsSettings.ramp); const remappedRampControlPoints = remapControlPointsForChannel(rampControlPoints, oldRange, thisChannel); - changeChannelSetting(channelIndex, {"ramp": controlPointsToRamp(remappedRampControlPoints), "controlPoints": thisChannel.lut.controlPoints}); + changeChannelSetting(channelIndex, { + ramp: controlPointsToRamp(remappedRampControlPoints), + controlPoints: thisChannel.lut.controlPoints, + }); } else { // ramp was just automatically remapped - update in state const ramp = controlPointsToRamp(thisChannel.lut.controlPoints); // now manually remap control points using the channel's old range const { controlPoints } = thisChannelsSettings; const remappedControlPoints = remapControlPointsForChannel(controlPoints, oldRange, thisChannel); - changeChannelSetting(channelIndex, {"controlPoints": remappedControlPoints, "ramp": ramp}); + changeChannelSetting(channelIndex, { controlPoints: remappedControlPoints, ramp: ramp }); } } }; @@ -607,7 +609,7 @@ const App: React.FC = (props) => { for (let i = 0; i < channelSettings.length; i++) { if (channelsAwaitingReset.has(i)) { const { ramp, controlPoints } = initializeLut(image, i, getCurrentViewerChannelSettings()); - changeChannelSetting(i, {"controlPoints": controlPoints, "ramp": controlPointsToRamp(ramp)}); + changeChannelSetting(i, { controlPoints: controlPoints, ramp: controlPointsToRamp(ramp) }); onResetChannel(i); } }