HTML5 Canvas 层管理性能提示
在创建 Konva 应用时,关于性能,最重要的考虑是层管理。Konva 相较于其他画布库的一个突出特点是,它使我们能够创建各个独立的层,每个层都有自己的画布元素。这意味着我们可以对某些舞台元素进行动画、过渡或更新,而无需重新绘制其他元素。如果我们检查一个 Konva 舞台的 DOM,我们会发现实际上每个层都有一个画布元素。
本教程包含两个层,一个是动画层,另一个是包含文本的静态层。由于没有理由不断重 绘文本,所以它被放置在自己的层中。
注意:不要创建太多层。通常最大为 3-5 个。
下面是一个展示高效层管理的示例:
- Vanilla
- React
- Vue
import Konva from 'konva'; const stage = new Konva.Stage({ container: 'container', width: window.innerWidth, height: window.innerHeight, }); // 静态文本层 const textLayer = new Konva.Layer(); stage.add(textLayer); // 动画形状层 const animLayer = new Konva.Layer(); stage.add(animLayer); // 添加静态文本 const text = new Konva.Text({ x: 20, y: 20, text: '这段文本在一个静态层中。\n下方的圆是在动画层中。', fontSize: 16, fill: 'black' }); textLayer.add(text); // 添加动画圆形 const circle = new Konva.Circle({ x: 100, y: 100, radius: 30, fill: 'red', }); animLayer.add(circle); // 创建动画 const anim = new Konva.Animation((frame) => { // 按"8"字形移动圆形 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}> {/* 静态文本层 */} <Layer> <Text x={20} y={20} text="这段文本在一个静态层中。\n下方的圆是在动画层中。" fontSize={16} fill="black" /> </Layer> {/* 动画形状层 */} <Layer> <Circle ref={circleRef} x={100} y={100} radius={30} fill="red" /> </Layer> </Stage> ); }; export default App;
<template> <v-stage :config="stageSize"> <!-- 静态文本层 --> <v-layer> <v-text :config="textConfig" /> </v-layer> <!-- 动画形状层 --> <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: '这段文本在一个静态层中。\n下方的圆是在动画层中。', 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>