响应式画布舞台演示
您的桌面和移动应用需要响应式/自适应画布吗?
有多种方法可以让您的画布舞台“响应式”,而且不同的应用可能需要不同的行为。
此演示展示了最简单的解决方案:通过缩放将画布舞台适应用户窗口。在此示例中,我们将重点调整舞台宽度。如果需要适应高度,您可以添加额外的逻辑。
说明: 尝试调整浏览器窗口大小,看看画布如何自适应。
- Vanilla
- React
- Vue
import Konva from 'konva';
// 定义场景的虚拟尺寸
// 实际尺寸会根据用户页面进行调整
const sceneWidth = 1000;
const sceneHeight = 1000;
// 创建初始尺寸的舞台
const stage = new Konva.Stage({
container: 'container',
width: sceneWidth,
height: sceneHeight,
});
const layer = new Konva.Layer();
stage.add(layer);
// 在中心添加圆形
const circle = new Konva.Circle({
radius: 50,
fill: 'red',
x: stage.width() / 2,
y: stage.height() / 2,
});
layer.add(circle);
// 在舞台右下角添加矩形
const rect = new Konva.Rect({
fill: 'green',
x: stage.width() - 100,
y: stage.height() - 100,
width: 100,
height: 100,
});
layer.add(rect);
// 添加一些文本
const text = new Konva.Text({
x: 20,
y: 20,
text: '尝试调整浏览器窗口大小',
fontSize: 20,
fontFamily: 'Arial',
fill: 'black',
});
layer.add(text);
// 使舞台响应式的函数
function fitStageIntoParentContainer() {
// 获取容器元素
const container = document.getElementById('container');
// 让容器宽度占满 100%
container.style.width = '100%';
// 获取当前容器宽度
const containerWidth = container.offsetWidth;
// 根据虚拟宽度与实际宽度计算缩放比例
const scale = containerWidth / sceneWidth;
// 设置舞台尺寸和缩放
stage.width(sceneWidth * scale);
stage.height(sceneHeight * scale);
stage.scale({ x: scale, y: scale });
}
// 初次自适应
fitStageIntoParentContainer();
// 窗口大小改变时自适应舞台
window.addEventListener('resize', fitStageIntoParentContainer);
import { useState, useEffect, useRef } from 'react';
import { Stage, Layer, Circle, Rect, Text } from 'react-konva';
const App = () => {
// 定义场景的虚拟尺寸
const sceneWidth = 1000;
const sceneHeight = 1000;
// 状态用于追踪当前缩放和尺寸
const [stageSize, setStageSize] = useState({
width: sceneWidth,
height: sceneHeight,
scale: 1
});
// 父容器引用
const containerRef = useRef(null);
// 处理调整大小的函数
const updateSize = () => {
if (!containerRef.current) return;
// 获取容器宽度
const containerWidth = containerRef.current.offsetWidth;
// 计算缩放比例
const scale = containerWidth / sceneWidth;
// 更新状态,设置新尺寸
setStageSize({
width: sceneWidth * scale,
height: sceneHeight * scale,
scale: scale
});
};
// 组件挂载及窗口大小变化时更新尺寸
useEffect(() => {
updateSize();
window.addEventListener('resize', updateSize);
return () => {
window.removeEventListener('resize', updateSize);
};
}, []);
return (
<div
ref={containerRef}
style={{ width: '100%', height: '100%' }}
>
<Stage
width={stageSize.width}
height={stageSize.height}
scaleX={stageSize.scale}
scaleY={stageSize.scale}
>
<Layer>
<Circle
radius={50}
fill="red"
x={sceneWidth / 2}
y={sceneHeight / 2}
/>
<Rect
fill="green"
x={sceneWidth - 100}
y={sceneHeight - 100}
width={100}
height={100}
/>
<Text
x={20}
y={20}
text="尝试调整浏览器窗口大小"
fontSize={20}
fontFamily="Arial"
fill="black"
/>
</Layer>
</Stage>
</div>
);
};
export default App;
<template>
<div ref="containerRef" style="width: 100%; height: 100%;">
<v-stage
:config="{
width: stageWidth,
height: stageHeight,
scaleX: scale,
scaleY: scale
}"
>
<v-layer>
<v-circle
:config="{
radius: 50,
fill: 'red',
x: sceneWidth / 2,
y: sceneHeight / 2
}"
/>
<v-rect
:config="{
fill: 'green',
x: sceneWidth - 100,
y: sceneHeight - 100,
width: 100,
height: 100
}"
/>
<v-text
:config="{
x: 20,
y: 20,
text: '尝试调整浏览器窗口大小',
fontSize: 20,
fontFamily: 'Arial',
fill: 'black'
}"
/>
</v-layer>
</v-stage>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, computed } from 'vue';
// 定义场景的虚拟尺寸
const sceneWidth = 1000;
const sceneHeight = 1000;
// 响应式引用
const containerRef = ref(null);
const scale = ref(1);
// 计算舞台尺寸
const stageWidth = computed(() => sceneWidth * scale.value);
const stageHeight = computed(() => sceneHeight * scale.value);
// 处理调整大小的函数
const updateSize = () => {
if (!containerRef.value) return;
// 获取容器宽度
const containerWidth = containerRef.value.offsetWidth;
// 计算缩放比例
scale.value = containerWidth / sceneWidth;
};
// 添加事件监听
onMounted(() => {
updateSize();
window.addEventListener('resize', updateSize);
});
// 清理监听器
onUnmounted(() => {
window.removeEventListener('resize', updateSize);
});
</script>