如何给画布添加背景?
如何给 Konva 舞台添加背景?
有两种方式可以添加背景。
1. 使用 Konva.Rect
形状添加背景。
Konva 推荐的给画布添加背景的方法是,在场景底部绘制一个与舞台大小相同的 Konva.Rect
矩形形状。你可以根据需要为该矩形设置样式,如纯色、渐变或图案图片。
这里唯一需要注意的是矩形的位置和大小。如果你对背景形状的任意父级 (比如舞台或图层)进行移动或缩放等变换,你需要“重置”背景形状的位置和大小,使其填满整个舞台区域。
2. 使用 CSS 添加背景
另一种给画布添加背景的方案是直接使用 CSS 样式给舞台的容器 DOM 元素设置背景。这个方法比第一种更简单,因为你不用再去追踪位置和大小的变化。它也有稍微更好的性能表现,因为不需要绘制额外的图形。
但它有一个缺点:使用 stage.toImage()
和 stage.toDataURL()
等导出方法时,CSS 背景不会被导出显示。
**说明:**下面示例中,绿色纯色背景是用 CSS 实现的。黄色到蓝色的渐变背景是用 Konva.Rect
实例绘制的。尝试拖动舞台,你会看到渐变背景保持固定位置。
- Vanilla
- React
- Vue
import Konva from 'konva'; const width = window.innerWidth; const height = window.innerHeight; const stage = new Konva.Stage({ container: 'container', width: width, height: height, draggable: true, }); const layer = new Konva.Layer(); stage.add(layer); // 这里演示两种给舞台添加背景的方法。 // 最简单的是直接用 CSS stage.container().style.backgroundColor = 'green'; // 另一种是用矩形 形状 const background = new Konva.Rect({ x: 0, y: 0, width: stage.width(), height: stage.height(), fillLinearGradientStartPoint: { x: 0, y: 0 }, fillLinearGradientEndPoint: { x: stage.width(), y: stage.height() }, // 渐变为透明色,以便能看到 CSS 背景 fillLinearGradientColorStops: [ 0, 'yellow', 0.5, 'blue', 0.6, 'rgba(0, 0, 0, 0)', ], // 为提升性能,移除背景的事件监听 // 因为背景不需要处理任何事件 listening: false, }); layer.add(background); // 舞台是可拖拽的 // 这意味着背景的绝对位置可能变化 // 所以需要在拖动时重置位置为 {0, 0} stage.on('dragmove', () => { background.absolutePosition({ x: 0, y: 0 }); }); // 添加示例图形 const circle = new Konva.Circle({ x: stage.width() / 2, y: stage.height() / 2, radius: 100, fill: 'red', }); layer.add(circle);
import { useState, useRef, useEffect } from 'react'; import { Stage, Layer, Rect, Circle } from 'react-konva'; const App = () => { const width = window.innerWidth; const height = window.innerHeight; const stageRef = useRef(null); const backgroundRef = useRef(null); // 组件挂载时设置 CSS 背景 useEffect(() => { if (stageRef.current) { // 给舞台容器设置 CSS 背景 const container = stageRef.current.container(); container.style.backgroundColor = 'green'; } }, []); // 拖动舞台时重置背景位置 const handleDragMove = () => { if (backgroundRef.current) { backgroundRef.current.absolutePosition({ x: 0, y: 0 }); } }; return ( <Stage width={width} height={height} draggable ref={stageRef} onDragMove={handleDragMove} > <Layer> {/* 渐变背景 */} <Rect ref={backgroundRef} x={0} y={0} width={width} height={height} fillLinearGradientStartPoint={{ x: 0, y: 0 }} fillLinearGradientEndPoint={{ x: width, y: height }} fillLinearGradientColorStops={[ 0, 'yellow', 0.5, 'blue', 0.6, 'rgba(0, 0, 0, 0)' ]} listening={false} /> {/* 示例图形 */} <Circle x={width / 2} y={height / 2} radius={100} fill="red" /> </Layer> </Stage> ); }; export default App;
<template> <v-stage ref="stageRef" :config="stageConfig" @dragmove="handleDragMove" > <v-layer> <!-- 渐变背景 --> <v-rect ref="backgroundRef" :config="backgroundConfig" /> <!-- 示例图形 --> <v-circle :config="circleConfig" /> </v-layer> </v-stage> </template> <script setup> import { ref, onMounted, computed } from 'vue'; const width = window.innerWidth; const height = window.innerHeight; const stageRef = ref(null); const backgroundRef = ref(null); const stageConfig = { width, height, draggable: true }; const backgroundConfig = { x: 0, y: 0, width: width, height: height, fillLinearGradientStartPoint: { x: 0, y: 0 }, fillLinearGradientEndPoint: { x: width, y: height }, fillLinearGradientColorStops: [ 0, 'yellow', 0.5, 'blue', 0.6, 'rgba(0, 0, 0, 0)' ], listening: false }; const circleConfig = { x: width / 2, y: height / 2, radius: 100, fill: 'red' }; // 组件挂载时设置 CSS 背景 onMounted(() => { if (stageRef.value) { // 给舞台容器设置 CSS 背景 const container = stageRef.value.getNode().container(); container.style.backgroundColor = 'green'; } }); // 拖动舞台时重置背景位置 const handleDragMove = () => { if (backgroundRef.value) { backgroundRef.value.getNode().absolutePosition({ x: 0, y: 0 }); } }; </script>