相对于指针位置的缩放舞台
这个演示展示了如何实现相对于鼠标指针位置的缩放。这创建了一个更自然的缩放体验,使内容围绕鼠标光标缩放。
**说明:**使用鼠标滚轮或触控板来缩放。注意内容是如何围绕光标的位置缩放,而不是舞台的中心。
- 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, }); const layer = new Konva.Layer(); stage.add(layer); const circle = new Konva.Circle({ x: stage.width() / 2, y: stage.height() / 2, radius: 50, fill: 'green', }); layer.add(circle); const scaleBy = 1.01; stage.on('wheel', (e) => { // 阻止默认的滚动 e.evt.preventDefault(); const oldScale = stage.scaleX(); const pointer = stage.getPointerPosition(); const mousePointTo = { x: (pointer.x - stage.x()) / oldScale, y: (pointer.y - stage.y()) / oldScale, }; // 如何缩放?放大 ?还是缩小? let direction = e.evt.deltaY > 0 ? 1 : -1; // 当我们在触控板上缩放时,e.evt.ctrlKey 为 true // 在这种情况下,反转方向 if (e.evt.ctrlKey) { direction = -direction; } const newScale = direction > 0 ? oldScale * scaleBy : oldScale / scaleBy; stage.scale({ x: newScale, y: newScale }); const newPos = { x: pointer.x - mousePointTo.x * newScale, y: pointer.y - mousePointTo.y * newScale, }; stage.position(newPos); });
import { Stage, Layer, Circle } from 'react-konva'; import { useRef } from 'react'; const App = () => { const width = window.innerWidth; const height = window.innerHeight; const stageRef = useRef(null); const handleWheel = (e) => { e.evt.preventDefault(); const stage = stageRef.current; const oldScale = stage.scaleX(); const pointer = stage.getPointerPosition(); const mousePointTo = { x: (pointer.x - stage.x()) / oldScale, y: (pointer.y - stage.y()) / oldScale, }; // 如何缩放?放大?还是缩小? let direction = e.evt.deltaY > 0 ? 1 : -1; // 当我们在触控板上缩放时,e.evt.ctrlKey 为 true // 在这种情况下,反转方向 if (e.evt.ctrlKey) { direction = -direction; } const scaleBy = 1.01; const newScale = direction > 0 ? oldScale * scaleBy : oldScale / scaleBy; stage.scale({ x: newScale, y: newScale }); const newPos = { x: pointer.x - mousePointTo.x * newScale, y: pointer.y - mousePointTo.y * newScale, }; stage.position(newPos); }; return ( <Stage width={width} height={height} ref={stageRef} onWheel={handleWheel} > <Layer> <Circle x={width / 2} y={height / 2} radius={50} fill="green" /> </Layer> </Stage> ); }; export default App;
<template> <v-stage ref="stageRef" :config="stageConfig" @wheel="handleWheel" > <v-layer> <v-circle :config="circleConfig" /> </v-layer> </v-stage> </template> <script setup> import { ref, computed } from 'vue'; const width = window.innerWidth; const height = window.innerHeight; const stageRef = ref(null); const stageConfig = computed(() => ({ width, height, })); const circleConfig = computed(() => ({ x: width / 2, y: height / 2, radius: 50, fill: 'green', })); const handleWheel = (e) => { e.evt.preventDefault(); const stage = stageRef.value.getNode(); const oldScale = stage.scaleX(); const pointer = stage.getPointerPosition(); const mousePointTo = { x: (pointer.x - stage.x()) / oldScale, y: (pointer.y - stage.y()) / oldScale, }; // 如何缩放?放大?还是缩小? let direction = e.evt.deltaY > 0 ? 1 : -1; // 当我们在触控板上缩放时,e.evt.ctrlKey 为 true // 在这种情况下,反转方向 if (e.evt.ctrlKey) { direction = -direction; } const scaleBy = 1.01; const newScale = direction > 0 ? oldScale * scaleBy : oldScale / scaleBy; stage.scale({ x: newScale, y: newScale }); const newPos = { x: pointer.x - mousePointTo.x * newScale, y: pointer.y - mousePointTo.y * newScale, }; stage.position(newPos); }; </script>