@fusion.dev/helix-plot 0.198.0 → 0.199.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.
@@ -0,0 +1,105 @@
1
+ import { Box3, BoxGeometry, BufferGeometry, Color, DirectionalLight, EdgesGeometry, Float32BufferAttribute, HemisphereLight, LineBasicMaterial, LineSegments, Mesh, MeshLambertMaterial, Vector3, } from 'three';
2
+ import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js';
3
+ import { createStage, edgeOf, HALF, inBox, lookThrough } from './stage.js';
4
+ export const threeTreemapDriver = (container, options = {}) => {
5
+ let field;
6
+ let drawnBlocks = [];
7
+ let tops = new Map();
8
+ const blockMaterial = new MeshLambertMaterial({
9
+ polygonOffset: true,
10
+ polygonOffsetFactor: 1,
11
+ polygonOffsetUnits: 1,
12
+ vertexColors: true,
13
+ });
14
+ const blocks = new Mesh(new BufferGeometry(), blockMaterial);
15
+ const edgeMaterial = new LineBasicMaterial({ vertexColors: true });
16
+ const edges = new LineSegments(new BufferGeometry(), edgeMaterial);
17
+ const stage = createStage(container, {
18
+ density: options.density,
19
+ pick: (ray) => {
20
+ const hit = ray.intersectObject(blocks)[0];
21
+ if (hit?.faceIndex === undefined || hit.faceIndex === null) {
22
+ return -1;
23
+ }
24
+ return drawnBlocks[Math.floor(hit.faceIndex / 12)] ?? -1;
25
+ },
26
+ });
27
+ const sky = new HemisphereLight(0xffffff, 0xffffff, 2.2);
28
+ const sun = new DirectionalLight(0xffffff, 1);
29
+ sun.position.set(-2, 4, 1);
30
+ stage.scene.add(blocks, edges, sky, sun);
31
+ const painted = (geometry, color) => {
32
+ const count = geometry.getAttribute('position').count;
33
+ const colors = new Float32Array(count * 3);
34
+ for (let at = 0; at < count; at++) {
35
+ colors.set([color.r, color.g, color.b], at * 3);
36
+ }
37
+ geometry.setAttribute('color', new Float32BufferAttribute(colors, 3));
38
+ return geometry;
39
+ };
40
+ return {
41
+ draw: (next, colors, font) => {
42
+ field = next;
43
+ const [ex, ey, ez] = next.axes.extent ?? [1, 1, 1];
44
+ const zero = inBox(next.axes.y, 0) * ey;
45
+ const page = new Color(colors.page);
46
+ const { emphasis, through } = colors.look;
47
+ const solids = [];
48
+ const lines = [];
49
+ drawnBlocks = [];
50
+ tops = new Map();
51
+ next.blocks.forEach((block, index) => {
52
+ const tone = new Color(colors.groups[block.groupIndex % colors.groups.length] ?? colors.ink);
53
+ const color = emphasis === 'outlined' ? tone.clone().lerp(page, 0.4) : tone;
54
+ const top = inBox(next.axes.y, next.height === '' ? 1 : (block.height ?? 0)) * ey;
55
+ const tall = Math.max(Math.abs(top - zero), 1e-3);
56
+ const [x0, x1] = [
57
+ inBox(next.axes.x, block.area.x0) * ex,
58
+ inBox(next.axes.x, block.area.x1) * ex,
59
+ ];
60
+ const [z0, z1] = [
61
+ inBox(next.axes.z, block.area.z0) * ez,
62
+ inBox(next.axes.z, block.area.z1) * ez,
63
+ ];
64
+ const box = new BoxGeometry(Math.abs(x1 - x0), tall, Math.abs(z1 - z0));
65
+ const [x, z] = [(x0 + x1) / 2, (z0 + z1) / 2];
66
+ box.translate(x, Math.min(top, zero) + tall / 2, z);
67
+ solids.push(painted(box, color));
68
+ lines.push(painted(new EdgesGeometry(box), emphasis === 'solid' ? edgeOf(color) : tone));
69
+ drawnBlocks.push(index);
70
+ tops.set(index, new Vector3(x, Math.max(top, zero), z));
71
+ });
72
+ lookThrough(blockMaterial, (emphasis === 'subtle' ? 0.2 : 1) * through);
73
+ lookThrough(edgeMaterial, through);
74
+ blocks.geometry.dispose();
75
+ edges.geometry.dispose();
76
+ blocks.geometry = (solids.length > 0 && mergeGeometries(solids)) || new BufferGeometry();
77
+ edges.geometry = (lines.length > 0 && mergeGeometries(lines)) || new BufferGeometry();
78
+ for (const one of [...solids, ...lines]) {
79
+ one.dispose();
80
+ }
81
+ stage.setAxes(next.axes, colors, font);
82
+ if (colors.look.box || tops.size === 0) {
83
+ stage.frame(new Vector3(-HALF * ex, -HALF * ey, -HALF * ez), new Vector3(HALF * ex, HALF * ey, HALF * ez));
84
+ }
85
+ else {
86
+ const around = new Box3().setFromBufferAttribute(blocks.geometry.getAttribute('position'));
87
+ stage.frame(around.min, around.max);
88
+ }
89
+ },
90
+ focus: (index) => {
91
+ stage.setMarker(field ? tops.get(index) : undefined);
92
+ },
93
+ onHover: (listener) => stage.onHover(listener),
94
+ onPlace: (listener) => stage.onPlace(listener),
95
+ onPress: (listener) => stage.onPress(listener),
96
+ stop: () => {
97
+ blocks.geometry.dispose();
98
+ blockMaterial.dispose();
99
+ edges.geometry.dispose();
100
+ edgeMaterial.dispose();
101
+ stage.stop();
102
+ },
103
+ turnBy: (across, up, animate) => stage.turnBy(across, up, animate),
104
+ };
105
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fusion.dev/helix-plot",
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.198.0",
3
+ "description": "Connects the Helix spatial charts to three.js, which draws them in three dimensions: Spatial Bar Chart, Spatial Heatmap, Spatial Ribbon Chart, Spatial Scatter Chart, Spatial Surface Chart, and Spatial Treemap.",
4
+ "version": "0.199.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.198.0"
38
+ "@fusion.dev/helix-core": "0.199.0"
39
39
  },
40
40
  "devDependencies": {
41
- "@fusion.dev/helix-headless": "0.198.0",
42
- "@fusion.dev/helix-testing": "0.198.0",
41
+ "@fusion.dev/helix-headless": "0.199.0",
42
+ "@fusion.dev/helix-testing": "0.199.0",
43
43
  "@types/bun": "^1.4.2",
44
44
  "@types/three": "^0.186.0",
45
45
  "three": "^0.186.1"