packages/storybook/stories/render-canvas.stories.tsx (93 lines of code) (raw):

import { createElement, Point, Size } from '@canvas-ui/core' import type { StoryObj } from '@storybook/react' import React, { useEffect, useRef } from 'react' export const RenderCanvasTest: StoryObj<React.FC> = () => { const canvasElRef = useRef<HTMLCanvasElement | null>(null) const prevFrameButtonRef = useRef<HTMLButtonElement | null>(null) const nextFrameButtonRef = useRef<HTMLButtonElement | null>(null) useEffect(() => { // 等待布局稳定 setTimeout(() => { if (!canvasElRef.current) { return } const canvasRect = canvasElRef.current.getBoundingClientRect() const surfaceSize = Size.fromWH(canvasRect.width, canvasRect.height) const canvas = createElement('Canvas') canvas.prepareInitialFrame() canvas.el = canvasElRef.current canvas.size = surfaceSize canvas.dpr = devicePixelRatio // // 构造如下结构 // a - d (动态添加) // / \ // b c // const a = createElement('View') a.size = Size.fromWH(200, 200) const b = createElement('View') b.size = Size.fromWH(50, 50) b.offset = Point.fromXY(10, 10) a.appendChild(b) const c = createElement('View') c.size = Size.fromWH(50, 50) c.offset = Point.fromXY(30, 30) a.appendChild(c) const d = createElement('View') d.repaintBoundary = false d.size = Size.fromWH(50, 50) d.offset = Point.fromXY(60, 60) type FrameCallback = () => void const frameCallbacks: readonly FrameCallback[] = [ // 0: initial frame () => { a.offset = Point.zero canvas.child = a }, () => { a.offset = Point.fromXY(50, 50) }, () => { d.repaintBoundary = true }, () => { a.appendChild(d) }, () => { d.repaintBoundary = false }, () => { a.removeChild(d) d.repaintBoundary = true }, () => { canvas.child = undefined } ] let frame = -1 const play = (direction = 1) => { frame += direction if (frame >= frameCallbacks.length) { frame = 0 } else if (frame < 0) { frame = frameCallbacks.length - 1 } frameCallbacks[frame]() } // 绘制首帧 play() prevFrameButtonRef.current?.addEventListener('click', () => { play(-1) }) nextFrameButtonRef.current?.addEventListener('click', () => { play(1) }) }, 100) }, [canvasElRef]) return ( <> <div> <button ref={prevFrameButtonRef}>prev frame</button> <button ref={nextFrameButtonRef}>next frame</button> </div> <canvas style={{ backgroundColor: '#ffffff', width: '500px', height: '500px' }} ref={canvasElRef}></canvas> </> ) } RenderCanvasTest.storyName = 'RenderCanvas' export default { title: 'core/rendering', component: RenderCanvasTest, decorators: [(Story: React.ComponentType) => <div style={{ backgroundColor: '#efefef', width: '100%', height: '100vh' }}><Story /></div>], }