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.
Files changed (91) hide show
  1. package/lib/parallel/core/index.d.ts +7 -5
  2. package/lib/parallel/core/index.d.ts.map +1 -1
  3. package/lib/parallel/core/index.js +5 -3
  4. package/lib/parallel/core/index.js.map +1 -1
  5. package/lib/parallel/core/parallelBrush.d.ts +22 -1
  6. package/lib/parallel/core/parallelBrush.d.ts.map +1 -1
  7. package/lib/parallel/core/parallelBrush.js +53 -3
  8. package/lib/parallel/core/parallelBrush.js.map +1 -1
  9. package/lib/parallel/core/parallelFilter.d.ts +14 -1
  10. package/lib/parallel/core/parallelFilter.d.ts.map +1 -1
  11. package/lib/parallel/core/parallelFilter.js +44 -11
  12. package/lib/parallel/core/parallelFilter.js.map +1 -1
  13. package/lib/parallel/core/parallelOrder.d.ts +36 -0
  14. package/lib/parallel/core/parallelOrder.d.ts.map +1 -0
  15. package/lib/parallel/core/parallelOrder.js +65 -0
  16. package/lib/parallel/core/parallelOrder.js.map +1 -0
  17. package/lib/parallel/core/parallelPaint.d.ts +4 -0
  18. package/lib/parallel/core/parallelPaint.d.ts.map +1 -1
  19. package/lib/parallel/core/parallelPaint.js +15 -6
  20. package/lib/parallel/core/parallelPaint.js.map +1 -1
  21. package/lib/parallel/core/parallelPalette.d.ts +10 -1
  22. package/lib/parallel/core/parallelPalette.d.ts.map +1 -1
  23. package/lib/parallel/core/parallelPalette.js +14 -1
  24. package/lib/parallel/core/parallelPalette.js.map +1 -1
  25. package/lib/parallel/core/parallelSelection.d.ts +43 -0
  26. package/lib/parallel/core/parallelSelection.d.ts.map +1 -0
  27. package/lib/parallel/core/parallelSelection.js +87 -0
  28. package/lib/parallel/core/parallelSelection.js.map +1 -0
  29. package/lib/parallel/core/parallelTicks.d.ts.map +1 -1
  30. package/lib/parallel/core/parallelTicks.js +7 -4
  31. package/lib/parallel/core/parallelTicks.js.map +1 -1
  32. package/lib/parallel/core/parallelTypes.d.ts +12 -1
  33. package/lib/parallel/core/parallelTypes.d.ts.map +1 -1
  34. package/lib/parallel/core/parallelTypes.js.map +1 -1
  35. package/lib/parallel/ui/ParallelAxesLayer.d.ts +2 -2
  36. package/lib/parallel/ui/ParallelAxesLayer.d.ts.map +1 -1
  37. package/lib/parallel/ui/ParallelAxesLayer.js +2 -2
  38. package/lib/parallel/ui/ParallelAxesLayer.js.map +1 -1
  39. package/lib/parallel/ui/ParallelCoordinates.d.ts.map +1 -1
  40. package/lib/parallel/ui/ParallelCoordinates.js +10 -5
  41. package/lib/parallel/ui/ParallelCoordinates.js.map +1 -1
  42. package/lib/parallel/ui/ParallelLabels.d.ts +6 -0
  43. package/lib/parallel/ui/ParallelLabels.d.ts.map +1 -1
  44. package/lib/parallel/ui/ParallelLabels.js +14 -2
  45. package/lib/parallel/ui/ParallelLabels.js.map +1 -1
  46. package/lib/parallel/ui/index.d.ts +4 -0
  47. package/lib/parallel/ui/index.d.ts.map +1 -1
  48. package/lib/parallel/ui/index.js +2 -0
  49. package/lib/parallel/ui/index.js.map +1 -1
  50. package/lib/parallel/ui/parallelCoordinatesProps.d.ts +26 -8
  51. package/lib/parallel/ui/parallelCoordinatesProps.d.ts.map +1 -1
  52. package/lib/parallel/ui/parallelGestureModel.d.ts +37 -6
  53. package/lib/parallel/ui/parallelGestureModel.d.ts.map +1 -1
  54. package/lib/parallel/ui/parallelGestureModel.js +42 -12
  55. package/lib/parallel/ui/parallelGestureModel.js.map +1 -1
  56. package/lib/parallel/ui/parallelPlotModel.d.ts +1 -1
  57. package/lib/parallel/ui/parallelPlotModel.d.ts.map +1 -1
  58. package/lib/parallel/ui/parallelPlotModel.js +3 -3
  59. package/lib/parallel/ui/parallelPlotModel.js.map +1 -1
  60. package/lib/parallel/ui/parallelStyles.d.ts +26 -3
  61. package/lib/parallel/ui/parallelStyles.d.ts.map +1 -1
  62. package/lib/parallel/ui/parallelStyles.js +26 -4
  63. package/lib/parallel/ui/parallelStyles.js.map +1 -1
  64. package/lib/parallel/ui/useParallelAxisDrag.d.ts +60 -0
  65. package/lib/parallel/ui/useParallelAxisDrag.d.ts.map +1 -0
  66. package/lib/parallel/ui/useParallelAxisDrag.js +96 -0
  67. package/lib/parallel/ui/useParallelAxisDrag.js.map +1 -0
  68. package/lib/parallel/ui/useParallelGesture.d.ts +10 -5
  69. package/lib/parallel/ui/useParallelGesture.d.ts.map +1 -1
  70. package/lib/parallel/ui/useParallelGesture.js +46 -21
  71. package/lib/parallel/ui/useParallelGesture.js.map +1 -1
  72. package/package.json +1 -1
  73. package/src/parallel/core/index.ts +16 -0
  74. package/src/parallel/core/parallelBrush.ts +69 -3
  75. package/src/parallel/core/parallelFilter.ts +52 -15
  76. package/src/parallel/core/parallelOrder.ts +73 -0
  77. package/src/parallel/core/parallelPaint.ts +16 -5
  78. package/src/parallel/core/parallelPalette.ts +14 -1
  79. package/src/parallel/core/parallelSelection.ts +99 -0
  80. package/src/parallel/core/parallelTicks.ts +7 -3
  81. package/src/parallel/core/parallelTypes.ts +13 -1
  82. package/src/parallel/ui/ParallelAxesLayer.tsx +10 -4
  83. package/src/parallel/ui/ParallelCoordinates.tsx +22 -3
  84. package/src/parallel/ui/ParallelLabels.tsx +23 -2
  85. package/src/parallel/ui/index.ts +15 -0
  86. package/src/parallel/ui/parallelCoordinatesProps.ts +26 -8
  87. package/src/parallel/ui/parallelGestureModel.ts +63 -13
  88. package/src/parallel/ui/parallelPlotModel.ts +3 -3
  89. package/src/parallel/ui/parallelStyles.ts +46 -4
  90. package/src/parallel/ui/useParallelAxisDrag.ts +147 -0
  91. 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, parallelBrushGrip, parallelIsBand, parallelRangeOf, } from "../core/parallelBrush.js";
16
+ import { parallelBandAt, parallelBandOf, parallelBrushTarget, } from "../core/parallelBrush.js";
17
17
  import { parallelNearestRow } from "../core/parallelHit.js";
18
- import { parallelAxisById, parallelAxisNear, parallelBandsOf, parallelPointOf, } from "./parallelGestureModel.js";
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 rangeOf(axisId, band) {
36
- const layout = parallelAxisById(layouts, axisId);
37
- if (layout === undefined || !parallelIsBand(band))
38
- return null;
39
- return parallelRangeOf(band, layout);
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 current = ranges[layout.id];
60
- const band = current === null || current === undefined
61
- ? null
62
- : parallelBandOf(current, layout);
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
- grip: parallelBrushGrip(point.y, band),
76
+ index: target.index,
77
+ grip: target.grip,
66
78
  originY: point.y,
67
- origin: band ?? { top: point.y, bottom: point.y },
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, rangeOf(drag.axis, band));
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, commit) {
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 (!commit) {
102
- onRangePreview?.(drag.axis, ranges[drag.axis] ?? null);
114
+ if (!keep) {
115
+ onRangePreview?.(drag.axis, parallelRangeList(ranges[drag.axis]));
103
116
  return;
104
117
  }
105
- const range = rangeOf(drag.axis, parallelBandAt(drag, pointRef.current.y, innerHeight));
106
- onRangePreview?.(drag.axis, range);
107
- onRangeChange(drag.axis, range);
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":"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"}
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.16.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 = parallelYToValue(band.bottom, axis);
133
- const high = parallelYToValue(band.top, axis);
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 interval, ready to be tested row by row. */
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 kept. */
21
- minimum: number;
22
- /** The highest value kept. */
23
- maximum: number;
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 - The interval each axis keeps, or `null` for none.
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 range = ranges[axis.id];
60
- if (range === null || range === undefined) continue;
61
- active.push({
62
- values: axis.values,
63
- minimum: Math.min(range[0], range[1]),
64
- maximum: Math.max(range[0], range[1]),
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
- if (value >= range.minimum && value <= range.maximum) continue;
75
- included[row] = 0;
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
- const color = palette[step];
153
- if (color !== undefined) context.strokeStyle = color;
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 skips that axis rather than collapsing onto one of its ends.
223
- if (!Number.isFinite(y)) continue;
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 }) *