diff --git a/client/component/src/AxialSelectionConfig.tsx b/client/component/src/AxialSelectionConfig.tsx
index 0b43791..b842ccf 100644
--- a/client/component/src/AxialSelectionConfig.tsx
+++ b/client/component/src/AxialSelectionConfig.tsx
@@ -28,7 +28,11 @@ function AxialSelectionConfig(props: AxialSelectionConfigProps) {
return selection.dimension === 0 ? (
-
+
key="x length"
label="x length"
@@ -46,7 +50,11 @@ function AxialSelectionConfig(props: AxialSelectionConfigProps) {
) : (
-
+
key="y length"
label="y length"
diff --git a/client/component/src/ClearSelectionsBtn.tsx b/client/component/src/ClearSelectionsBtn.tsx
index f541edc..d53398c 100644
--- a/client/component/src/ClearSelectionsBtn.tsx
+++ b/client/component/src/ClearSelectionsBtn.tsx
@@ -1,4 +1,3 @@
-import type BaseSelection from './selections/BaseSelection';
import { Btn } from '@h5web/lib';
import type { SelectionHandler } from './selections/utils';
@@ -6,12 +5,8 @@ import type { SelectionHandler } from './selections/utils';
* Props for the `ClearSelectionsBtn` component.
*/
interface ClearSelectionsBtnProps {
- /** The current selections */
- selections: BaseSelection[];
/** The function to call to update the selections state */
updateSelection: SelectionHandler;
- /** The ID of the current selection */
- currentSelectionID: string | null;
/** The function to call to update the current selection ID */
updateCurrentSelectionID: (s: string | null) => void;
/** Indicates whether the component is disabled (optional) */
diff --git a/client/component/src/PlotToolbar.tsx b/client/component/src/PlotToolbar.tsx
index 754bd2a..1b24ea2 100644
--- a/client/component/src/PlotToolbar.tsx
+++ b/client/component/src/PlotToolbar.tsx
@@ -21,7 +21,6 @@ import { TbAxisX, TbAxisY, TbGridDots } from 'react-icons/tb';
import AspectConfigModal from './AspectConfigModal';
import AxisConfigModal from './AxisConfigModal';
-import type BaseSelection from './selections/BaseSelection';
import { BatonConfigModal } from './BatonConfigModal';
import ClearSelectionsBtn from './ClearSelectionsBtn';
import InteractionModeToggle from './InteractionModeToggle';
@@ -163,14 +162,14 @@ function PlotToolbar(props: PropsWithChildren): JSX.Element {
];
const selectionConfig = SelectionConfig({
- selections: selections as BaseSelection[],
+ selections,
updateSelection,
- currentSelectionID: currentSelectionID,
+ currentSelectionID,
updateCurrentSelectionID: setCurrentSelectionID,
icon: MdOutlineShapeLine as IIconType,
domain: value.dDomain,
customDomain: value.dCustomDomain,
- showSelectionConfig: showSelectionConfig,
+ showSelectionConfig,
updateShowSelectionConfig: setShowSelectionConfig,
hasBaton: selectBaton,
});
@@ -306,9 +305,7 @@ function PlotToolbar(props: PropsWithChildren): JSX.Element {
overflows.push(
diff --git a/client/component/src/SelectionConfig.tsx b/client/component/src/SelectionConfig.tsx
index 7f9582d..3869b9e 100644
--- a/client/component/src/SelectionConfig.tsx
+++ b/client/component/src/SelectionConfig.tsx
@@ -1,5 +1,4 @@
import Modeless from './Modeless';
-import type BaseSelection from './selections/BaseSelection';
import { getSelectionLabel } from './selections/utils';
import AxialSelection from './selections/AxialSelection';
import RectangularSelection from './selections/RectangularSelection';
@@ -37,7 +36,7 @@ export const SELECTION_ICONS = {
*/
interface SelectionConfigProps {
/** The current selections */
- selections: BaseSelection[];
+ selections: SelectionBase[];
/** Handles updating selection */
updateSelection?: SelectionHandler;
/** The ID of the current selection (optional) */
@@ -73,7 +72,7 @@ function SelectionConfig(props: SelectionConfigProps) {
updateSelection,
hasBaton,
} = props;
- let currentSelection: BaseSelection | null = null;
+ let currentSelection: SelectionBase | null = null;
if (selections.length > 0) {
currentSelection =
selections.find((s) => s.id === currentSelectionID) ?? selections[0];
@@ -86,7 +85,7 @@ function SelectionConfig(props: SelectionConfigProps) {
if (currentSelectionID) {
const selection = selections.find((s) => s.id === currentSelectionID);
if (selection) {
- let lastSelection: BaseSelection | undefined;
+ let lastSelection: SelectionBase | undefined;
if (!Object.hasOwn(selections, 'findLast')) {
// workaround missing method
const oSelections = selections.filter(
@@ -118,11 +117,8 @@ function SelectionConfig(props: SelectionConfigProps) {
);
if (currentSelection !== null) {
- const cSelection: BaseSelection = currentSelection;
- const colour = (cSelection.colour ??
- ('defaultColour' in cSelection
- ? cSelection.defaultColour
- : '#000000')) as string;
+ const cSelection: SelectionBase = currentSelection;
+ const colour = cSelection.defaultColour;
modeless.push(
@@ -148,6 +144,7 @@ function SelectionConfig(props: SelectionConfigProps) {
)}
);
+ const disabled = !hasBaton;
modeless.push(
key="name"
@@ -159,7 +156,7 @@ function SelectionConfig(props: SelectionConfigProps) {
updateSelection(cSelection);
}
}}
- disabled={!hasBaton}
+ disabled={disabled}
/>
);
modeless.push(
@@ -177,39 +174,39 @@ function SelectionConfig(props: SelectionConfigProps) {
}}
decimalPlaces={2}
isValid={(v) => isValidPositiveNumber(v, 1, true)}
- disabled={!hasBaton}
+ disabled={disabled}
/>
);
- if (AxialSelection.isShape(cSelection as SelectionBase)) {
+ if (AxialSelection.isShape(cSelection)) {
modeless.push(
AxialSelectionConfig({
- selection: cSelection as AxialSelection,
+ selection: cSelection,
updateSelection,
- disabled: !hasBaton,
+ disabled,
})
);
- } else if (LinearSelection.isShape(cSelection as SelectionBase)) {
+ } else if (LinearSelection.isShape(cSelection)) {
modeless.push(
LinearSelectionConfig({
- selection: cSelection as LinearSelection,
+ selection: cSelection,
updateSelection,
- disabled: !hasBaton,
+ disabled,
})
);
- } else if (RectangularSelection.isShape(cSelection as SelectionBase)) {
+ } else if (RectangularSelection.isShape(cSelection)) {
modeless.push(
RectangularSelectionConfig({
- selection: cSelection as RectangularSelection,
+ selection: cSelection,
updateSelection,
- disabled: !hasBaton,
+ disabled,
})
);
- } else if (PolygonalSelection.isShape(cSelection as SelectionBase)) {
+ } else if (PolygonalSelection.isShape(cSelection)) {
modeless.push(
PolygonalSelectionConfig({
- selection: cSelection as PolygonalSelection,
+ selection: cSelection,
updateSelection,
- disabled: !hasBaton,
+ disabled,
})
);
}
@@ -218,7 +215,7 @@ function SelectionConfig(props: SelectionConfigProps) {
{
if (window.confirm('Clear selection?')) {
handleDeleteSelection();
diff --git a/client/component/src/SelectionConfigComponents.tsx b/client/component/src/SelectionConfigComponents.tsx
index 7b32089..e0368ce 100644
--- a/client/component/src/SelectionConfigComponents.tsx
+++ b/client/component/src/SelectionConfigComponents.tsx
@@ -1,15 +1,17 @@
-import type BaseSelection from './selections/BaseSelection';
import type OrientableSelection from './selections/OrientableSelection';
import { isNumber } from './utils';
import LabelledInput from './LabelledInput';
-import { SelectionHandler } from './selections/utils';
+import { SelectionBase, SelectionHandler } from './selections/utils';
/**
* Props for the `AngleInput` component.
*/
interface AngleInputProps {
+ /** The selection for which the angle value is being configured */
selection: OrientableSelection;
+ /** Function to handle updating angle of selection */
updateSelection?: SelectionHandler;
+ /** If input component is disabled (optional) */
disabled?: boolean;
}
@@ -41,31 +43,33 @@ function AngleInput(props: AngleInputProps) {
}
/**
- * Props for the `XInput` component.
+ * Props for `XInput` and `YInput` components.
*/
-interface XInputProps {
- selection: BaseSelection;
+interface StartInputProps {
+ /** The selection for which the start value is being configured */
+ selection: SelectionBase;
+ /** Function to handle updating start of selection */
updateSelection?: SelectionHandler;
+ /** If input component is disabled (optional) */
disabled?: boolean;
}
/**
* Render a labelled inout for x.
- * @param {XInputProps} props - The component props.
+ * @param {StartInputProps} props - The component props.
* @returns {JSX.Element} The rendered component.
*/
-function XInput(props: XInputProps) {
+function XInput(props: StartInputProps) {
const { selection, updateSelection, disabled } = props;
return (
key="x"
label="x"
- input={selection.vStart.x}
+ input={selection.start[0]}
decimalPlaces={8}
updateValue={(x: number) => {
- selection.start[0] = x;
- selection.vStart.x = x;
+ selection.setStart(0, x);
if (updateSelection) {
updateSelection(selection);
}
@@ -76,35 +80,22 @@ function XInput(props: XInputProps) {
);
}
-/**
- * Props for the `YInput` component.
- */
-interface YInputProps {
- /** The selection for which the y values are being configured */
- selection: BaseSelection;
- /** Function to handle updating y of selection */
- updateSelection?: SelectionHandler;
- /** If input component is disabled (optional) */
- disabled?: boolean;
-}
-
/**
* Render a labelled input for y.
- * @param {YInputProps} props - The component props.
+ * @param {StartInputProps} props - The component props.
* @returns {JSX.Element} The rendered component.
*/
-function YInput(props: YInputProps) {
+function YInput(props: StartInputProps) {
const { selection, updateSelection, disabled } = props;
return (
key="y"
label="y"
- input={selection.vStart.y}
+ input={selection.start[1]}
decimalPlaces={8}
updateValue={(y: number) => {
- selection.start[1] = y;
- selection.vStart.y = y;
+ selection.setStart(1, y);
if (updateSelection) {
updateSelection(selection);
}
diff --git a/client/component/src/SelectionTypeDropdown.tsx b/client/component/src/SelectionTypeDropdown.tsx
index 1d2e5fb..b66e3d0 100644
--- a/client/component/src/SelectionTypeDropdown.tsx
+++ b/client/component/src/SelectionTypeDropdown.tsx
@@ -106,6 +106,7 @@ function SelectionTypeDropdown(props: SelectionDropdownProps) {
const {
value,
onSelectionTypeChange,
+ disabled,
options = [
SelectionType.line,
SelectionType.rectangle,
@@ -122,7 +123,7 @@ function SelectionTypeDropdown(props: SelectionDropdownProps) {
onChange={onSelectionTypeChange}
options={options}
renderOption={(option) => }
- disabled={props.disabled}
+ disabled={disabled}
/>
);
}
diff --git a/client/component/src/selections/BaseSelection.tsx b/client/component/src/selections/BaseSelection.tsx
index cb9e1b0..aa7c48e 100644
--- a/client/component/src/selections/BaseSelection.tsx
+++ b/client/component/src/selections/BaseSelection.tsx
@@ -11,6 +11,7 @@ import type { SelectionBase } from './utils';
export default class BaseSelection implements SelectionBase {
id: string;
name = '';
+ defaultColour: string = '#000000'; // black
colour?: string;
alpha = 0.3;
fixed = false;
@@ -28,6 +29,19 @@ export default class BaseSelection implements SelectionBase {
return '';
}
+ setStart(i: number, v: number) {
+ this.start[i] = v;
+ if (i == 0) {
+ this.vStart.x = v;
+ } else if (i == 1) {
+ this.vStart.y = v;
+ } else if (i == 2) {
+ this.vStart.z = v;
+ } else {
+ console.log('Index error (%i > 2) on setting start', i);
+ }
+ }
+
getPoints() {
return [this.vStart.clone()];
}
@@ -41,22 +55,18 @@ export default class BaseSelection implements SelectionBase {
this.fixed = other.fixed;
}
- setName(name: string) {
- this.name = name;
- }
-
- setFixed(fixed: boolean) {
- this.fixed = fixed;
- }
-
static createFromSelection(s: BaseSelection) {
const l = new BaseSelection([...s.start]);
l.setProperties(s);
return l;
}
- onHandleChange(i: number, pos: [number | undefined, number | undefined]) {
- console.debug('base: oHC', i, pos);
+ onHandleChange(
+ i: number,
+ pos: [number | undefined, number | undefined],
+ d?: boolean
+ ) {
+ console.debug('base: oHC', i, pos, d);
if (i === 0) {
const b = BaseSelection.createFromSelection(this);
const x = pos[0];
diff --git a/client/component/src/selections/utils.tsx b/client/component/src/selections/utils.tsx
index db1a841..52c9ec8 100644
--- a/client/component/src/selections/utils.tsx
+++ b/client/component/src/selections/utils.tsx
@@ -18,7 +18,6 @@ import { Vector3 } from 'three';
import DvdAxisBox from '../shapes/DvdAxisBox';
import DvdPolyline from '../shapes/DvdPolyline';
import AxialSelection from './AxialSelection';
-import type BaseSelection from './BaseSelection';
import CircularSelection from './CircularSelection';
import CircularSectorialSelection from './CircularSectorialSelection';
import EllipticalSelection from './EllipticalSelection';
@@ -64,6 +63,8 @@ interface SelectionBase {
readonly id: string;
/** name */
name: string;
+ /** default colour */
+ defaultColour: string;
/** outline colour */
colour?: string;
/** opacity [0,1] */
@@ -74,8 +75,10 @@ interface SelectionBase {
start: [number, number];
/** if true, outline is dashed */
asDashed?: boolean;
+ /** set start */
+ setStart: (i: number, v: number) => void;
/** retrieve points */
- getPoints?: () => Vector3[];
+ getPoints: () => Vector3[];
/** callback for drag handle movements */
onHandleChange: HandleChangeFunction;
/** string representation */
@@ -156,7 +159,7 @@ function createSelection(
selectionType: SelectionType,
axesFlipped: [boolean, boolean],
points: Vector3[]
-) {
+): SelectionBase {
switch (selectionType) {
case SelectionType.rectangle:
return RectangularSelection.createFromPoints(axesFlipped, points);
@@ -226,7 +229,7 @@ function pointsToSelection(
points: Vector3[],
alpha: number,
colour?: string
-): BaseSelection {
+): SelectionBase {
console.debug('Points', selectionType, points);
const s = createSelection(selectionType, [false, false], points);
s.alpha = alpha;
@@ -398,14 +401,8 @@ function SelectionShape(props: SelectionShapeProps) {
},
[updateSelection, htmlToDataFunction]
);
- if (
- selectionType !== SelectionType.unknown &&
- selection.getPoints !== undefined
- ) {
+ if (selectionType !== SelectionType.unknown) {
const pts = selection.getPoints();
- const defColour = (
- 'defaultColour' in selection ? selection.defaultColour : '#000000'
- ) as string;
return (
{(...htmlSelection: Vector3[]) =>
@@ -414,7 +411,7 @@ function SelectionShape(props: SelectionShapeProps) {
htmlSelection,
selection.alpha,
size,
- selection.colour ?? defColour,
+ selection.colour ?? selection.defaultColour,
selection.asDashed,
selection.fixed || !showHandles,
combinedUpdate(selection)