画布形状上的手势事件
如何在画布形状上监听滑动、捏合缩放、旋转和其他多点触控手势事件?
默认情况下,Konva
仅支持基本的触摸事件,如 touchstart
、touchmove
、touchend
。
你需要手动从这些触摸事件中实现手势事件。
如果你在寻找整个舞台的平移和缩放逻辑,可以查看 多点触控缩放舞台演示。
但我能够稍微修改 Hammer.js 使其与 Konva 一起工作!
你可以在这里找到修改后的 hammer.js 源代码。
说明:你可以在矩形上试验不同的手势,如滑动、旋转、缩放、拖放、按压。在桌面浏览器上,按住 Shift
键可以模拟触摸事件。
- Vanilla
import Konva from 'konva'; // 加载所需的脚本 const loadScript = (src) => { return new Promise((resolve, reject) => { if (document.querySelector(`script[src="${src}"]`)) { resolve(); return; } const script = document.createElement('script'); script.src = src; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); }); }; // 加载依赖后初始化演示 async function initDemo() { try { await loadScript('https://cdn.rawgit.com/hammerjs/touchemulator/master/touch-emulator.js'); await loadScript('https://konvajs.org/js/hammer-konva.js'); // 在桌面上模拟触摸 TouchEmulator(); Konva.hitOnDragEnabled = true; Konva.captureTouchEventsEnabled = true; const stage = new Konva.Stage({ container: 'container', width: window.innerWidth, height: window.innerHeight, }); const layer = new Konva.Layer(); stage.add(layer); const originalAttrs = { x: stage.width() / 2, y: stage.height() / 2, scaleX: 1, scaleY: 1, draggable: true, rotation: 0, }; const group = new Konva.Group(originalAttrs); layer.add(group); const size = 200; const rect = new Konva.Rect({ width: size, height: size, fill: 'yellow', offsetX: size / 2, offsetY: size / 2, cornerRadius: 5, shadowBlur: 10, shadowColor: 'grey', }); group.add(rect); const defaultText = '试试\拖动、滑动、捏合缩放、旋转、按压...'; const text = new Konva.Text({ text: defaultText, x: -size / 2, width: size, align: 'center', }); group.add(text); // 附加修改后的 Hammer.js // "domEvents" 属性允许在组上触发事件 // 而不是 "hammertime" 实例 const hammertime = new Hammer(group, { domEvents: true }); // 添加旋转手势 hammertime.get('rotate').set({ enable: true }); // 现在附加所有可能的事件 group.on('swipe', function (ev) { text.text('正在滑动'); group.to({ x: group.x() + ev.evt.gesture.deltaX, y: group.y() + ev.evt.gesture.deltaY, onFinish: function () { group.to(Object.assign({}, originalAttrs)); text.text(defaultText); }, }); }); group.on('press', function (ev) { text.text('正在按压'); rect.to({ fill: 'green', }); }); group.on('touchend', function (ev) { rect.to({ fill: 'yellow', }); setTimeout(() => { text.text(defaultText); }, 300); }); group.on('dragend', () => { group.to(Object.assign({}, originalAttrs)); }); let oldRotation = 0; let startScale = 0; group.on('rotatestart', function (ev) { oldRotation = ev.evt.gesture.rotation; startScale = rect.scaleX(); group.stopDrag(); group.draggable(false); text.text('正在旋转...'); }); group.on('rotate', function (ev) { const delta = oldRotation - ev.evt.gesture.rotation; group.rotate(-delta); oldRotation = ev.evt.gesture.rotation; group.scaleX(startScale * ev.evt.gesture.scale); group.scaleY(startScale * ev.evt.gesture.scale); }); group.on('rotateend rotatecancel', function (ev) { group.to(Object.assign({}, originalAttrs)); text.text(defaultText); group.draggable(true); }); } catch (error) { console.error('初始化演示失败:', error); } } // 启动演示 initDemo();