动画压力测试
此演示创建了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, }); /* * 将 listening 属性设置为 false 将改善 * 绘制性能,因为矩形不必被 * 绘制到命中图上 */ 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; // 矩形的状态 const [boxes, setBoxes] = useState([]); // 动画引用以跟踪动画 const animRef = useRef(null); const layerRef = useRef(null); // 生成随机矩形 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, // 初始旋转 }); } setBoxes(newBoxes); }, [width, height]); // 挂载时设置动画 useEffect(() => { if (layerRef.current && boxes.length > 0) { // 创建动画 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()); // 开始动画 animRef.current.start(); // 卸载时清理 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; // 生成具有随机属性的矩形 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; // 创建完矩形后开始动画 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(); } }); }); // 卸载时清理动画 onUnmounted(() => { if (animation) { animation.stop(); } }); </script>
说明: 此演示展示了 Konva 的动画能力,通过同时旋转300个矩形。观看这些形状在屏幕上平滑旋转。