packages/storybook/stories/clip-rect-layer.stories.tsx (122 lines of code) (raw):

import { ClipRectLayer, LayerTree, Matrix, OffsetLayer, PaintStyle, PictureLayer, PictureRecoder, Point, Rasterizer, Rect, Size, Surface, TransformLayer } from '@canvas-ui/core' import type { StoryObj } from '@storybook/react' import React, { useEffect, useRef } from 'react' export const ClipRectLayerTest: 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 makeShapes = () => { // 矩形 const recorder = new PictureRecoder() const canvas = recorder.begin() canvas.drawRect(0, 0, 100, 100, { style: PaintStyle.fill, color: '#CCCCCC', }) canvas.drawRect(0, 0, 100, 100, { style: PaintStyle.stroke, color: '#FF00FF', }) const rect = recorder.end() return { rect, } } const shapes = makeShapes() const canvasRect = canvasElRef.current.getBoundingClientRect() const surfaceSize = Size.scale(Size.fromWH(canvasRect.width, canvasRect.height), devicePixelRatio) const surface = Surface.makeCanvasSurface({ el: canvasElRef.current }) const rasterizer = new Rasterizer({ surface, }) // 构建图层 // 稍后,我们会复用这些图层 const rootLayer = new TransformLayer(Matrix.fromScale(devicePixelRatio)) const offsetLayer = new OffsetLayer(Point.fromXY(0, 0)) rootLayer.appendChild(offsetLayer) const CLIP_PADDING = 10 const clipRectLayer = new ClipRectLayer(Rect.fromLTWH(CLIP_PADDING, CLIP_PADDING, shapes.rect.cullRect.width - CLIP_PADDING * 2, shapes.rect.cullRect.height - CLIP_PADDING * 2)) offsetLayer.appendChild(clipRectLayer) const INNER_CLIP_PADDING = 20 const innerClipRectLayer = new ClipRectLayer(Rect.fromLTWH(0, 0, shapes.rect.cullRect.width - INNER_CLIP_PADDING * 2, shapes.rect.cullRect.height - INNER_CLIP_PADDING * 2)) clipRectLayer.appendChild(innerClipRectLayer) const pictureLayer = new PictureLayer(Point.fromXY(0, 0)) pictureLayer.picture = shapes.rect innerClipRectLayer.appendChild(pictureLayer) type FrameCallback = () => void const frameCallbacks: readonly FrameCallback[] = [ // 0: initial frame () => { // 更新 dpr rootLayer.transform = Matrix.fromScale(devicePixelRatio) offsetLayer.offset = Point.fromXY(0, 0) const layerTree = new LayerTree({ rootLayer }) rasterizer.draw(layerTree, surfaceSize) }, // 1 () => { // 更新 dpr rootLayer.transform = Matrix.fromScale(devicePixelRatio) // 修改了 OffsetLayer,造成位移 offsetLayer.offset = Point.fromXY(10, 10) const layerTree = new LayerTree({ rootLayer }) rasterizer.draw(layerTree, surfaceSize) }, // 2 () => { // 更新 dpr rootLayer.transform = Matrix.fromScale(devicePixelRatio) // 修改了 OffsetLayer,造成位移 offsetLayer.offset = Point.fromXY(20, 20) const layerTree = new LayerTree({ rootLayer }) rasterizer.draw(layerTree, surfaceSize) }, // 3 () => { // 更新 dpr rootLayer.transform = Matrix.fromScale(devicePixelRatio) // 修改了 OffsetLayer,造成位移 offsetLayer.offset = Point.fromXY(10, 10) const layerTree = new LayerTree({ rootLayer }) rasterizer.draw(layerTree, surfaceSize) } ] 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> </> ) } ClipRectLayerTest.storyName = 'ClipRectLayer' export default { title: 'core/compositing', component: ClipRectLayerTest, decorators: [(Story: React.ComponentType) => <div style={{ backgroundColor: '#efefef', width: '100%', height: '100vh' }}><Story /></div>], }