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
|
@@ -13,9 +13,10 @@
|
|
|
13
13
|
import { useMemo, useRef, useState } from 'react';
|
|
14
14
|
import { useCapturedPointer } from "../../scatter/ui/useCapturedPointer.js";
|
|
15
15
|
import { PARALLEL_MARGIN } from "../core/parallelAxes.js";
|
|
16
|
-
import { parallelBandAt, parallelBandOf,
|
|
16
|
+
import { parallelBandAt, parallelBandOf, parallelBrushTarget, } from "../core/parallelBrush.js";
|
|
17
17
|
import { parallelNearestRow } from "../core/parallelHit.js";
|
|
18
|
-
import {
|
|
18
|
+
import { parallelRangeList } from "../core/parallelSelection.js";
|
|
19
|
+
import { parallelAxisById, parallelAxisNear, parallelBandsOf, parallelCommitOf, parallelPointOf, } from "./parallelGestureModel.js";
|
|
19
20
|
/**
|
|
20
21
|
* The brush and the hover, over one surface.
|
|
21
22
|
* @param options - See {@link ParallelGestureOptions}.
|
|
@@ -23,6 +24,7 @@ import { parallelAxisById, parallelAxisNear, parallelBandsOf, parallelPointOf, }
|
|
|
23
24
|
*/
|
|
24
25
|
export function useParallelGesture(options) {
|
|
25
26
|
const { layouts, values, count, innerHeight, included, ranges } = options;
|
|
27
|
+
const { several = false } = options;
|
|
26
28
|
const { onRangeChange, onRangePreview, onHoverChange, onRowClick } = options;
|
|
27
29
|
const [draft, setDraft] = useState(null);
|
|
28
30
|
const [ownHovered, setOwnHovered] = useState(-1);
|
|
@@ -32,11 +34,18 @@ export function useParallelGesture(options) {
|
|
|
32
34
|
const pointRef = useRef({ x: 0, y: 0 });
|
|
33
35
|
const reportedRef = useRef(-1);
|
|
34
36
|
const claimedRef = useRef(false);
|
|
35
|
-
function
|
|
36
|
-
const layout = parallelAxisById(layouts,
|
|
37
|
-
if (layout === undefined
|
|
38
|
-
return
|
|
39
|
-
return
|
|
37
|
+
function commit(drag, band) {
|
|
38
|
+
const layout = parallelAxisById(layouts, drag.axis);
|
|
39
|
+
if (layout === undefined)
|
|
40
|
+
return parallelRangeList(ranges[drag.axis]);
|
|
41
|
+
return parallelCommitOf({
|
|
42
|
+
list: parallelRangeList(ranges[drag.axis]),
|
|
43
|
+
index: drag.index,
|
|
44
|
+
band,
|
|
45
|
+
layout,
|
|
46
|
+
still: unmoved(drag, band),
|
|
47
|
+
several,
|
|
48
|
+
});
|
|
40
49
|
}
|
|
41
50
|
function report(index) {
|
|
42
51
|
if (index === reportedRef.current)
|
|
@@ -56,21 +65,25 @@ export function useParallelGesture(options) {
|
|
|
56
65
|
claimedRef.current = false;
|
|
57
66
|
return false;
|
|
58
67
|
}
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
68
|
+
const list = parallelRangeList(ranges[layout.id]);
|
|
69
|
+
const bands = [];
|
|
70
|
+
for (const range of list)
|
|
71
|
+
bands.push(parallelBandOf(range, layout));
|
|
72
|
+
const target = parallelBrushTarget(point.y, bands);
|
|
73
|
+
const held = target.index === -1 ? undefined : bands[target.index];
|
|
63
74
|
const drag = {
|
|
64
75
|
axis: layout.id,
|
|
65
|
-
|
|
76
|
+
index: target.index,
|
|
77
|
+
grip: target.grip,
|
|
66
78
|
originY: point.y,
|
|
67
|
-
origin:
|
|
79
|
+
origin: held ?? { top: point.y, bottom: point.y },
|
|
68
80
|
};
|
|
69
81
|
dragRef.current = drag;
|
|
70
82
|
pointRef.current = point;
|
|
71
83
|
claimedRef.current = true;
|
|
72
84
|
setDraft({
|
|
73
85
|
axis: layout.id,
|
|
86
|
+
index: target.index,
|
|
74
87
|
band: parallelBandAt(drag, point.y, innerHeight),
|
|
75
88
|
});
|
|
76
89
|
return true;
|
|
@@ -80,8 +93,8 @@ export function useParallelGesture(options) {
|
|
|
80
93
|
const drag = dragRef.current;
|
|
81
94
|
if (claimed && drag !== null) {
|
|
82
95
|
const band = parallelBandAt(drag, point.y, innerHeight);
|
|
83
|
-
setDraft({ axis: drag.axis, band });
|
|
84
|
-
onRangePreview?.(drag.axis,
|
|
96
|
+
setDraft({ axis: drag.axis, index: drag.index, band });
|
|
97
|
+
onRangePreview?.(drag.axis, commit(drag, band));
|
|
85
98
|
return;
|
|
86
99
|
}
|
|
87
100
|
setPointer({
|
|
@@ -90,7 +103,7 @@ export function useParallelGesture(options) {
|
|
|
90
103
|
});
|
|
91
104
|
report(findRow(point));
|
|
92
105
|
}
|
|
93
|
-
function release(event,
|
|
106
|
+
function release(event, keep) {
|
|
94
107
|
const drag = dragRef.current;
|
|
95
108
|
dragRef.current = null;
|
|
96
109
|
setDraft(null);
|
|
@@ -98,13 +111,13 @@ export function useParallelGesture(options) {
|
|
|
98
111
|
return;
|
|
99
112
|
if (event !== null)
|
|
100
113
|
pointRef.current = parallelPointOf(event);
|
|
101
|
-
if (!
|
|
102
|
-
onRangePreview?.(drag.axis, ranges[drag.axis]
|
|
114
|
+
if (!keep) {
|
|
115
|
+
onRangePreview?.(drag.axis, parallelRangeList(ranges[drag.axis]));
|
|
103
116
|
return;
|
|
104
117
|
}
|
|
105
|
-
const
|
|
106
|
-
onRangePreview?.(drag.axis,
|
|
107
|
-
onRangeChange(drag.axis,
|
|
118
|
+
const kept = commit(drag, parallelBandAt(drag, pointRef.current.y, innerHeight));
|
|
119
|
+
onRangePreview?.(drag.axis, kept);
|
|
120
|
+
onRangeChange(drag.axis, kept);
|
|
108
121
|
}
|
|
109
122
|
const { surface } = useCapturedPointer({
|
|
110
123
|
touch: false,
|
|
@@ -136,4 +149,16 @@ export function useParallelGesture(options) {
|
|
|
136
149
|
brushing: draft !== null,
|
|
137
150
|
};
|
|
138
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Whether a press took hold of an interval and let it go where it found it,
|
|
154
|
+
* which is a click on that interval rather than a move of it.
|
|
155
|
+
* @param drag - The drag, as it began.
|
|
156
|
+
* @param band - The band as the pointer left it.
|
|
157
|
+
* @returns Whether nothing moved.
|
|
158
|
+
*/
|
|
159
|
+
function unmoved(drag, band) {
|
|
160
|
+
return (drag.index !== -1 &&
|
|
161
|
+
band.top === drag.origin.top &&
|
|
162
|
+
band.bottom === drag.origin.bottom);
|
|
163
|
+
}
|
|
139
164
|
//# sourceMappingURL=useParallelGesture.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useParallelGesture.js","sourceRoot":"","sources":["../../../src/parallel/ui/useParallelGesture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAMlD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAE5E,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D,OAAO,EACL,cAAc,EACd,cAAc,EACd,
|
|
1
|
+
{"version":3,"file":"useParallelGesture.js","sourceRoot":"","sources":["../../../src/parallel/ui/useParallelGesture.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-cheminfo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "React components, hooks and framework-free helpers shared by the cheminfo sites: site chrome, citations, sharing, routing, pedagogy, charts, and the structure, orbital and 3D molecule viewers",
|
|
6
6
|
"author": "Luc Patiny",
|
|
@@ -22,6 +22,7 @@ export type {
|
|
|
22
22
|
ParallelBand,
|
|
23
23
|
ParallelBrushDrag,
|
|
24
24
|
ParallelBrushGrip,
|
|
25
|
+
ParallelBrushTarget,
|
|
25
26
|
} from './parallelBrush.ts';
|
|
26
27
|
export {
|
|
27
28
|
PARALLEL_BRUSH_HALF_WIDTH,
|
|
@@ -30,6 +31,7 @@ export {
|
|
|
30
31
|
parallelBandAt,
|
|
31
32
|
parallelBandOf,
|
|
32
33
|
parallelBrushGrip,
|
|
34
|
+
parallelBrushTarget,
|
|
33
35
|
parallelIsBand,
|
|
34
36
|
parallelRangeOf,
|
|
35
37
|
} from './parallelBrush.ts';
|
|
@@ -42,6 +44,7 @@ export {
|
|
|
42
44
|
parallelIncludedMask,
|
|
43
45
|
parallelKeptCount,
|
|
44
46
|
parallelRangeKeeps,
|
|
47
|
+
parallelSelectionKeeps,
|
|
45
48
|
} from './parallelFilter.ts';
|
|
46
49
|
export type { ParallelPoint, ParallelSegment } from './parallelHit.ts';
|
|
47
50
|
export {
|
|
@@ -49,6 +52,11 @@ export {
|
|
|
49
52
|
parallelNearestRow,
|
|
50
53
|
parallelSegmentAt,
|
|
51
54
|
} from './parallelHit.ts';
|
|
55
|
+
export {
|
|
56
|
+
parallelAxisOrder,
|
|
57
|
+
parallelDropIndex,
|
|
58
|
+
parallelMoveAxis,
|
|
59
|
+
} from './parallelOrder.ts';
|
|
52
60
|
export type {
|
|
53
61
|
ParallelHighlight,
|
|
54
62
|
ParallelHighlightPaint,
|
|
@@ -63,9 +71,16 @@ export {
|
|
|
63
71
|
} from './parallelPaint.ts';
|
|
64
72
|
export {
|
|
65
73
|
PARALLEL_PALETTE_STEPS,
|
|
74
|
+
PARALLEL_PALETTE_UNKNOWN,
|
|
66
75
|
parallelColorSteps,
|
|
67
76
|
parallelPalette,
|
|
68
77
|
} from './parallelPalette.ts';
|
|
78
|
+
export {
|
|
79
|
+
parallelHasRange,
|
|
80
|
+
parallelMergeRanges,
|
|
81
|
+
parallelRangeList,
|
|
82
|
+
parallelWriteRange,
|
|
83
|
+
} from './parallelSelection.ts';
|
|
69
84
|
export type { ParallelGraduation } from './parallelTicks.ts';
|
|
70
85
|
export { PARALLEL_TICK_COUNT, parallelTicks } from './parallelTicks.ts';
|
|
71
86
|
export type {
|
|
@@ -75,6 +90,7 @@ export type {
|
|
|
75
90
|
ParallelColorBy,
|
|
76
91
|
ParallelRange,
|
|
77
92
|
ParallelRanges,
|
|
93
|
+
ParallelSelection,
|
|
78
94
|
ParallelTick,
|
|
79
95
|
} from './parallelTypes.ts';
|
|
80
96
|
export { parallelAxisOf } from './parallelTypes.ts';
|
|
@@ -28,6 +28,8 @@ export type ParallelBrushGrip = 'create' | 'move' | 'top' | 'bottom';
|
|
|
28
28
|
export interface ParallelBrushDrag {
|
|
29
29
|
/** The axis being brushed, by its id. */
|
|
30
30
|
axis: string;
|
|
31
|
+
/** Which of that axis's intervals is being written, or `-1` for a new one. */
|
|
32
|
+
index: number;
|
|
31
33
|
/** What the press took hold of. */
|
|
32
34
|
grip: ParallelBrushGrip;
|
|
33
35
|
/** Where the press landed, in pixels from the top of the drawing area. */
|
|
@@ -45,6 +47,15 @@ export const PARALLEL_BRUSH_SMALLEST = 1;
|
|
|
45
47
|
/** How far either side of an axis a press still reaches it, in pixels. */
|
|
46
48
|
export const PARALLEL_BRUSH_HALF_WIDTH = 9;
|
|
47
49
|
|
|
50
|
+
/**
|
|
51
|
+
* How close to an axis's own end a band edge counts as standing on it.
|
|
52
|
+
*
|
|
53
|
+
* Half a pixel is below anything a pointer can aim at, and the two ends are
|
|
54
|
+
* where the rows a reader most wants sit: the axes end exactly on the data,
|
|
55
|
+
* so the extreme row is drawn on the end itself.
|
|
56
|
+
*/
|
|
57
|
+
const END_REACH = 0.5;
|
|
58
|
+
|
|
48
59
|
/**
|
|
49
60
|
* What a press at that height takes hold of.
|
|
50
61
|
* @param y - Where the press landed, in pixels from the top of the drawing area.
|
|
@@ -64,6 +75,52 @@ export function parallelBrushGrip(
|
|
|
64
75
|
return 'create';
|
|
65
76
|
}
|
|
66
77
|
|
|
78
|
+
/** Which of an axis's bands a press took hold of, and by what. */
|
|
79
|
+
export interface ParallelBrushTarget {
|
|
80
|
+
/** The band, as an index into the list, or `-1` when none was under it. */
|
|
81
|
+
index: number;
|
|
82
|
+
/** What the press took hold of. */
|
|
83
|
+
grip: ParallelBrushGrip;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Nothing under the press, so it starts a band of its own. */
|
|
87
|
+
const NEW_BAND: ParallelBrushTarget = { index: -1, grip: 'create' };
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Which band a press at that height took hold of, on an axis carrying several.
|
|
91
|
+
* @param y - Where the press landed, in pixels from the top of the drawing area.
|
|
92
|
+
* @param bands - The bands on that axis, in any order.
|
|
93
|
+
* @returns The band and the grip. An edge wins over the band it belongs to and
|
|
94
|
+
* over any band it lies inside, so two bands dragged flush against each other
|
|
95
|
+
* can still be pulled apart; a press on bare axis starts a new band.
|
|
96
|
+
*/
|
|
97
|
+
export function parallelBrushTarget(
|
|
98
|
+
y: number,
|
|
99
|
+
bands: readonly ParallelBand[],
|
|
100
|
+
): ParallelBrushTarget {
|
|
101
|
+
let nearest = NEW_BAND;
|
|
102
|
+
let nearestDistance = PARALLEL_BRUSH_HANDLE_REACH;
|
|
103
|
+
for (let index = 0; index < bands.length; index++) {
|
|
104
|
+
const band = bands[index] as ParallelBand;
|
|
105
|
+
const toTop = Math.abs(y - band.top);
|
|
106
|
+
if (toTop <= nearestDistance) {
|
|
107
|
+
nearestDistance = toTop;
|
|
108
|
+
nearest = { index, grip: 'top' };
|
|
109
|
+
}
|
|
110
|
+
const toBottom = Math.abs(y - band.bottom);
|
|
111
|
+
if (toBottom <= nearestDistance) {
|
|
112
|
+
nearestDistance = toBottom;
|
|
113
|
+
nearest = { index, grip: 'bottom' };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (nearest !== NEW_BAND) return nearest;
|
|
117
|
+
for (let index = 0; index < bands.length; index++) {
|
|
118
|
+
const band = bands[index] as ParallelBand;
|
|
119
|
+
if (y > band.top && y < band.bottom) return { index, grip: 'move' };
|
|
120
|
+
}
|
|
121
|
+
return NEW_BAND;
|
|
122
|
+
}
|
|
123
|
+
|
|
67
124
|
/**
|
|
68
125
|
* The band a drag stands at, now that the pointer is there.
|
|
69
126
|
* @param drag - The drag, as it began.
|
|
@@ -123,14 +180,23 @@ export function parallelBandOf(
|
|
|
123
180
|
* @param band - The band, in pixels from the top of the drawing area.
|
|
124
181
|
* @param axis - The axis it belongs to.
|
|
125
182
|
* @returns The interval, low value first — which is the order every filter in
|
|
126
|
-
* the family reads, and getting it backwards keeps nothing at all.
|
|
183
|
+
* the family reads, and getting it backwards keeps nothing at all. An edge
|
|
184
|
+
* standing on an end of the axis reports that end verbatim: inverting the
|
|
185
|
+
* placement is not exact, and one ulp is enough to drop the row the axis ends
|
|
186
|
+
* on from its own full-range brush.
|
|
127
187
|
*/
|
|
128
188
|
export function parallelRangeOf(
|
|
129
189
|
band: ParallelBand,
|
|
130
190
|
axis: ParallelAxisLayout,
|
|
131
191
|
): ParallelRange {
|
|
132
|
-
const low =
|
|
133
|
-
|
|
192
|
+
const low =
|
|
193
|
+
band.bottom >= parallelValueToY(axis.min, axis) - END_REACH
|
|
194
|
+
? axis.min
|
|
195
|
+
: parallelYToValue(band.bottom, axis);
|
|
196
|
+
const high =
|
|
197
|
+
band.top <= parallelValueToY(axis.max, axis) + END_REACH
|
|
198
|
+
? axis.max
|
|
199
|
+
: parallelYToValue(band.top, axis);
|
|
134
200
|
return low <= high ? [low, high] : [high, low];
|
|
135
201
|
}
|
|
136
202
|
|
|
@@ -5,22 +5,28 @@
|
|
|
5
5
|
* figure has to filter on the same answer. Two definitions of "kept" is the
|
|
6
6
|
* fault this file exists to prevent: a table showing fourteen rows under a
|
|
7
7
|
* plot drawing one is not a rounding error, it is two different programs.
|
|
8
|
+
*
|
|
9
|
+
* An axis carrying several intervals keeps a row that falls in any of them,
|
|
10
|
+
* while a row has to be kept by every brushed axis — union down an axis,
|
|
11
|
+
* intersection across them, which is the only reading under which brushing a
|
|
12
|
+
* second axis can never widen what the first one left.
|
|
8
13
|
*/
|
|
9
14
|
|
|
15
|
+
import { parallelRangeList } from './parallelSelection.ts';
|
|
10
16
|
import type {
|
|
11
17
|
ParallelAxis,
|
|
12
18
|
ParallelRange,
|
|
13
19
|
ParallelRanges,
|
|
14
20
|
} from './parallelTypes.ts';
|
|
15
21
|
|
|
16
|
-
/** One axis's
|
|
22
|
+
/** One axis's intervals, ready to be tested row by row. */
|
|
17
23
|
interface ActiveRange {
|
|
18
24
|
/** The column being tested. */
|
|
19
25
|
values: ArrayLike<number>;
|
|
20
|
-
/** The lowest value
|
|
21
|
-
minimum:
|
|
22
|
-
/** The highest value
|
|
23
|
-
maximum:
|
|
26
|
+
/** The lowest value each interval keeps. */
|
|
27
|
+
minimum: Float64Array;
|
|
28
|
+
/** The highest value each interval keeps. */
|
|
29
|
+
maximum: Float64Array;
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
/**
|
|
@@ -38,10 +44,28 @@ export function parallelRangeKeeps(
|
|
|
38
44
|
return value >= range[0] && value <= range[1];
|
|
39
45
|
}
|
|
40
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Whether one value falls inside any of an axis's intervals.
|
|
49
|
+
* @param ranges - The intervals that axis keeps.
|
|
50
|
+
* @param value - The value to test.
|
|
51
|
+
* @returns Whether any of them keeps it. An axis keeping nothing keeps every
|
|
52
|
+
* value, which is what an unbrushed axis means.
|
|
53
|
+
*/
|
|
54
|
+
export function parallelSelectionKeeps(
|
|
55
|
+
ranges: readonly ParallelRange[],
|
|
56
|
+
value: number,
|
|
57
|
+
): boolean {
|
|
58
|
+
if (ranges.length === 0) return true;
|
|
59
|
+
for (const range of ranges) {
|
|
60
|
+
if (value >= range[0] && value <= range[1]) return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
41
65
|
/**
|
|
42
66
|
* Which rows every brush keeps at once.
|
|
43
67
|
* @param axes - The axes, whose ids the intervals are keyed by.
|
|
44
|
-
* @param ranges -
|
|
68
|
+
* @param ranges - What each axis keeps: one interval, several, or none.
|
|
45
69
|
* @param count - How many rows there are.
|
|
46
70
|
* @returns One byte per row, `1` for kept. An interval keyed on an axis that
|
|
47
71
|
* is not drawn is ignored rather than emptying the figure, so a range left
|
|
@@ -56,23 +80,36 @@ export function parallelIncludedMask(
|
|
|
56
80
|
const included = new Uint8Array(count).fill(1);
|
|
57
81
|
const active: ActiveRange[] = [];
|
|
58
82
|
for (const axis of axes) {
|
|
59
|
-
const
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
83
|
+
const list = parallelRangeList(ranges[axis.id]);
|
|
84
|
+
if (list.length === 0) continue;
|
|
85
|
+
const minimum = new Float64Array(list.length);
|
|
86
|
+
const maximum = new Float64Array(list.length);
|
|
87
|
+
for (let index = 0; index < list.length; index++) {
|
|
88
|
+
const range = list[index] as ParallelRange;
|
|
89
|
+
minimum[index] = Math.min(range[0], range[1]);
|
|
90
|
+
maximum[index] = Math.max(range[0], range[1]);
|
|
91
|
+
}
|
|
92
|
+
active.push({ values: axis.values, minimum, maximum });
|
|
66
93
|
}
|
|
67
94
|
if (active.length === 0) return included;
|
|
68
95
|
|
|
69
96
|
for (const range of active) {
|
|
70
97
|
const rows = Math.min(count, range.values.length);
|
|
98
|
+
const intervals = range.minimum.length;
|
|
71
99
|
for (let row = 0; row < rows; row++) {
|
|
72
100
|
if (included[row] === 0) continue;
|
|
73
101
|
const value = range.values[row] as number;
|
|
74
|
-
|
|
75
|
-
|
|
102
|
+
let kept = false;
|
|
103
|
+
for (let index = 0; index < intervals; index++) {
|
|
104
|
+
if (
|
|
105
|
+
value >= (range.minimum[index] as number) &&
|
|
106
|
+
value <= (range.maximum[index] as number)
|
|
107
|
+
) {
|
|
108
|
+
kept = true;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (!kept) included[row] = 0;
|
|
76
113
|
}
|
|
77
114
|
// A row the figure has no value for on a brushed axis is not in range.
|
|
78
115
|
for (let row = rows; row < count; row++) included[row] = 0;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which order the axes stand in, when the reader is the one deciding.
|
|
3
|
+
*
|
|
4
|
+
* A parallel-coordinates figure only shows a relationship between two columns
|
|
5
|
+
* that stand next to each other, so the order is not decoration: moving an
|
|
6
|
+
* axis is how a reader asks a different question of the same data. The
|
|
7
|
+
* arithmetic of the move is here, away from the pointer that starts it, so
|
|
8
|
+
* that dragging a name and pressing an arrow key are the same operation.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { ParallelAxisLayout } from './parallelAxes.ts';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The same ids with one of them moved.
|
|
15
|
+
* @param ids - The axes, from left to right.
|
|
16
|
+
* @param from - Which one is moving.
|
|
17
|
+
* @param to - The place it lands in, counted in the list it left.
|
|
18
|
+
* @returns The new order. The list comes back unchanged when either place is
|
|
19
|
+
* outside it or when nothing moves, so a caller can report without comparing.
|
|
20
|
+
*/
|
|
21
|
+
export function parallelMoveAxis(
|
|
22
|
+
ids: readonly string[],
|
|
23
|
+
from: number,
|
|
24
|
+
to: number,
|
|
25
|
+
): string[] {
|
|
26
|
+
const order = [...ids];
|
|
27
|
+
if (from < 0 || from >= order.length) return order;
|
|
28
|
+
if (to < 0 || to >= order.length || to === from) return order;
|
|
29
|
+
const [moved] = order.splice(from, 1);
|
|
30
|
+
if (moved === undefined) return [...ids];
|
|
31
|
+
order.splice(to, 0, moved);
|
|
32
|
+
return order;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Where an axis dragged to that position would land.
|
|
37
|
+
* @param x - Where the pointer is, in pixels from the left of the drawing area.
|
|
38
|
+
* @param layouts - The axes, from left to right.
|
|
39
|
+
* @returns The index of the axis whose place it would take, or `-1` when there
|
|
40
|
+
* is nowhere to land. Nearest axis rather than nearest gap: a reader dragging
|
|
41
|
+
* a name over its neighbour means the two to swap, and the neighbour's own
|
|
42
|
+
* name is the thing they are aiming at.
|
|
43
|
+
*/
|
|
44
|
+
export function parallelDropIndex(
|
|
45
|
+
x: number,
|
|
46
|
+
layouts: readonly ParallelAxisLayout[],
|
|
47
|
+
): number {
|
|
48
|
+
let nearest = -1;
|
|
49
|
+
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
50
|
+
for (let index = 0; index < layouts.length; index++) {
|
|
51
|
+
const layout = layouts[index];
|
|
52
|
+
if (layout === undefined) continue;
|
|
53
|
+
const distance = Math.abs(x - layout.x);
|
|
54
|
+
if (distance < nearestDistance) {
|
|
55
|
+
nearestDistance = distance;
|
|
56
|
+
nearest = index;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return nearest;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The ids of the axes, from left to right.
|
|
64
|
+
* @param layouts - The axes, already placed.
|
|
65
|
+
* @returns Their ids, which is what an order is reported as.
|
|
66
|
+
*/
|
|
67
|
+
export function parallelAxisOrder(
|
|
68
|
+
layouts: readonly ParallelAxisLayout[],
|
|
69
|
+
): string[] {
|
|
70
|
+
const ids: string[] = [];
|
|
71
|
+
for (const layout of layouts) ids.push(layout.id);
|
|
72
|
+
return ids;
|
|
73
|
+
}
|
|
@@ -149,8 +149,10 @@ export function paintParallelLines(
|
|
|
149
149
|
if (steps !== null) {
|
|
150
150
|
const step = steps[row] as number;
|
|
151
151
|
if (step !== previousStep) {
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
// A step past the end of the ramp is a quantity nobody knows for this
|
|
153
|
+
// row; it is drawn in the neutral ink rather than in the ramp's first
|
|
154
|
+
// colour, which means the smallest value in the set.
|
|
155
|
+
context.strokeStyle = palette[step] ?? line;
|
|
154
156
|
previousStep = step;
|
|
155
157
|
}
|
|
156
158
|
}
|
|
@@ -201,6 +203,10 @@ export function paintParallelHighlights(
|
|
|
201
203
|
|
|
202
204
|
/**
|
|
203
205
|
* Add one row's line to the path being built.
|
|
206
|
+
*
|
|
207
|
+
* The line is one polyline per unbroken run of known values, so a row with a
|
|
208
|
+
* gap in the middle is drawn as two, and nothing is painted over an axis the
|
|
209
|
+
* row has no value on.
|
|
204
210
|
* @param context - A context already scaled and moved to the drawing area.
|
|
205
211
|
* @param row - The row to trace.
|
|
206
212
|
* @param layouts - The axes, from left to right.
|
|
@@ -218,9 +224,14 @@ export function traceParallelRow(
|
|
|
218
224
|
const column = values[index];
|
|
219
225
|
if (layout === undefined || column === undefined) continue;
|
|
220
226
|
const y = parallelPixelAt(layout.pixels, column[row] as number);
|
|
221
|
-
// A row whose value on this axis is not known yet has no point to draw
|
|
222
|
-
// the line
|
|
223
|
-
|
|
227
|
+
// A row whose value on this axis is not known yet has no point to draw,
|
|
228
|
+
// and the line breaks rather than bridging the axis: a segment drawn
|
|
229
|
+
// across it reads as a value the row does not hold, and the hit test,
|
|
230
|
+
// which has no endpoint there, cannot pick it back.
|
|
231
|
+
if (!Number.isFinite(y)) {
|
|
232
|
+
started = false;
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
224
235
|
if (started) {
|
|
225
236
|
context.lineTo(layout.x, y);
|
|
226
237
|
} else {
|
|
@@ -20,6 +20,15 @@ import type { ParallelColorBy } from './parallelTypes.ts';
|
|
|
20
20
|
/** How many steps the ramp is quantised into; there is one more colour than steps. */
|
|
21
21
|
export const PARALLEL_PALETTE_STEPS = 120;
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* The step a row whose colouring quantity is unknown takes.
|
|
25
|
+
*
|
|
26
|
+
* Past the end of the ramp on purpose: no colour indexes it, so the painter
|
|
27
|
+
* leaves such a row in the neutral ink rather than claiming for it the ink of
|
|
28
|
+
* the smallest value in the set.
|
|
29
|
+
*/
|
|
30
|
+
export const PARALLEL_PALETTE_UNKNOWN = PARALLEL_PALETTE_STEPS + 1;
|
|
31
|
+
|
|
23
32
|
/**
|
|
24
33
|
* The ramp, sampled into the steps a line's colour is looked up by.
|
|
25
34
|
* @param scale - The ramp, as the registry hands it over or as a plain list of colours. Defaults to viridis.
|
|
@@ -39,13 +48,16 @@ export function parallelPalette(
|
|
|
39
48
|
* loop reads an integer instead of placing a value on a ramp.
|
|
40
49
|
* @param color - The quantity the lines are coloured by.
|
|
41
50
|
* @param count - How many rows there are.
|
|
42
|
-
* @returns One step per row, from `0` to {@link PARALLEL_PALETTE_STEPS}
|
|
51
|
+
* @returns One step per row, from `0` to {@link PARALLEL_PALETTE_STEPS}, or
|
|
52
|
+
* {@link PARALLEL_PALETTE_UNKNOWN} for a row whose value is not a number.
|
|
43
53
|
*/
|
|
44
54
|
export function parallelColorSteps(
|
|
45
55
|
color: ParallelColorBy,
|
|
46
56
|
count: number,
|
|
47
57
|
): Uint8Array {
|
|
48
58
|
const steps = new Uint8Array(count);
|
|
59
|
+
// A row the column does not reach is as unknown as one holding no number.
|
|
60
|
+
steps.fill(PARALLEL_PALETTE_UNKNOWN);
|
|
49
61
|
const extent = parallelExtent(color.values, count);
|
|
50
62
|
const min = color.min ?? extent.min;
|
|
51
63
|
const max = color.max ?? extent.max;
|
|
@@ -54,6 +66,7 @@ export function parallelColorSteps(
|
|
|
54
66
|
const rows = Math.min(count, color.values.length);
|
|
55
67
|
for (let row = 0; row < rows; row++) {
|
|
56
68
|
const value = color.values[row] as number;
|
|
69
|
+
if (!Number.isFinite(value)) continue;
|
|
57
70
|
steps[row] = logarithmic
|
|
58
71
|
? Math.round(
|
|
59
72
|
positionInRange(value, min, max, { logarithmic: true }) *
|