动画压力测试
此示例创建 300 个大小、位置和颜色随机的矩形,然后通过旋转每个矩形为它们设置动画。将图层的 listening 属性设为 false 可以优化动画性能。这样,矩形不会绘制到命中图,因此绘制性能会更好。
- Vanilla
- React
- Vue
import Konva from 'konva'; const width = window.innerWidth; const height = window.innerHeight; function update(layer, frame) { const angularSpeed = 100; const angularDiff = (angularSpeed * frame.timeDiff) / 1000; const shapes = layer.getChildren(); for (let n = 0; n < shapes.length; n++) { const shape = shapes[n]; shape.rotate(angularDiff); } } const stage = new Konva.Stage({ container: 'container', width: width, height: height, }); /* * setting the listening property to false will improve * drawing performance because the rectangles won't have to be * drawn onto the hit graph */ const layer = new Konva.Layer({ listening: false, }); const colors = [ 'red', 'orange', 'yellow', 'green', 'blue', 'cyan', 'purple', ]; let colorIndex = 0; for (let i = 0; i < 300; i++) { const color = colors[colorIndex++]; if (colorIndex >= colors.length) { colorIndex = 0; } const randWidth = Math.random() * 100 + 20; const randHeight = Math.random() * 100 + 20; const randX = Math.random() * stage.width() - 20; const randY = Math.random() * stage.height() - 20; const box = new Konva.Rect({ x: randX, y: randY, offset: { x: randWidth / 2, y: randHeight / 2, }, width: randWidth, height: randHeight, fill: color, stroke: 'black', strokeWidth: 4, }); layer.add(box); } stage.add(layer); const anim = new Konva.Animation(function (frame) { update(layer, frame); }, layer); anim.start();
import { useState, useEffect, useRef } from 'react'; import { Stage, Layer, Rect } from 'react-konva'; import Konva from 'konva'; const App = () => { const width = window.innerWidth; const height = window.innerHeight; // State for rectangles const [boxes, setBoxes] = useState([]); // Animation ref to keep track of the animation const animRef = useRef(null); const layerRef = useRef(null); // Generate random boxes useEffect(() => { const colors = [ 'red', 'orange', 'yellow', 'green', 'blue', 'cyan', 'purple', ]; const newBoxes = []; let colorIndex = 0; for (let i = 0; i < 300; i++) { const color = colors[colorIndex++]; if (colorIndex >= colors.length) { colorIndex = 0; } const randWidth = Math.random() * 100 + 20; const randHeight = Math.random() * 100 + 20; const randX = Math.random() * width - 20; const randY = Math.random() * height - 20; newBoxes.push({ id: i, x: randX, y: randY, width: randWidth, height: randHeight, offsetX: randWidth / 2, offsetY: randHeight / 2, fill: color, stroke: 'black', strokeWidth: 4, rotation: 0, // Initial rotation }); } setBoxes(newBoxes); }, [width, height]); // Setup animation on mount useEffect(() => { if (layerRef.current && boxes.length > 0) { // Create animation const angularSpeed = 100; animRef.current = new Konva.Animation((frame) => { const angularDiff = (angularSpeed * frame.timeDiff) / 1000; setBoxes(prevBoxes => prevBoxes.map(box => ({ ...box, rotation: box.rotation + angularDiff })) ); }, layerRef.current.getLayer()); // Start animation animRef.current.start(); // Cleanup on unmount return () => { if (animRef.current) { animRef.current.stop(); } }; } }, [boxes.length]); return ( <Stage width={width} height={height}> <Layer ref={layerRef} listening={false}> {boxes.map((box) => ( <Rect key={box.id} x={box.x} y={box.y} width={box.width} height={box.height} offsetX={box.offsetX} offsetY={box.offsetY} fill={box.fill} stroke={box.stroke} strokeWidth={box.strokeWidth} rotation={box.rotation} /> ))} </Layer> </Stage> ); }; export default App;
<template> <v-stage :config="stageConfig"> <v-layer ref="layer" :config="{ listening: false }"> <v-rect v-for="box in boxes" :key="box.id" :config="box" /> </v-layer> </v-stage> </template> <script setup> import { ref, onMounted, onUnmounted, computed, nextTick } from 'vue'; import Konva from 'konva'; const width = window.innerWidth; const height = window.innerHeight; const stageConfig = { width, height }; const layer = ref(null); const boxes = ref([]); let animation = null; // Generate boxes with random properties onMounted(() => { const colors = [ 'red', 'orange', 'yellow', 'green', 'blue', 'cyan', 'purple', ]; let colorIndex = 0; const newBoxes = []; for (let i = 0; i < 300; i++) { const color = colors[colorIndex++]; if (colorIndex >= colors.length) { colorIndex = 0; } const randWidth = Math.random() * 100 + 20; const randHeight = Math.random() * 100 + 20; const randX = Math.random() * width - 20; const randY = Math.random() * height - 20; newBoxes.push({ id: i, x: randX, y: randY, width: randWidth, height: randHeight, offset: { x: randWidth / 2, y: randHeight / 2, }, fill: color, stroke: 'black', strokeWidth: 4, rotation: 0, }); } boxes.value = newBoxes; // Start animation after boxes are created nextTick(() => { if (layer.value) { const angularSpeed = 100; animation = new Konva.Animation((frame) => { const angularDiff = (angularSpeed * frame.timeDiff) / 1000; boxes.value.forEach(box => { box.rotation += angularDiff; }); }, layer.value.getNode()); animation.start(); } }); }); // Cleanup animation on unmount onUnmounted(() => { if (animation) { animation.stop(); } }); </script>
操作说明: 此示例同时旋转 300 个矩形,以展示 Konva 的动画能力。观察这些图形在屏幕上流畅旋转。