vuegraphx
v1.1.0
Published
The math and graphics engine core for VueGraphX
Readme
English | 简体中文
🌟 简介
VueGraphX 提供两条互补的能力主线:
- 表达式渲染:把 2D/3D 数学表达式、几何指令交给统一渲染管线执行。
- 图形运行时:把具体图形实现收敛为 shape definition,再通过统一 capability API 暴露交互能力。
当前 playground 还提供一个实验性的双层模式(dual-layer):
- 把 2D 对象理解为落在
z = 0工作平面上的内容。 - 把立体对象放在同一坐标系里,但仅允许对象局部旋转,不旋转全局坐标轴。
- 用固定正视角的
view3d承载 3D 场景,再叠加独立的 2D 顶层/底层覆盖,用来模拟更接近数学软件的“平面 + 立体同轴展示”。
它适合两类场景:
- 直接作为数学表达式渲染引擎使用。
- 作为业务侧几何编辑器、教学工具或交互式画板的底层运行时使用。
🌐 在线演示: https://zyizyiz.github.io/VueGraphX/
✨ 核心特性
- 🚀 能力优先交互:外部通过
subscribeCapabilities()订阅状态,通过executeCapability()触发行为,不必记忆每种图形的专用 API。 - 🧩 组合式图形定义:使用
createComposedShapeDefinition()、GraphShapeApi和GraphShapeContext在业务侧组合自己的图形。 - 🎬 共享动画与标注能力:动画轨道、点标注、命中分组、拖拽与悬浮 UI 投影工具都是通用基础设施。
- 📐 统一 2D / 3D 渲染入口:表达式渲染和 view3d 生命周期都通过同一个引擎门面管理。
- 🧪 playground 双层模式:以
3d引擎模式为底座,叠加独立的 2D 层,并通过对象级旋转查看立体结构。 - 🧱 分层场景基础设施:内置
view3D.fitToBoard和分组级bindNativeEvent(),方便消费侧组合双层/多层交互。 - 🛡️ 类型安全:公共类型、能力契约和 shape authoring API 都完整导出,适合二次封装和 IDE 自动提示。
📦 安装
npm install vuegraphx你还需要在项目中安装 vue。如果需要沿用 JSXGraph 默认样式,可额外引入其 CSS。
🔨 快速上手
1. 初始化引擎
import { GraphXEngine, createComposedShapeDefinition } from 'vuegraphx';
import 'jsxgraph/distrib/jsxgraph.css';
const engine = new GraphXEngine('box', {
boundingbox: [-5, 5, 5, -5],
axis: true,
showNavigation: false,
});
const customCircle = createComposedShapeDefinition<{ x: number; y: number }>({
type: 'circle',
supportedModes: ['2d', 'geometry'],
create(_context, payload) {
if (!payload) return null;
return {
entityType: 'circle',
initialState: {},
setup(api) {
const center = api.trackObject(api.board.create('point', [payload.x, payload.y], { visible: false }));
const radiusPoint = api.trackObject(api.board.create('point', [payload.x + 2, payload.y], { visible: false }));
const circle = api.trackObject(api.board.create('circle', [center, radiusPoint]));
circle.on('down', () => Promise.resolve().then(() => api.select()));
},
getCapabilityTarget(api) {
if (!api.selected) return null;
return {
entityType: 'circle',
entityId: api.id,
entity: { id: api.id },
remove: () => api.remove()
};
}
};
}
});
engine.registerShape(customCircle);
engine.createShape('circle', { x: 0, y: 0 });2. 订阅能力并驱动交互
import type { GraphCapabilitySnapshot } from 'vuegraphx';
const unsubscribe = engine.subscribeCapabilities((snapshot: GraphCapabilitySnapshot) => {
console.log('当前选中图形:', snapshot.selection);
console.log('当前可用能力:', snapshot.capabilities);
});
engine.executeCapability('style.stroke', { color: '#ef4444' });
engine.executeCapability('resize.value', { value: 3.5 });
engine.executeCapability('animation.play');
unsubscribe();3. 执行表达式渲染
engine.executeCommand('function-demo', 'y = sin(x) + 0.5*cos(2*x)', '#ff0000');
engine.executeCommand('geometry-demo', 'c1 = Circle((0,0), (2,0))', '#0000ff');4. 切换到 3D 模式
engine.setMode('3d');
const view3d = engine.getView3D();
console.log('当前 3D 视图是否可用:', !!view3d);
engine.executeCommand('surface-demo', 'z = sin(x) * cos(y)', '#42b883');
engine.executeCommand('line-demo', 'Line((0,0,0), (1,1,1))', '#e74c3c');5. 在业务侧实现分层 / 双层场景
如果你的应用要把多个交互层叠在一起,例如:
- 顶层 2D 标注 / 命中层 + 底层 3D 场景
- 底层 2D 坐标网格 + 顶层 3D 立体对象
- 需要让“空白区域穿透、图元本体命中”的教学白板或几何编辑器
当前版本建议优先使用两类公共能力,而不是直接依赖 playground 内部实现:
5.1 view3D.fitToBoard
当容器宽高比变化、board 自身 bounding box 发生调整时,view3d 默认的固定矩形容易出现“3D 图元移动到边缘后被裁剪”的问题。可以启用:
const engine = new GraphXEngine('box', {
axis: false,
showNavigation: false,
view3D: {
fitToBoard: true,
rect: [[-8, -8], [16, 16], [[-5, 5], [-5, 5], [-5, 5]]],
attributes: {
projection: 'parallel'
}
}
});
engine.setMode('3d');启用后,运行时会:
- 在初始化时把
view3d同步到当前 board 的真实可视区域。 - 在
resize()后继续同步。 - 在 board 的
boundingbox变化后继续同步。
这很适合响应式布局、分栏编辑器、嵌入式白板和任意比例的容器。
5.2 createGroup() + bindNativeEvent()
在多层透传场景中,底层图元有时不能完全依赖 JSXGraph 自己的命中代理。这时可以直接对受管分组的渲染节点绑定原生 DOM 事件:
const group = api.createGroup({ face, edge }, { createNativeGroup: false });
const dispose = group.bindNativeEvent('pointerdown', (member, event, node) => {
event.preventDefault();
console.log('hit member:', member.key, node.tagName);
}, {
stopPropagation: true,
passive: false
});这类 API 适合:
- 双层 / 多层透传布局
- 需要直接控制
pointerdown/touchstart的图元 - JSXGraph 默认命中代理不够稳定的组合场景
同时你仍然可以继续使用:
group.onHit()处理常规命中group.bindDrag()处理常规拖拽group.getRenderNode(key)获取成员对应的真实渲染节点
6. 关于 playground 的双层模式
双层模式当前是 playground 层的组合能力,不是新的公共 EngineMode。它的目标是演示一种更接近数学软件的交互方式:
- 全局只有一套坐标系,平面对象按
z = 0语义理解。 - 立体对象和 2D 对象共处同一坐标系,但立体对象允许局部旋转以观察结构。
- 顶层 2D 与底层 3D 可以同时存在,并通过 CSS / 原生命中事件实现“空白穿透、图元接管”。
当前实现位于:
playground/App.vue:双层模式入口、双实例挂载与层级透传样式。playground/types/mode.ts:把 playground 的dual-layer映射到底层 3D 引擎配置,并启用view3D.fitToBoard。playground/shapes/index.ts:区分顶层 2D 图形与底层 3D 图形注册。playground/components/DualLayerPanel.vue:双层模式专用控制面板。
🧠 推荐使用方式
当前版本建议按下面的心智模型接入:
- 用
registerShape()注册业务自己的图形定义。 - 用
createShape()或拖拽入口创建实例。 - 用
subscribeCapabilities()驱动工具栏、属性面板和动画控制 UI。 - 用
executeCapability()执行删除、样式、缩放、动画、拆分等通用行为。 - 用
executeCommand()处理表达式渲染类需求。
能力描述统一包含:
feature:能力语义,例如resize、style、delete。kind:交互方式,例如action、toggle、input、panel。group:能力分组,例如edit、style、animation。active/enabled/meta:当前状态、可用性和附加参数。
这意味着 UI 层可以围绕“能力”而不是“图形种类”来写。
📚 文档入口
更新 API 文档:
npm run docs:api🏗️ 当前目录分层
库代码集中在 src/ 下:
architecture/capabilities/: 通用能力契约、能力处理器和能力注册表。architecture/shapes/: shape definition、shape runtime、组合式 authoring API。board/: JSXGraph board / view3d 生命周期管理。engine/: 对外门面GraphXEngine。entities/: 表达式渲染结果的注册、替换与清理。math/: 共享数学作用域。parsing/: 文本与表达式解析。rendering/: 表达式渲染器、指令目录和处理器。types/: 对外基础类型与引擎配置。
playground 中与双层模式直接相关的文件:
playground/App.vue: playground 模式切换、双层容器挂载与事件透传样式。playground/types/mode.ts: playground 模式到引擎模式的映射与view3D配置。playground/components/DualLayerPanel.vue: 双层模式的添加图形与交互说明。playground/shapes/wireframeCube.ts: 使用createGroup()与bindNativeEvent()的 3D 图形交互示例。
🧪 测试与校验
npm run build
npm run test
npm run check:jsxgraph-3d📝 贡献说明
欢迎提交 PR 与 Issue。当前版本有两类主要扩展方式:
- 扩展表达式渲染:在
src/rendering/handlers/中新增或调整处理器,并补覆盖测试。 - 扩展图形运行时:优先通过
createComposedShapeDefinition()、能力契约和通用 shape API 完成,而不是把具体图形硬编码进库内。
更详细的贡献约束见 DEVELOPMENT.md。
📄 许可证
本项目采用 Apache License 2.0 许可证。
