HTML5 Canvas 图层管理性能技巧
创建 Konva 应用时,性能方面最重要的考虑因素是图层管理。 Konva 与其他 Canvas 库的一个区别是,它可以创建独立图层, 并让每个图层使用自己的 Canvas 元素。这意味着,我们可以对部分舞台元素 执行动画、过渡或更新,而不重绘其他元素。 检查 Konva 舞台的 DOM 时,可以看到每个图层都有一个 Canvas 元素。
本教程包含两个图层:一个动画图层,以及一个包含文本的静态图层。 由于没有必要持续重绘文本,因此文本位于单独的图层中。
注意:不要创建过多图层。通常最多使用 3 到 5 个图层。
以下示例展示了高效的图层管理:
- Vanilla
- React
- Vue
import Konva from 'konva'; const stage = new Konva.Stage({ container: 'container', width: window.innerWidth, height: window.innerHeight, }); // Static layer for text const textLayer = new Konva.Layer(); stage.add(textLayer); // Animated layer for shapes const animLayer = new Konva.Layer(); stage.add(animLayer); // Add static text const text = new Konva.Text({ x: 20, y: 20, text: 'This text is in a static layer.\nThe circle below is in an animated layer.', fontSize: 16, fill: 'black' }); textLayer.add(text); // Add animated circle const circle = new Konva.Circle({ x: 100, y: 100, radius: 30, fill: 'red', }); animLayer.add(circle); // Create animation const anim = new Konva.Animation((frame) => { // Move circle in a figure-8 pattern const scale = 100; const centerX = stage.width() / 2; const centerY = stage.height() / 2; circle.x(centerX + Math.sin(frame.time / 1000) * scale); circle.y(centerY + Math.sin(frame.time / 2000) * scale); }, animLayer); anim.start();
import { Stage, Layer, Text, Circle } from 'react-konva'; import { useEffect, useRef } from 'react'; const App = () => { const circleRef = useRef(null); useEffect(() => { const anim = new Konva.Animation((frame) => { const scale = 100; const centerX = window.innerWidth / 2; const centerY = window.innerHeight / 2; circleRef.current.x(centerX + Math.sin(frame.time / 1000) * scale); circleRef.current.y(centerY + Math.sin(frame.time / 2000) * scale); }, circleRef.current.getLayer()); anim.start(); return () => anim.stop(); }, []); return ( <Stage width={window.innerWidth} height={window.innerHeight}> {/* Static layer for text */} <Layer> <Text x={20} y={20} text="This text is in a static layer.\nThe circle below is in an animated layer." fontSize={16} fill="black" /> </Layer> {/* Animated layer for shapes */} <Layer> <Circle ref={circleRef} x={100} y={100} radius={30} fill="red" /> </Layer> </Stage> ); }; export default App;
<template> <v-stage :config="stageSize"> <!-- Static layer for text --> <v-layer> <v-text :config="textConfig" /> </v-layer> <!-- Animated layer for shapes --> <v-layer ref="animLayerRef"> <v-circle ref="circleRef" :config="circleConfig" /> </v-layer> </v-stage> </template> <script setup> import { ref, onMounted, onUnmounted } from 'vue'; import Konva from 'konva'; const stageSize = { width: window.innerWidth, height: window.innerHeight }; const textConfig = { x: 20, y: 20, text: 'This text is in a static layer.\nThe circle below is in an animated layer.', fontSize: 16, fill: 'black' }; const circleConfig = ref({ x: 100, y: 100, radius: 30, fill: 'red' }); const animLayerRef = ref(null); const circleRef = ref(null); let anim = null; onMounted(() => { anim = new Konva.Animation((frame) => { const scale = 100; const centerX = window.innerWidth / 2; const centerY = window.innerHeight / 2; const circle = circleRef.value.getNode(); circle.x(centerX + Math.sin(frame.time / 1000) * scale); circle.y(centerY + Math.sin(frame.time / 2000) * scale); }, animLayerRef.value.getNode()); anim.start(); }); onUnmounted(() => { if (anim) { anim.stop(); } }); </script>