react-cheminfo 0.16.0 → 0.17.0
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/parallel/core/index.d.ts +7 -5
- package/lib/parallel/core/index.d.ts.map +1 -1
- package/lib/parallel/core/index.js +5 -3
- package/lib/parallel/core/index.js.map +1 -1
- package/lib/parallel/core/parallelBrush.d.ts +22 -1
- package/lib/parallel/core/parallelBrush.d.ts.map +1 -1
- package/lib/parallel/core/parallelBrush.js +53 -3
- package/lib/parallel/core/parallelBrush.js.map +1 -1
- package/lib/parallel/core/parallelFilter.d.ts +14 -1
- package/lib/parallel/core/parallelFilter.d.ts.map +1 -1
- package/lib/parallel/core/parallelFilter.js +44 -11
- package/lib/parallel/core/parallelFilter.js.map +1 -1
- package/lib/parallel/core/parallelOrder.d.ts +36 -0
- package/lib/parallel/core/parallelOrder.d.ts.map +1 -0
- package/lib/parallel/core/parallelOrder.js +65 -0
- package/lib/parallel/core/parallelOrder.js.map +1 -0
- package/lib/parallel/core/parallelPaint.d.ts +4 -0
- package/lib/parallel/core/parallelPaint.d.ts.map +1 -1
- package/lib/parallel/core/parallelPaint.js +15 -6
- package/lib/parallel/core/parallelPaint.js.map +1 -1
- package/lib/parallel/core/parallelPalette.d.ts +10 -1
- package/lib/parallel/core/parallelPalette.d.ts.map +1 -1
- package/lib/parallel/core/parallelPalette.js +14 -1
- package/lib/parallel/core/parallelPalette.js.map +1 -1
- package/lib/parallel/core/parallelSelection.d.ts +43 -0
- package/lib/parallel/core/parallelSelection.d.ts.map +1 -0
- package/lib/parallel/core/parallelSelection.js +87 -0
- package/lib/parallel/core/parallelSelection.js.map +1 -0
- package/lib/parallel/core/parallelTicks.d.ts.map +1 -1
- package/lib/parallel/core/parallelTicks.js +7 -4
- package/lib/parallel/core/parallelTicks.js.map +1 -1
- package/lib/parallel/core/parallelTypes.d.ts +12 -1
- package/lib/parallel/core/parallelTypes.d.ts.map +1 -1
- package/lib/parallel/core/parallelTypes.js.map +1 -1
- package/lib/parallel/ui/ParallelAxesLayer.d.ts +2 -2
- package/lib/parallel/ui/ParallelAxesLayer.d.ts.map +1 -1
- package/lib/parallel/ui/ParallelAxesLayer.js +2 -2
- package/lib/parallel/ui/ParallelAxesLayer.js.map +1 -1
- package/lib/parallel/ui/ParallelCoordinates.d.ts.map +1 -1
- package/lib/parallel/ui/ParallelCoordinates.js +10 -5
- package/lib/parallel/ui/ParallelCoordinates.js.map +1 -1
- package/lib/parallel/ui/ParallelLabels.d.ts +6 -0
- package/lib/parallel/ui/ParallelLabels.d.ts.map +1 -1
- package/lib/parallel/ui/ParallelLabels.js +14 -2
- package/lib/parallel/ui/ParallelLabels.js.map +1 -1
- package/lib/parallel/ui/index.d.ts +4 -0
- package/lib/parallel/ui/index.d.ts.map +1 -1
- package/lib/parallel/ui/index.js +2 -0
- package/lib/parallel/ui/index.js.map +1 -1
- package/lib/parallel/ui/parallelCoordinatesProps.d.ts +26 -8
- package/lib/parallel/ui/parallelCoordinatesProps.d.ts.map +1 -1
- package/lib/parallel/ui/parallelGestureModel.d.ts +37 -6
- package/lib/parallel/ui/parallelGestureModel.d.ts.map +1 -1
- package/lib/parallel/ui/parallelGestureModel.js +42 -12
- package/lib/parallel/ui/parallelGestureModel.js.map +1 -1
- package/lib/parallel/ui/parallelPlotModel.d.ts +1 -1
- package/lib/parallel/ui/parallelPlotModel.d.ts.map +1 -1
- package/lib/parallel/ui/parallelPlotModel.js +3 -3
- package/lib/parallel/ui/parallelPlotModel.js.map +1 -1
- package/lib/parallel/ui/parallelStyles.d.ts +26 -3
- package/lib/parallel/ui/parallelStyles.d.ts.map +1 -1
- package/lib/parallel/ui/parallelStyles.js +26 -4
- package/lib/parallel/ui/parallelStyles.js.map +1 -1
- package/lib/parallel/ui/useParallelAxisDrag.d.ts +60 -0
- package/lib/parallel/ui/useParallelAxisDrag.d.ts.map +1 -0
- package/lib/parallel/ui/useParallelAxisDrag.js +96 -0
- package/lib/parallel/ui/useParallelAxisDrag.js.map +1 -0
- package/lib/parallel/ui/useParallelGesture.d.ts +10 -5
- package/lib/parallel/ui/useParallelGesture.d.ts.map +1 -1
- package/lib/parallel/ui/useParallelGesture.js +46 -21
- package/lib/parallel/ui/useParallelGesture.js.map +1 -1
- package/package.json +1 -1
- package/src/parallel/core/index.ts +16 -0
- package/src/parallel/core/parallelBrush.ts +69 -3
- package/src/parallel/core/parallelFilter.ts +52 -15
- package/src/parallel/core/parallelOrder.ts +73 -0
- package/src/parallel/core/parallelPaint.ts +16 -5
- package/src/parallel/core/parallelPalette.ts +14 -1
- package/src/parallel/core/parallelSelection.ts +99 -0
- package/src/parallel/core/parallelTicks.ts +7 -3
- package/src/parallel/core/parallelTypes.ts +13 -1
- package/src/parallel/ui/ParallelAxesLayer.tsx +10 -4
- package/src/parallel/ui/ParallelCoordinates.tsx +22 -3
- package/src/parallel/ui/ParallelLabels.tsx +23 -2
- package/src/parallel/ui/index.ts +15 -0
- package/src/parallel/ui/parallelCoordinatesProps.ts +26 -8
- package/src/parallel/ui/parallelGestureModel.ts +63 -13
- package/src/parallel/ui/parallelPlotModel.ts +3 -3
- package/src/parallel/ui/parallelStyles.ts +46 -4
- package/src/parallel/ui/useParallelAxisDrag.ts +147 -0
- package/src/parallel/ui/useParallelGesture.ts +61 -28
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dragging an axis by its name to stand somewhere else.
|
|
3
|
+
*
|
|
4
|
+
* Two columns only show their relationship when they are neighbours, so the
|
|
5
|
+
* order the axes stand in is a question the reader asks, not a decision the
|
|
6
|
+
* caller takes once. The name is the handle: it is the only part of an axis
|
|
7
|
+
* that is not already spoken for by the brush, and it is what a reader reaches
|
|
8
|
+
* for anyway.
|
|
9
|
+
*
|
|
10
|
+
* The gesture moves the name and nothing else. Reordering the axes for real
|
|
11
|
+
* would repaint every line on every frame, which a library of ten thousand
|
|
12
|
+
* molecules cannot afford — so the figure shows where the axis would land and
|
|
13
|
+
* moves it once, on release.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { KeyboardEvent, PointerEvent } from 'react';
|
|
17
|
+
import { useRef, useState } from 'react';
|
|
18
|
+
|
|
19
|
+
import type { ParallelAxisLayout } from '../core/parallelAxes.ts';
|
|
20
|
+
import {
|
|
21
|
+
parallelAxisOrder,
|
|
22
|
+
parallelDropIndex,
|
|
23
|
+
parallelMoveAxis,
|
|
24
|
+
} from '../core/parallelOrder.ts';
|
|
25
|
+
|
|
26
|
+
/** What {@link useParallelAxisDrag} needs. */
|
|
27
|
+
export interface ParallelAxisDragOptions {
|
|
28
|
+
/** The axes, from left to right, already placed. */
|
|
29
|
+
layouts: readonly ParallelAxisLayout[];
|
|
30
|
+
/**
|
|
31
|
+
* Called with the axis ids in the order the reader put them in.
|
|
32
|
+
* @default undefined — the axes cannot be moved
|
|
33
|
+
*/
|
|
34
|
+
onAxisOrder?: ((ids: readonly string[]) => void) | undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** The name being dragged, and where it would land. */
|
|
38
|
+
export interface ParallelAxisDragState {
|
|
39
|
+
/** Which axis is moving, as an index into the axes. */
|
|
40
|
+
from: number;
|
|
41
|
+
/** How far its name has been dragged, in pixels. */
|
|
42
|
+
dx: number;
|
|
43
|
+
/** Which place it would take if let go now. */
|
|
44
|
+
to: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** The reorder gesture, as the figure renders it. */
|
|
48
|
+
export interface ParallelAxisDrag {
|
|
49
|
+
/** Whether the axes can be moved at all. */
|
|
50
|
+
enabled: boolean;
|
|
51
|
+
/** The name being dragged, or `null` when none is. */
|
|
52
|
+
active: ParallelAxisDragState | null;
|
|
53
|
+
/** Spread onto one axis's name. */
|
|
54
|
+
propsFor: (index: number) => ParallelAxisHandleProps;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** What one axis name carries so it can be dragged and stepped with the keys. */
|
|
58
|
+
export interface ParallelAxisHandleProps {
|
|
59
|
+
onPointerDown: (event: PointerEvent<HTMLElement>) => void;
|
|
60
|
+
onPointerMove: (event: PointerEvent<HTMLElement>) => void;
|
|
61
|
+
onPointerUp: (event: PointerEvent<HTMLElement>) => void;
|
|
62
|
+
onPointerCancel: (event: PointerEvent<HTMLElement>) => void;
|
|
63
|
+
onKeyDown: (event: KeyboardEvent<HTMLElement>) => void;
|
|
64
|
+
tabIndex: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** A name that has not been dragged, and is not moving anything. */
|
|
68
|
+
const IDLE: ParallelAxisHandleProps = {
|
|
69
|
+
onPointerDown: noop,
|
|
70
|
+
onPointerMove: noop,
|
|
71
|
+
onPointerUp: noop,
|
|
72
|
+
onPointerCancel: noop,
|
|
73
|
+
onKeyDown: noop,
|
|
74
|
+
tabIndex: -1,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Move an axis by dragging its name, or by stepping it with the arrow keys.
|
|
79
|
+
* @param options - See {@link ParallelAxisDragOptions}.
|
|
80
|
+
* @returns The gesture. See {@link ParallelAxisDrag}.
|
|
81
|
+
*/
|
|
82
|
+
export function useParallelAxisDrag(
|
|
83
|
+
options: ParallelAxisDragOptions,
|
|
84
|
+
): ParallelAxisDrag {
|
|
85
|
+
const { layouts, onAxisOrder } = options;
|
|
86
|
+
const [active, setActive] = useState<ParallelAxisDragState | null>(null);
|
|
87
|
+
const originRef = useRef(0);
|
|
88
|
+
|
|
89
|
+
function move(from: number, to: number): void {
|
|
90
|
+
if (onAxisOrder === undefined) return;
|
|
91
|
+
const order = parallelAxisOrder(layouts);
|
|
92
|
+
if (to < 0 || to >= order.length || to === from) return;
|
|
93
|
+
onAxisOrder(parallelMoveAxis(order, from, to));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function dropAt(from: number, dx: number): number {
|
|
97
|
+
const layout = layouts[from];
|
|
98
|
+
if (layout === undefined) return from;
|
|
99
|
+
return parallelDropIndex(layout.x + dx, layouts);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function propsFor(index: number): ParallelAxisHandleProps {
|
|
103
|
+
if (onAxisOrder === undefined) return IDLE;
|
|
104
|
+
return {
|
|
105
|
+
tabIndex: 0,
|
|
106
|
+
onPointerDown: (event) => {
|
|
107
|
+
if (event.button !== 0) return;
|
|
108
|
+
event.preventDefault();
|
|
109
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
110
|
+
originRef.current = event.clientX;
|
|
111
|
+
setActive({ from: index, dx: 0, to: index });
|
|
112
|
+
},
|
|
113
|
+
onPointerMove: (event) => {
|
|
114
|
+
setActive((current) => {
|
|
115
|
+
if (current?.from !== index) return current;
|
|
116
|
+
const dx = event.clientX - originRef.current;
|
|
117
|
+
return { from: index, dx, to: dropAt(index, dx) };
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
onPointerUp: (event) => {
|
|
121
|
+
event.currentTarget.releasePointerCapture?.(event.pointerId);
|
|
122
|
+
setActive((current) => {
|
|
123
|
+
if (current !== null && current.from === index) {
|
|
124
|
+
move(current.from, current.to);
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
onPointerCancel: () => {
|
|
130
|
+
setActive(null);
|
|
131
|
+
},
|
|
132
|
+
onKeyDown: (event) => {
|
|
133
|
+
const step =
|
|
134
|
+
event.key === 'ArrowLeft' ? -1 : event.key === 'ArrowRight' ? 1 : 0;
|
|
135
|
+
if (step === 0) return;
|
|
136
|
+
event.preventDefault();
|
|
137
|
+
move(index, index + step);
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return { enabled: onAxisOrder !== undefined, active, propsFor };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function noop(): void {
|
|
146
|
+
// A figure whose axes are fixed hands its names no handlers at all.
|
|
147
|
+
}
|
|
@@ -25,11 +25,10 @@ import type { ParallelBand, ParallelBrushDrag } from '../core/parallelBrush.ts';
|
|
|
25
25
|
import {
|
|
26
26
|
parallelBandAt,
|
|
27
27
|
parallelBandOf,
|
|
28
|
-
|
|
29
|
-
parallelIsBand,
|
|
30
|
-
parallelRangeOf,
|
|
28
|
+
parallelBrushTarget,
|
|
31
29
|
} from '../core/parallelBrush.ts';
|
|
32
30
|
import { parallelNearestRow } from '../core/parallelHit.ts';
|
|
31
|
+
import { parallelRangeList } from '../core/parallelSelection.ts';
|
|
33
32
|
import type { ParallelRange, ParallelRanges } from '../core/parallelTypes.ts';
|
|
34
33
|
|
|
35
34
|
import type { ParallelDraft } from './parallelGestureModel.ts';
|
|
@@ -37,6 +36,7 @@ import {
|
|
|
37
36
|
parallelAxisById,
|
|
38
37
|
parallelAxisNear,
|
|
39
38
|
parallelBandsOf,
|
|
39
|
+
parallelCommitOf,
|
|
40
40
|
parallelPointOf,
|
|
41
41
|
} from './parallelGestureModel.ts';
|
|
42
42
|
|
|
@@ -54,11 +54,16 @@ export interface ParallelGestureOptions {
|
|
|
54
54
|
included: Uint8Array | null;
|
|
55
55
|
/** The intervals in force, whoever owns them. */
|
|
56
56
|
ranges: ParallelRanges;
|
|
57
|
-
/**
|
|
58
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Whether one axis may keep several intervals at once.
|
|
59
|
+
* @default false
|
|
60
|
+
*/
|
|
61
|
+
several?: boolean | undefined;
|
|
62
|
+
/** Called when a brush is released, with every interval that axis now keeps. */
|
|
63
|
+
onRangeChange: (axisId: string, ranges: readonly ParallelRange[]) => void;
|
|
59
64
|
/** Called on every frame a band grows. */
|
|
60
65
|
onRangePreview?:
|
|
61
|
-
((axisId: string,
|
|
66
|
+
((axisId: string, ranges: readonly ParallelRange[]) => void) | undefined;
|
|
62
67
|
/** The row the caller says is hovered, if it owns that. */
|
|
63
68
|
hovered?: number | undefined;
|
|
64
69
|
/** Called with the row under the pointer, or `-1`. */
|
|
@@ -73,8 +78,8 @@ export interface ParallelGesture {
|
|
|
73
78
|
surface: ScatterSurfaceProps;
|
|
74
79
|
/** Put on the same rectangle, for the click that picks a line. */
|
|
75
80
|
onClick: (event: ReactMouseEvent<Element>) => void;
|
|
76
|
-
/** The
|
|
77
|
-
bands: ReadonlyMap<string, ParallelBand>;
|
|
81
|
+
/** The bands to draw on each axis, the one being dragged included. */
|
|
82
|
+
bands: ReadonlyMap<string, ParallelBand[]>;
|
|
78
83
|
/** The row under the pointer, or `-1`. */
|
|
79
84
|
hovered: number;
|
|
80
85
|
/** Where the pointer is in the figure, or `null` when it is away. */
|
|
@@ -92,6 +97,7 @@ export function useParallelGesture(
|
|
|
92
97
|
options: ParallelGestureOptions,
|
|
93
98
|
): ParallelGesture {
|
|
94
99
|
const { layouts, values, count, innerHeight, included, ranges } = options;
|
|
100
|
+
const { several = false } = options;
|
|
95
101
|
const { onRangeChange, onRangePreview, onHoverChange, onRowClick } = options;
|
|
96
102
|
|
|
97
103
|
const [draft, setDraft] = useState<ParallelDraft | null>(null);
|
|
@@ -104,10 +110,20 @@ export function useParallelGesture(
|
|
|
104
110
|
const reportedRef = useRef(-1);
|
|
105
111
|
const claimedRef = useRef(false);
|
|
106
112
|
|
|
107
|
-
function
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
function commit(
|
|
114
|
+
drag: ParallelBrushDrag,
|
|
115
|
+
band: ParallelBand,
|
|
116
|
+
): readonly ParallelRange[] {
|
|
117
|
+
const layout = parallelAxisById(layouts, drag.axis);
|
|
118
|
+
if (layout === undefined) return parallelRangeList(ranges[drag.axis]);
|
|
119
|
+
return parallelCommitOf({
|
|
120
|
+
list: parallelRangeList(ranges[drag.axis]),
|
|
121
|
+
index: drag.index,
|
|
122
|
+
band,
|
|
123
|
+
layout,
|
|
124
|
+
still: unmoved(drag, band),
|
|
125
|
+
several,
|
|
126
|
+
});
|
|
111
127
|
}
|
|
112
128
|
|
|
113
129
|
function report(index: number): void {
|
|
@@ -135,22 +151,24 @@ export function useParallelGesture(
|
|
|
135
151
|
claimedRef.current = false;
|
|
136
152
|
return false;
|
|
137
153
|
}
|
|
138
|
-
const
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
154
|
+
const list = parallelRangeList(ranges[layout.id]);
|
|
155
|
+
const bands: ParallelBand[] = [];
|
|
156
|
+
for (const range of list) bands.push(parallelBandOf(range, layout));
|
|
157
|
+
const target = parallelBrushTarget(point.y, bands);
|
|
158
|
+
const held = target.index === -1 ? undefined : bands[target.index];
|
|
143
159
|
const drag: ParallelBrushDrag = {
|
|
144
160
|
axis: layout.id,
|
|
145
|
-
|
|
161
|
+
index: target.index,
|
|
162
|
+
grip: target.grip,
|
|
146
163
|
originY: point.y,
|
|
147
|
-
origin:
|
|
164
|
+
origin: held ?? { top: point.y, bottom: point.y },
|
|
148
165
|
};
|
|
149
166
|
dragRef.current = drag;
|
|
150
167
|
pointRef.current = point;
|
|
151
168
|
claimedRef.current = true;
|
|
152
169
|
setDraft({
|
|
153
170
|
axis: layout.id,
|
|
171
|
+
index: target.index,
|
|
154
172
|
band: parallelBandAt(drag, point.y, innerHeight),
|
|
155
173
|
});
|
|
156
174
|
return true;
|
|
@@ -161,8 +179,8 @@ export function useParallelGesture(
|
|
|
161
179
|
const drag = dragRef.current;
|
|
162
180
|
if (claimed && drag !== null) {
|
|
163
181
|
const band = parallelBandAt(drag, point.y, innerHeight);
|
|
164
|
-
setDraft({ axis: drag.axis, band });
|
|
165
|
-
onRangePreview?.(drag.axis,
|
|
182
|
+
setDraft({ axis: drag.axis, index: drag.index, band });
|
|
183
|
+
onRangePreview?.(drag.axis, commit(drag, band));
|
|
166
184
|
return;
|
|
167
185
|
}
|
|
168
186
|
setPointer({
|
|
@@ -172,22 +190,22 @@ export function useParallelGesture(
|
|
|
172
190
|
report(findRow(point));
|
|
173
191
|
}
|
|
174
192
|
|
|
175
|
-
function release(event: SurfaceEvent | null,
|
|
193
|
+
function release(event: SurfaceEvent | null, keep: boolean): void {
|
|
176
194
|
const drag = dragRef.current;
|
|
177
195
|
dragRef.current = null;
|
|
178
196
|
setDraft(null);
|
|
179
197
|
if (drag === null) return;
|
|
180
198
|
if (event !== null) pointRef.current = parallelPointOf(event);
|
|
181
|
-
if (!
|
|
182
|
-
onRangePreview?.(drag.axis, ranges[drag.axis]
|
|
199
|
+
if (!keep) {
|
|
200
|
+
onRangePreview?.(drag.axis, parallelRangeList(ranges[drag.axis]));
|
|
183
201
|
return;
|
|
184
202
|
}
|
|
185
|
-
const
|
|
186
|
-
drag
|
|
203
|
+
const kept = commit(
|
|
204
|
+
drag,
|
|
187
205
|
parallelBandAt(drag, pointRef.current.y, innerHeight),
|
|
188
206
|
);
|
|
189
|
-
onRangePreview?.(drag.axis,
|
|
190
|
-
onRangeChange(drag.axis,
|
|
207
|
+
onRangePreview?.(drag.axis, kept);
|
|
208
|
+
onRangeChange(drag.axis, kept);
|
|
191
209
|
}
|
|
192
210
|
|
|
193
211
|
const { surface } = useCapturedPointer({
|
|
@@ -225,3 +243,18 @@ export function useParallelGesture(
|
|
|
225
243
|
brushing: draft !== null,
|
|
226
244
|
};
|
|
227
245
|
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Whether a press took hold of an interval and let it go where it found it,
|
|
249
|
+
* which is a click on that interval rather than a move of it.
|
|
250
|
+
* @param drag - The drag, as it began.
|
|
251
|
+
* @param band - The band as the pointer left it.
|
|
252
|
+
* @returns Whether nothing moved.
|
|
253
|
+
*/
|
|
254
|
+
function unmoved(drag: ParallelBrushDrag, band: ParallelBand): boolean {
|
|
255
|
+
return (
|
|
256
|
+
drag.index !== -1 &&
|
|
257
|
+
band.top === drag.origin.top &&
|
|
258
|
+
band.bottom === drag.origin.bottom
|
|
259
|
+
);
|
|
260
|
+
}
|