@fusion.dev/helix-plot 0.194.0 → 0.196.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/dist/connect-plot/connect-plot.d.ts +15 -7
- package/dist/index.d.ts +1 -1
- package/dist/three/heatmap-driver.js +18 -2
- package/dist/three/stage.js +20 -21
- package/package.json +4 -4
|
@@ -43,6 +43,16 @@ export interface Place {
|
|
|
43
43
|
x: number;
|
|
44
44
|
y: number;
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Where a spatial heatmap's named corners are drawn: the two ends of its
|
|
48
|
+
* front edge, the long edge at the foot of the slab nearer the reader, and
|
|
49
|
+
* the corners of the box round the relief, which the labels stand clear of.
|
|
50
|
+
*/
|
|
51
|
+
export interface Corners {
|
|
52
|
+
end: Place;
|
|
53
|
+
outline?: Place[];
|
|
54
|
+
start: Place;
|
|
55
|
+
}
|
|
46
56
|
/**
|
|
47
57
|
* What a renderer has to answer for a 3D chart to drive it, and nothing that
|
|
48
58
|
* is the same for every renderer: that is the connector's.
|
|
@@ -66,14 +76,12 @@ export interface PlotDriver<F> {
|
|
|
66
76
|
onPlace?(place: (at: Place | undefined) => void): () => void;
|
|
67
77
|
/**
|
|
68
78
|
* Calls `corners` with where the drawing's named corners are drawn, the
|
|
69
|
-
* two ends of a spatial heatmap's front edge
|
|
70
|
-
* and with `undefined` while they
|
|
71
|
-
* first and last labels there
|
|
79
|
+
* two ends of a spatial heatmap's front edge and the corners of the box
|
|
80
|
+
* round it, whenever a frame moves them, and with `undefined` while they
|
|
81
|
+
* are out of view. The chart stands its first and last labels there, clear
|
|
82
|
+
* of the box. Returns what stops listening.
|
|
72
83
|
*/
|
|
73
|
-
onCorners?(corners: (at:
|
|
74
|
-
end: Place;
|
|
75
|
-
start: Place;
|
|
76
|
-
} | undefined) => void): () => void;
|
|
84
|
+
onCorners?(corners: (at: Corners | undefined) => void): () => void;
|
|
77
85
|
/**
|
|
78
86
|
* Calls `press` with a reading's index when the reader presses it in the
|
|
79
87
|
* drawing, and with `-1` when they press where none is. Returns what stops
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { type Axes, type Axis, type Place, type PlotColors, type PlotConnection, type PlotDriver, type PointerKind, plotColorsFrom, } from './connect-plot/connect-plot.js';
|
|
1
|
+
export { type Axes, type Axis, type Corners, type Place, type PlotColors, type PlotConnection, type PlotDriver, type PointerKind, plotColorsFrom, } from './connect-plot/connect-plot.js';
|
|
2
2
|
export { connectSpatialHeatmap, type HeatmapCell, type SpatialHeatmapConnection, type SpatialHeatmapDriver, type SpatialHeatmapField, } from './connect-spatial-heatmap/connect-spatial-heatmap.js';
|
|
3
3
|
export { connectSpatialScatterChart, type Field, type Point, type SpatialScatterChartConnection, type SpatialScatterChartDriver, } from './connect-spatial-scatter-chart/connect-spatial-scatter-chart.js';
|
|
4
4
|
export { connectSpatialSurfaceChart, type SpatialSurfaceChartConnection, type SpatialSurfaceChartDriver, type SurfaceCell, type SurfaceField, } from './connect-spatial-surface-chart/connect-spatial-surface-chart.js';
|
|
@@ -89,8 +89,24 @@ export const threeHeatmapDriver = (container, options = {}) => {
|
|
|
89
89
|
framed = true;
|
|
90
90
|
unfollow?.();
|
|
91
91
|
const foot = FLOOR - THICKNESS * unit;
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
const corners = [];
|
|
93
|
+
for (const x of [-wide / 2, wide / 2]) {
|
|
94
|
+
for (const z of [deep / 2, -deep / 2]) {
|
|
95
|
+
corners.push(new Vector3(x, foot, z), new Vector3(x, foot + high, z));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
unfollow = stage.track(corners, (at) => {
|
|
99
|
+
if (!at) {
|
|
100
|
+
cornered?.(undefined);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const [lastStart, firstStart, lastEnd, firstEnd] = [0, 2, 4, 6].map((index) => at[index]);
|
|
104
|
+
const last = lastStart.y + lastEnd.y >= firstStart.y + firstEnd.y;
|
|
105
|
+
cornered?.({
|
|
106
|
+
end: last ? lastEnd : firstEnd,
|
|
107
|
+
outline: at,
|
|
108
|
+
start: last ? lastStart : firstStart,
|
|
109
|
+
});
|
|
94
110
|
});
|
|
95
111
|
},
|
|
96
112
|
focus: (index) => {
|
package/dist/three/stage.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { pageBudget } from '@fusion.dev/helix-core';
|
|
1
|
+
import { boxLabels, pageBudget, } from '@fusion.dev/helix-core';
|
|
2
2
|
import { BufferGeometry, CanvasTexture, Float32BufferAttribute, LineBasicMaterial, LineSegments, PerspectiveCamera, Raycaster, Scene, Spherical, Sprite, SpriteMaterial, Vector2, Vector3, WebGLRenderer, } from 'three';
|
|
3
3
|
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
|
4
4
|
const STEP = Math.PI / 12;
|
|
@@ -63,7 +63,8 @@ export const createStage = (container, options) => {
|
|
|
63
63
|
container.append(canvas);
|
|
64
64
|
const labels = document.createElement('div');
|
|
65
65
|
labels.setAttribute('aria-hidden', 'true');
|
|
66
|
-
labels.style.cssText =
|
|
66
|
+
labels.style.cssText =
|
|
67
|
+
'position:absolute;inset:0;pointer-events:none;overflow:hidden;user-select:none;-webkit-user-select:none';
|
|
67
68
|
container.append(labels);
|
|
68
69
|
const scene = new Scene();
|
|
69
70
|
const camera = new PerspectiveCamera(35, 1, 0.1, 100);
|
|
@@ -79,6 +80,8 @@ export const createStage = (container, options) => {
|
|
|
79
80
|
controls.minDistance = 2.5;
|
|
80
81
|
controls.maxDistance = 12;
|
|
81
82
|
controls.rotateSpeed = 0.7;
|
|
83
|
+
controls.minPolarAngle = 0.15;
|
|
84
|
+
controls.maxPolarAngle = Math.PI / 2 - 0.02;
|
|
82
85
|
const gridMaterial = new LineBasicMaterial({ opacity: 0.35, transparent: true });
|
|
83
86
|
const grid = new LineSegments(new BufferGeometry(), gridMaterial);
|
|
84
87
|
scene.add(grid);
|
|
@@ -138,34 +141,30 @@ export const createStage = (container, options) => {
|
|
|
138
141
|
const width = container.clientWidth;
|
|
139
142
|
const height = container.clientHeight;
|
|
140
143
|
const marks = [];
|
|
141
|
-
const label = (
|
|
142
|
-
const on = at.clone().project(camera);
|
|
143
|
-
if (on.z > 1) {
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
144
|
+
const label = (left, top, text, strong = false) => {
|
|
146
145
|
const mark = document.createElement('span');
|
|
147
146
|
mark.textContent = text;
|
|
148
147
|
const size = strong ? 'var(--helix-text-sm, 13px)' : 'var(--helix-text-xs, 11px)';
|
|
149
148
|
const weight = strong
|
|
150
149
|
? 'var(--helix-weight-semibold, 600)'
|
|
151
150
|
: 'var(--helix-weight-medium, 500)';
|
|
152
|
-
mark.style.cssText = `position:absolute;left:${
|
|
151
|
+
mark.style.cssText = `position:absolute;left:${left}px;top:${top}px;translate:-50% -50%;white-space:nowrap;font-family:${font};font-size:${size};font-weight:${weight};line-height:1;color:${strong ? colors?.ink : colors?.quiet};text-shadow:0 0 3px ${colors?.ground},0 0 3px ${colors?.ground}`;
|
|
153
152
|
marks.push(mark);
|
|
154
153
|
};
|
|
155
|
-
const
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
154
|
+
const place = new Vector3();
|
|
155
|
+
const seen = ([x, y, z]) => {
|
|
156
|
+
place.set(x * HALF, y * HALF, z * HALF);
|
|
157
|
+
const depth = -place.distanceTo(camera.position);
|
|
158
|
+
const on = place.project(camera);
|
|
159
|
+
return { depth, x: ((on.x + 1) / 2) * width, y: ((1 - on.y) / 2) * height };
|
|
160
|
+
};
|
|
161
|
+
const text = (axis) => ({
|
|
162
|
+
name: axis.name,
|
|
163
|
+
ticks: axis.ticks.map((tick) => ({ at: inBox(axis, tick) / HALF, text: tickText(tick) })),
|
|
164
|
+
});
|
|
165
|
+
for (const one of boxLabels(seen, { x: text(axes.x), y: text(axes.y), z: text(axes.z) }, { gap: 6, name: 13, tick: 11, wide: 0.58 })) {
|
|
166
|
+
label(one.x, one.y, one.text, one.name);
|
|
165
167
|
}
|
|
166
|
-
label(new Vector3(0, -h, h + 0.35), x.name, true);
|
|
167
|
-
label(new Vector3(h + 0.62, -h, 0), z.name, true);
|
|
168
|
-
label(new Vector3(-h, h + 0.28, h), y.name, true);
|
|
169
168
|
labels.replaceChildren(...marks);
|
|
170
169
|
for (const mark of marks) {
|
|
171
170
|
const half = mark.offsetWidth / 2;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusion.dev/helix-plot",
|
|
3
3
|
"description": "Connects the Helix Spatial Heatmap, Spatial Scatter Chart, and Spatial Surface Chart to three.js, which draws them in three dimensions.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.196.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ross Sheppard <ross.sheppard@fusion.dev>",
|
|
7
7
|
"repository": {
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
},
|
|
36
36
|
"bugs": "https://github.com/project-fusion/fusion/issues",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@fusion.dev/helix-core": "0.
|
|
38
|
+
"@fusion.dev/helix-core": "0.196.0"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@fusion.dev/helix-headless": "0.
|
|
42
|
-
"@fusion.dev/helix-testing": "0.
|
|
41
|
+
"@fusion.dev/helix-headless": "0.196.0",
|
|
42
|
+
"@fusion.dev/helix-testing": "0.196.0",
|
|
43
43
|
"@types/bun": "^1.4.2",
|
|
44
44
|
"@types/three": "^0.186.0",
|
|
45
45
|
"three": "^0.186.1"
|