fabric.JS移动端Zoom缩放与Move平移功能失效问题求助
Fabric.js 触摸事件适配问题修复
问题描述
- 鼠标滚轮可实现画布缩放,但移动端触屏无法完成缩放操作;
- 电脑端通过Alt+左键可平移画布,但移动端触屏无法平移画布。
修复方案
移动端双指缩放
利用Fabric.js的touch:gesture事件,通过事件对象的scale属性获取双指缩放比例,结合当前画布缩放值计算新的缩放级别,并以双指中心点作为缩放原点:
canvas.on('touch:gesture', function(e) { if (e.scale && e.scale !== 1) { var currentZoom = canvas.getZoom(); var newZoom = currentZoom * e.scale; // 限制缩放范围 newZoom = Math.max(0.01, Math.min(20, newZoom)); // 以双指中心点为缩放原点 var centerPoint = { x: e.center.x, y: e.center.y }; canvas.zoomToPoint(centerPoint, newZoom); e.e.preventDefault(); e.e.stopPropagation(); } });
移动端单指平移
通过touch:drag事件实现单指平移,逻辑与PC端平移一致,计算触摸位移来更新视口变换参数:
canvas.on('touch:drag', function(e) { var pointer = canvas.getPointer(e.e); if (!canvas.isDragging) { canvas.isDragging = true; canvas.selection = false; canvas.lastPosX = pointer.x; canvas.lastPosY = pointer.y; } else { var vpt = canvas.viewportTransform; vpt[4] += pointer.x - canvas.lastPosX; vpt[5] += pointer.y - canvas.lastPosY; canvas.requestRenderAll(); canvas.lastPosX = pointer.x; canvas.lastPosY = pointer.y; } e.e.preventDefault(); e.e.stopPropagation(); }); canvas.on('touch:up', function() { canvas.setViewportTransform(canvas.viewportTransform); canvas.isDragging = false; canvas.selection = true; });
修改后的完整代码
HTML
<div id="info"></div> <div id="canvasWrapper"> <canvas id="step1" width="400" height="400" style="border: solid gray thin;"></canvas> </div>
JavaScript
var canvas = new fabric.Canvas('step1'); canvas.add(new fabric.Rect({ width: 50, height: 50, fill: 'blue', angle: 10 })) canvas.add(new fabric.Circle({ radius: 50, fill: 'red', top: 44, left: 80 })) canvas.add(new fabric.Ellipse({ rx: 50, ry: 10, fill: 'yellow', top: 80, left: 35 })) canvas.add(new fabric.Rect({ width: 50, height: 50, fill: 'purple', angle: -19, top: 70, left: 70 })) canvas.add(new fabric.Circle({ radius: 50, fill: 'green', top: 110, left: 30 })) canvas.add(new fabric.Ellipse({ rx: 50, ry: 10, fill: 'orange', top: 12, left: 100, angle: 30 })) // 电脑端滚轮缩放 canvas.on('mouse:wheel', function(opt) { var delta = opt.e.deltaY; var zoom = canvas.getZoom(); zoom *= 0.999 ** delta; if (zoom > 20) zoom = 20; if (zoom < 0.01) zoom = 0.01; canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom); opt.e.preventDefault(); opt.e.stopPropagation(); }); // 电脑端Alt+左键平移 canvas.on('mouse:down', function(opt) { var evt = opt.e; if (evt.altKey === true) { this.isDragging = true; this.selection = false; this.lastPosX = evt.clientX; this.lastPosY = evt.clientY; } }); canvas.on('mouse:move', function(opt) { if (this.isDragging) { var e = opt.e; var vpt = this.viewportTransform; vpt[4] += e.clientX - this.lastPosX; vpt[5] += e.clientY - this.lastPosY; this.requestRenderAll(); this.lastPosX = e.clientX; this.lastPosY = e.clientY; } }); canvas.on('mouse:up', function(opt) { this.setViewportTransform(this.viewportTransform); this.isDragging = false; this.selection = true; }); // 移动端双指缩放 canvas.on('touch:gesture', function(e) { if (e.scale && e.scale !== 1) { var currentZoom = canvas.getZoom(); var newZoom = currentZoom * e.scale; newZoom = Math.max(0.01, Math.min(20, newZoom)); var centerPoint = { x: e.center.x, y: e.center.y }; canvas.zoomToPoint(centerPoint, newZoom); e.e.preventDefault(); e.e.stopPropagation(); } }); // 移动端单指平移 canvas.on('touch:drag', function(e) { var pointer = canvas.getPointer(e.e); if (!canvas.isDragging) { canvas.isDragging = true; canvas.selection = false; canvas.lastPosX = pointer.x; canvas.lastPosY = pointer.y; } else { var vpt = canvas.viewportTransform; vpt[4] += pointer.x - canvas.lastPosX; vpt[5] += pointer.y - canvas.lastPosY; canvas.requestRenderAll(); canvas.lastPosX = pointer.x; canvas.lastPosY = pointer.y; } e.e.preventDefault(); e.e.stopPropagation(); }); canvas.on('touch:up', function() { canvas.setViewportTransform(canvas.viewportTransform); canvas.isDragging = false; canvas.selection = true; }); // 保留原触摸事件日志(可选) var info = document.getElementById('info'); canvas.on({ 'touch:orientation': function() { var text = document.createTextNode(' Orientation '); info.insertBefore(text, info.firstChild); }, 'touch:shake': function() { var text = document.createTextNode(' Shaking '); info.insertBefore(text, info.firstChild); }, 'touch:longpress': function() { var text = document.createTextNode(' Longpress '); info.insertBefore(text, info.firstChild); }, });
内容的提问来源于stack exchange,提问作者Adeeba
相关产品推荐
相关产品推荐

