如何使用 Konva 创建响应式 Canvas
Canvas 有显示尺寸和绘制尺寸。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;
不要在应用的 state 中存储缩放后的坐标。请存储虚拟坐标。Konva 在绘制和转换指针坐标时应用舞台缩放比例。
对于高像素密度屏幕,Konva 默认使用设备像素比。除非应用自行管理后备存储,否则不要用 devicePixelRatio 乘以舞台尺寸。
有关调整舞台尺寸的更多信息,请参阅响应式 Canvas 沙盒示例。