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>