Skip to main content

如何使用 Konva 创建响应式画布

画布具有显示尺寸和绘制尺寸。CSS 调整大小只会改变显示尺寸。这种改变可能会拉伸渲染出的像素。

对于响应式 Konva 场景,请定义一个固定的虚拟尺寸。然后根据可用的容器宽度缩放舞台。

缩放公式为:

scale = containerWidth / virtualWidth

显示高度为 virtualHeight * scale。所有节点坐标都保持在虚拟坐标系中。

响应式 React 示例

此示例使用 ResizeObserver。当容器尺寸发生变化时,观察器会做出响应,而不仅仅是在浏览器窗口尺寸发生变化时响应。

import { useEffect, useRef, useState } from 'react';
import { Stage, Layer, Rect, Circle, Text } from 'react-konva';

const VIRTUAL_WIDTH = 900;
const VIRTUAL_HEIGHT = 420;

const App = () => {
const containerRef = useRef(null);
const [containerWidth, setContainerWidth] = useState(VIRTUAL_WIDTH);
const [circlePosition, setCirclePosition] = useState({
x: VIRTUAL_WIDTH / 2,
y: VIRTUAL_HEIGHT / 2,
});
const [rectanglePosition, setRectanglePosition] = useState({
x: VIRTUAL_WIDTH - 190,
y: VIRTUAL_HEIGHT - 130,
});

useEffect(() => {
const container = containerRef.current;
const observer = new ResizeObserver(([entry]) => {
setContainerWidth(entry.contentRect.width);
});

observer.observe(container);
return () => observer.disconnect();
}, []);

const scale = containerWidth / VIRTUAL_WIDTH;

return (
<div ref={containerRef} style={{ width: '100%' }}>
<Stage
width={containerWidth}
height={VIRTUAL_HEIGHT * scale}
scaleX={scale}
scaleY={scale}
>
<Layer>
<Rect
width={VIRTUAL_WIDTH}
height={VIRTUAL_HEIGHT}
fill="#e7f5ff"
/>
<Text
x={40}
y={35}
text="900 × 420 virtual scene"
fontSize={28}
fill="#1864ab"
/>
<Circle
x={circlePosition.x}
y={circlePosition.y}
radius={70}
fill="#4dabf7"
draggable
onDragEnd={(event) => {
setCirclePosition(event.target.position());
}}
/>
<Rect
x={rectanglePosition.x}
y={rectanglePosition.y}
width={150}
height={90}
fill="#74c0fc"
cornerRadius={10}
draggable
onDragEnd={(event) => {
setRectanglePosition(event.target.position());
}}
/>
</Layer>
</Stage>
</div>
);
};

export default App;

不要在应用程序状态中存储缩放后的坐标。请存储虚拟坐标。Konva 会在渲染和指针转换期间应用舞台缩放。

对于高像素密度,Konva 默认使用设备像素比。除非应用程序自行管理后备存储,否则不要将舞台尺寸乘以 devicePixelRatio

如需了解更多舞台调整大小的详细信息,请参阅响应式沙盒演示