# 数据岛 Three.js 接口

在工作区根目录运行 `npm start`，打开 [数据看板](http://127.0.0.1:8877/pastel-dashboard/)。首次安装依赖运行 `npm ci`。统一入口为 [实验首页](http://127.0.0.1:8877/)。

模型文件：`assets/pastel_dashboard.glb`，约 2.7 MB；元数据：`assets/pastel-info.json`。

## 浏览器调用

```js
const dashboard = await window.dashboardReady;

// 后排 24 根方柱，索引 0–23；高度采用模型单位。
dashboard.setBarHeight('skyline', 0, 3.5);

// 前排 5 根圆柱，索引 0–4。
dashboard.setBarHeights('cylinders', [0.5, 0.8, 1.2, 1.6, 2]);

// 大环图固定 6 段，小环图固定 3 段；输入权重或原始数据即可。
dashboard.setDonutValues('main', [30, 20, 15, 15, 10, 10]);
dashboard.setDonutValues('secondary', [50, 30, 20]);

// 原始值、当前高度，以及归一化后的比例（0–1）。
const state = dashboard.getState();
console.log(state.donuts.main.proportions);

window.addEventListener('dashboardchange', event => console.log(event.detail));
dashboard.reset();
```

这些是前端 JavaScript 接口，不是 HTTP 接口。接入后端时，在获取数据后调用这些方法即可：

```js
const data = await fetch('/your-data-endpoint').then(r => r.json());
const dashboard = await window.dashboardReady;
dashboard.setBarHeights('skyline', data.heights); // 恰好 24 个值
dashboard.setDonutValues('main', data.shares);   // 恰好 6 个值
```

## 约束与行为

- 高度支持 `0`（隐藏）或 `0.08–6`。底部固定，修改顶点而非缩放物体，以保留柱顶和柱底的圆角。
- 一组柱子更新前会验证所有高度，错误输入不会造成部分更新。
- 占比使用非负有限数值，总和必须大于零；自动归一化，无须凑到 100。零值分段隐藏，一个非零值形成完整圆环。
- 极小占比会缩小倒角和缝隙，角度低于 `1e-12` 弧度时不绘制，状态仍保留其比例。
- 环图首次加载保留 Blender 的原始网格；更新时重建扇形，沿用导入的材质、圆心、半径和厚度。旧动态网格及时释放。
- `reset()` 恢复 Blender 原始网格与初始值。
- 两组环图的分段数、堆叠方块、横向条形图、波浪图在此版本固定。
- 更新发生在浏览器，不会修改 `.blend` 或磁盘中的 `.glb`。如需保存当前数据，应保存 `getState()` 返回的 JSON。
- WebGL 光照与 Blender 的 Cycles 渲染存在外观差异。

## 在其他 Three.js 项目复用

```js
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { createDashboard } from './dashboard-controller.js';

const gltf = await new GLTFLoader().loadAsync('./assets/pastel_dashboard.glb');
const metadata = await fetch('./assets/pastel-info.json').then(r => r.json());
scene.add(gltf.scene);
const api = createDashboard(gltf.scene, metadata, state => console.log(state));
api.setDonutValues('secondary', [10, 60, 30]);
```

控制器针对本次导出的 GLB：网格已烘焙变换为 Y 轴向上，节点通过 glTF extras 中的组名和索引识别。缩放整个模型时，将它与动态环图一起缩放（动态环图已放在模型根节点下）。

导出脚本为 `export_model.py`，应在包含 `Pastel Analytics Island` 场景的 Blender 中运行。在工作区根目录运行 `npm test` 可检查真实 GLB 的柱子形变、占比边界情况和重复更新。

参考：[Three.js GLTFLoader](https://threejs.org/docs/pages/GLTFLoader.html)、[ExtrudeGeometry](https://threejs.org/docs/pages/ExtrudeGeometry.html)。
