响应式画布舞台演示
您的桌面和移动应用需要响应式/自适应画布吗?
有多种方法可以让您的画布舞台“响应式”,而且不同的应用可能需要不同的行为。
此演示展示了最简单的解决方案:通过缩放将画布舞台适应用户窗口。在此示例中,我们将重点调整舞台宽度。如果需要适应高度,您可以添加额外的逻辑。
说明: 尝试调整浏览器窗口大小,看看画布如何自适应。
- 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>