Fabricjs 平移和缩放
Posted
技术标签:
【中文标题】Fabricjs 平移和缩放【英文标题】:Fabricjs pan and zoom 【发布时间】:2015-08-08 14:04:10 【问题描述】:如何使用 fabricjs 进行平移和缩放?我试过使用 zoomToPoint 和 setZoom 方法,但它们不适用于平移。一旦我开始使用不同的缩放点,我就会遇到麻烦。
$('#zoomIn').click(function()
canvas.setZoom(canvas.getZoom() * 1.1 ) ;
) ;
$('#zoomOut').click(function()
canvas.setZoom(canvas.getZoom() / 1.1 ) ;
) ;
$('#goRight').click(function()
//Need to implement
) ;
$('#goLeft').click(function()
//Need to implement
) ;
http://jsfiddle.net/hdramos/ux16013L/
【问题讨论】:
你能详细说明一下吗?我在什么方面进行调整? 【参考方案1】:使用以下方法解决:
相对平移() 绝对平移()
[更新]
$('#goRight').click(function()
var units = 10 ;
var delta = new fabric.Point(units,0) ;
canvas.relativePan(delta) ;
) ;
$('#goLeft').click(function()
var units = 10 ;
var delta = new fabric.Point(-units,0) ;
canvas.relativePan(delta) ;
) ;
$('#goUp').click(function()
var units = 10 ;
var delta = new fabric.Point(0,-units) ;
canvas.relativePan(delta) ;
) ;
$('#goDown').click(function()
var units = 10 ;
var delta = new fabric.Point(0,units) ;
canvas.relativePan(delta) ;
);
http://jsfiddle.net/ux16013L/2/
【讨论】:
您能提供一些示例代码并更新您的 JSFiddle 吗?谢谢! 请我尝试做同样的事情! 请参阅更新。这就是我所拥有的。 假设如果您放大并向左或向右移动等然后缩小,那么您将以某个不是初始位置的位置结束!可以重置到初始位置吗?? 如何重置为实际画布?【参考方案2】:我知道它已经被回答了,但我不得不做一个鼠标平移,所以我调整了接受答案的小提琴来这样做。我把它贴在这里给任何必须做这样的事情的人。这只是主要思想:
var panning = false;
canvas.on('mouse:up', function (e)
panning = false;
);
canvas.on('mouse:down', function (e)
panning = true;
);
canvas.on('mouse:move', function (e)
if (panning && e && e.e)
var units = 10;
var delta = new fabric.Point(e.e.movementX, e.e.movementY);
canvas.relativePan(delta);
);
这里是小提琴:http://jsfiddle.net/gncabrera/hkee5L6d/5/
【讨论】:
这似乎在 IE 中不起作用。从外观上看,e.e.movementX 和 e.e.movementY 在fabric.js 的IE 版本中不存在。快速环顾四周,发现***.com/questions/40355425/…【参考方案3】:这是我的画布缩放(使用鼠标滚轮)和平移(使用左/上/右/下键或 shift 键 + 鼠标左下 + 鼠标移动)的解决方案。
https://jsfiddle.net/milanhlinak/7s4w0uLy/8/
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="lib/jquery-3.1.1.min.js"></script>
<script type="text/javascript" src="lib/fabric.min.js"></script>
</head>
<body>
<canvas id="canvas" style="border: 1px solid #cccccc"></canvas>
<script>
var Direction =
LEFT: 0,
UP: 1,
RIGHT: 2,
DOWN: 3
;
var zoomLevel = 0;
var zoomLevelMin = 0;
var zoomLevelMax = 3;
var shiftKeyDown = false;
var mouseDownPoint = null;
var canvas = new fabric.Canvas('canvas',
width: 500,
height: 500,
selectionKey: 'ctrlKey'
);
canvas.add(new fabric.Rect(
left: 100,
top: 100,
width: 50,
height: 50,
fill: '#faa'
));
canvas.add(new fabric.Rect(
left: 300,
top: 300,
width: 50,
height: 50,
fill: '#afa'
));
canvas.on('mouse:down', function (options)
var pointer = canvas.getPointer(options.e, true);
mouseDownPoint = new fabric.Point(pointer.x, pointer.y);
);
canvas.on('mouse:up', function (options)
mouseDownPoint = null;
);
canvas.on('mouse:move', function (options)
if (shiftKeyDown && mouseDownPoint)
var pointer = canvas.getPointer(options.e, true);
var mouseMovePoint = new fabric.Point(pointer.x, pointer.y);
canvas.relativePan(mouseMovePoint.subtract(mouseDownPoint));
mouseDownPoint = mouseMovePoint;
keepPositionInBounds(canvas);
);
fabric.util.addListener(document.body, 'keydown', function (options)
if (options.repeat)
return;
var key = options.which || options.keyCode; // key detection
if (key == 16) // handle Shift key
canvas.defaultCursor = 'move';
canvas.selection = false;
shiftKeyDown = true;
else if (key === 37) // handle Left key
move(Direction.LEFT);
else if (key === 38) // handle Up key
move(Direction.UP);
else if (key === 39) // handle Right key
move(Direction.RIGHT);
else if (key === 40) // handle Down key
move(Direction.DOWN);
);
fabric.util.addListener(document.body, 'keyup', function (options)
var key = options.which || options.keyCode; // key detection
if (key == 16) // handle Shift key
canvas.defaultCursor = 'default';
canvas.selection = true;
shiftKeyDown = false;
);
jQuery('.canvas-container').on('mousewheel', function (options)
var delta = options.originalEvent.wheelDelta;
if (delta != 0)
var pointer = canvas.getPointer(options.e, true);
var point = new fabric.Point(pointer.x, pointer.y);
if (delta > 0)
zoomIn(point);
else if (delta < 0)
zoomOut(point);
);
function move(direction)
switch (direction)
case Direction.LEFT:
canvas.relativePan(new fabric.Point(-10 * canvas.getZoom(), 0));
break;
case Direction.UP:
canvas.relativePan(new fabric.Point(0, -10 * canvas.getZoom()));
break;
case Direction.RIGHT:
canvas.relativePan(new fabric.Point(10 * canvas.getZoom(), 0));
break;
case Direction.DOWN:
canvas.relativePan(new fabric.Point(0, 10 * canvas.getZoom()));
break;
keepPositionInBounds(canvas);
function zoomIn(point)
if (zoomLevel < zoomLevelMax)
zoomLevel++;
canvas.zoomToPoint(point, Math.pow(2, zoomLevel));
keepPositionInBounds(canvas);
function zoomOut(point)
if (zoomLevel > zoomLevelMin)
zoomLevel--;
canvas.zoomToPoint(point, Math.pow(2, zoomLevel));
keepPositionInBounds(canvas);
function keepPositionInBounds()
var zoom = canvas.getZoom();
var xMin = (2 - zoom) * canvas.getWidth() / 2;
var xMax = zoom * canvas.getWidth() / 2;
var yMin = (2 - zoom) * canvas.getHeight() / 2;
var yMax = zoom * canvas.getHeight() / 2;
var point = new fabric.Point(canvas.getWidth() / 2, canvas.getHeight() / 2);
var center = fabric.util.transformPoint(point, canvas.viewportTransform);
var clampedCenterX = clamp(center.x, xMin, xMax);
var clampedCenterY = clamp(center.y, yMin, yMax);
var diffX = clampedCenterX - center.x;
var diffY = clampedCenterY - center.y;
if (diffX != 0 || diffY != 0)
canvas.relativePan(new fabric.Point(diffX, diffY));
function clamp(value, min, max)
return Math.max(min, Math.min(value, max));
</script>
</body>
</html>
【讨论】:
【参考方案4】:我在 Github 上有一个使用 fabric.js 画布平移和缩放的示例:https://sabatinomasala.github.io/fabric-clipping-demo/
负责平移行为的代码如下:https://github.com/SabatinoMasala/fabric-clipping-demo/blob/master/src/classes/Panning.js
这是fabric.Canvas.prototype
上的一个简单扩展,可让您在画布上切换“拖动模式”,如下所示:
canvas.toggleDragMode(true); // Start panning
canvas.toggleDragMode(false); // Stop panning
看看下面的 sn-p,整个代码都有文档。
const STATE_IDLE = 'idle';
const STATE_PANNING = 'panning';
fabric.Canvas.prototype.toggleDragMode = function(dragMode)
// Remember the previous X and Y coordinates for delta calculations
let lastClientX;
let lastClientY;
// Keep track of the state
let state = STATE_IDLE;
// We're entering dragmode
if (dragMode)
// Discard any active object
this.discardActiveObject();
// Set the cursor to 'move'
this.defaultCursor = 'move';
// Loop over all objects and disable events / selectable. We remember its value in a temp variable stored on each object
this.forEachObject(function(object)
object.prevEvented = object.evented;
object.prevSelectable = object.selectable;
object.evented = false;
object.selectable = false;
);
// Remove selection ability on the canvas
this.selection = false;
// When MouseUp fires, we set the state to idle
this.on('mouse:up', function(e)
state = STATE_IDLE;
);
// When MouseDown fires, we set the state to panning
this.on('mouse:down', (e) =>
state = STATE_PANNING;
lastClientX = e.e.clientX;
lastClientY = e.e.clientY;
);
// When the mouse moves, and we're panning (mouse down), we continue
this.on('mouse:move', (e) =>
if (state === STATE_PANNING && e && e.e)
// let delta = new fabric.Point(e.e.movementX, e.e.movementY); // No Safari support for movementX and movementY
// For cross-browser compatibility, I had to manually keep track of the delta
// Calculate deltas
let deltaX = 0;
let deltaY = 0;
if (lastClientX)
deltaX = e.e.clientX - lastClientX;
if (lastClientY)
deltaY = e.e.clientY - lastClientY;
// Update the last X and Y values
lastClientX = e.e.clientX;
lastClientY = e.e.clientY;
let delta = new fabric.Point(deltaX, deltaY);
this.relativePan(delta);
this.trigger('moved');
);
else
// When we exit dragmode, we restore the previous values on all objects
this.forEachObject(function(object)
object.evented = (object.prevEvented !== undefined) ? object.prevEvented : object.evented;
object.selectable = (object.prevSelectable !== undefined) ? object.prevSelectable : object.selectable;
);
// Reset the cursor
this.defaultCursor = 'default';
// Remove the event listeners
this.off('mouse:up');
this.off('mouse:down');
this.off('mouse:move');
// Restore selection ability on the canvas
this.selection = true;
;
// Create the canvas
let canvas = new fabric.Canvas('fabric')
canvas.backgroundColor = '#f1f1f1';
// Add a couple of rects
let rect = new fabric.Rect(
width: 100,
height: 100,
fill: '#f00'
);
canvas.add(rect)
rect = new fabric.Rect(
width: 200,
height: 200,
top: 200,
left: 200,
fill: '#f00'
);
canvas.add(rect)
// Handle dragmode change
let dragMode = false;
$('#dragmode').change(_ =>
dragMode = !dragMode;
canvas.toggleDragMode(dragMode);
);
<div>
<label for="dragmode">
Enable panning
<input type="checkbox" id="dragmode" name="dragmode" />
</label>
</div>
<canvas id="fabric"></canvas>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.15/fabric.min.js"></script>
【讨论】:
【参考方案5】:如果你只想在显示中平移画布,而不是改变元素的位置, 你可以使用this solution。
这个想法是有一个固定大小的容器,其 css 为overflow: hidden
,里面有一个扩展的画布。平底锅将在容器内移动画布,因此用户每次都会看到已用过的画布的不同区域。
【讨论】:
以上是关于Fabricjs 平移和缩放的主要内容,如果未能解决你的问题,请参考以下文章
canvas - 使用fabricjs和angularjs进行捏缩放
如何修复 FabricJS 中 Inkscape SVG 的缩放和旋转?