构建交互式绘图应用
这个流程展示如何组合 asset + canvas + input,而不把场景树或应用对象放进宿主。
1. 声明能力和资源
{
"apiVersion": "0.1",
"assets": { "fonts/ui": "assets/ui.woff2" },
"capabilities": [
"host:asset.loadFont",
"host:canvas.getInfo",
"host:canvas.draw",
"host:canvas.measureText",
"host:input.focus"
]
}
2. 初始化布局
const font = await host.asset.loadFont('fonts/ui');
const info = await host.canvas.getInfo('main');
if (!info) throw new Error('main canvas missing');
const [label] = await host.canvas.measureText('main', ['新建'], font);
const model = createSceneModel(info, label.width); // guest 内存中的 L2/L3 状态
3. 处理输入
await host.input.focus('main');
host.events.on('input.pointer', (event) => {
if (event.canvasId !== 'main') return;
model.handlePointer(event);
model.dirty = true;
});
命中测试在 guest 中使用自己的场景模型完成。宿主只提供输入事实与真实绘图面。
4. 每帧批量绘制
host.events.on('canvas.frame', async ({ canvasId }) => {
if (canvasId !== 'main' || !model.dirty) return;
model.dirty = false;
await host.canvas.draw('main', model.toDrawOperations(font));
});
把一帧的指令放在一个批次中,避免每个图形都跨 guest/host 边界。
5. 处理尺寸变化
host.events.on('canvas.resize', ({ width, height }) => {
model.resize(width, height);
model.dirty = true;
});
软件像素路径
模拟器或体素渲染器可以把第 4 步换成 canvas.present()。像素缓冲与场景状态仍属于 guest;这条路径不要升级成宿主场景引擎。
相关参考
canvas.draw()、canvas.present()、input.pointer、asset.loadFont()