canvas — 实现与 components.md 对照
对照基准:
- 规格:docs/refs/components.md#canvas
- AI 限制:仅 2d;Context 经
this.createSelectorQuery 获取;type=webgl ⏭️;canvas-id 可选(同页唯一)
- 实现:
packages/flexui-frontend/src/components/canvas/canvas.ts
flexui-engine/driver/js/packages/flexui-backend/src/adapters/canvas-adapter.ts
- JS 2d 代理:
.../native-backend/canvas-context.ts(createSelectorQuery → fields({ context }))
- Native:
framework/ohos/.../canvas/FRCanvasView.ets(drawCommands / getSize)
- Demo:
demos/ascf-ai-demo/.../canvas-demo/(属性 + JS 自绘图表)
模板使用 kebab-case(如 disable-scroll),组件 properties 为 camelCase(如 disableScroll);adapter / host attribute 仅 kebab-case,不双写 camelCase 别名。
包名说明:内置组件源码在 @openflexui/frontend(packages/flexui-frontend);原生 adapter 在 flexui-backend。
结论摘要
| 维度 |
结论 |
| 规格纳入(✅) |
type(仅 2d)、canvas-id(可选、同页唯一)、disable-scroll、bindtouch* / bindlongtap、binderror → 已声明并贯通 |
| 规格「⏭️」 |
type=webgl → 不作为合法值(传入则 error + 仍 2d) |
| 绘制 |
JS Canvas2D:createSelectorQuery().fields({ context: true, size: true }) → ctx.fillRect / stroke … → callUIFunction(drawCommands) |
| 默认值 |
type='2d'、disable-scroll=false;标签默认尺寸 300×150(微信 tip) |
| 尺寸 tip |
标签默认 300×150;绘制面硬上限 1365×1365(仅布局超限时 FRCanvasView clamp + scale + setTransform;未超限仍 width/height:100%,与无 clamp 路径一致) |
属性对照
通用(可交付)
| 属性(模板) |
类型 |
规格默认 |
components.md |
当前实现 |
说明 |
type |
string |
— |
✅ 仅 2d |
✅ type → canvasType(传原值) |
非法 / webgl → native binderror + 仍按 2d 绘制;不 setData 回写 |
canvas-id |
string |
— |
✅ 纳入(可选) |
✅ → canvasId |
同页不可重复;重复 → 隐藏 + binderror + 拒绘 / 无 context |
disable-scroll |
boolean |
false |
✅ 纳入 |
✅ → disableScroll |
true 时 native 空 Pan 抢占,阻止外层页滚 |
bindtouchstart 等 |
event |
— |
✅ |
✅ |
adapter 映射;FRCanvas overlay onTouch |
bindlongtap |
event |
— |
✅ |
✅ longtap → longclick |
|
binderror |
event |
— |
✅ |
✅ |
等 listener 注册后再发(deferred);含 type / 重复 canvas-id |
通用(AI 冲突 — 不声明)
| 属性 |
components.md |
当前实现 |
type=webgl |
⏭️ AI 冲突 |
❌ 不作为合法值;传入则 error + 仍 2d 绘制 |
事件对照
| 事件 |
components.md |
当前实现 |
detail / 备注 |
bindtouchstart / move / end / cancel |
✅ |
✅ |
adapter processEventData 填 touches |
bindlongtap |
✅ |
✅ |
native longclick |
binderror |
✅ |
✅ |
{ errMsg };type 非法 / 重复 canvas-id |
bindtap |
(基础) |
✅ |
tap → click |
实现要点
- TS 声明:交付
type、canvasId、disableScroll。
type:host 写原值 → adapter 原样 → native canvasType;非 2d 时 deferred error;禁止 setData({ type: '2d' })。
canvas-id:可选。NBE 按 rootViewId 注册;冲突置 canvas-id-conflict → visibility:hidden + FRCanvasView 拒 drawCommands + binderror。Domlike 组件层注册表同语义。冲突节点永久隐藏可接受,不因原 owner release 自动复活(微信 tip「不再正常工作」);级联 untrackDescendants release 后,新挂载同 id 可 claim。
disable-scroll:kebab host attr;true 时 PanGesture 抢占。
- 触摸 / 长按:
FRCanvas 对齐 View 的 overlay + LongPressGesture。
- JS 绘图:
NativeBackendElement.getContext(cb) 返回 CanvasRenderingContext2DProxy;冲突时 cb(null)。命令经 drawCommands 落到 ArkUI。布局超过 1365 时才 clamp。flush(onDone?) 须等 native ack 后再标记已绘制;canvasReady=false 时 native 不假成功,onReady 超时(3s)binderror + rejected: canvasNotReady。
- Demo 图表:
canvas-demo/charts.ts 用 JS API 画 line/area/column/pie/radar;禁止 native demo-chart 属性自绘。
- 验证:改 adapter / canvas-context / NBE →
build-jsfwk;改 FRCanvasView.ets → HAP(含 native);改 demo → 重编 pack。
Demo 验收清单
| 项 |
预期 |
| type=2d |
画布可见;触摸可测 |
| canvas-id 唯一 |
可见 |
| 重复 canvas-id |
第二块隐藏 + binderror |
| disable-scroll |
true 时拖动画布不带动页滚 |
| bindtouch* / longtap / error |
状态文案更新 |
| JS 五图 |
query 取 context 后绘制,非空图 |
关键文件
| 角色 |
路径 |
| 组件定义 |
packages/flexui-frontend/src/components/canvas/canvas.ts |
| Domlike 注册表 |
.../canvas/canvas-id-registry.ts |
| Adapter |
.../flexui-backend/src/adapters/canvas-adapter.ts |
| Native 注册表 |
.../native-backend/canvas-id-registry.ts |
| JS 2d 代理 |
.../native-backend/canvas-context.ts |
| Native View |
.../canvas/FRCanvasView.ets |
| Demo |
demos/.../canvas-demo/(含 charts.ts) |