我有一个Fabric.js画布,我想实现软件包通常使用“手动”工具进行的全画布平移。当你按下其中一个鼠标按钮,然后在按住鼠标按钮的同时在画布上移动,画布的可见部分也会相应地改变。
您可以看到in this video我想要实现的目标。
为了实现这个功能,我编写了以下代码:
deal_id
但它不起作用。你可以看到in this video会发生什么。
如何按顺序修改代码:
要像第一个视频一样进行平移工作吗?
让事件处理程序使用该事件?当用户按下或释放鼠标右键时,它应该阻止上下文菜单出现。
答案 0 :(得分:12)
平移Fabric画布以响应鼠标移动的一种简单方法是计算鼠标事件之间的光标位移并将其传递给relativePan
。
观察我们如何使用上一个鼠标事件的screenX
和screenY
属性来计算当前鼠标事件的相对位置:
function startPan(event) {
if (event.button != 2) {
return;
}
var x0 = event.screenX,
y0 = event.screenY;
function continuePan(event) {
var x = event.screenX,
y = event.screenY;
fc.relativePan({ x: x - x0, y: y - y0 });
x0 = x;
y0 = y;
}
function stopPan(event) {
$(window).off('mousemove', continuePan);
$(window).off('mouseup', stopPan);
};
$(window).mousemove(continuePan);
$(window).mouseup(stopPan);
$(window).contextmenu(cancelMenu);
};
function cancelMenu() {
$(window).off('contextmenu', cancelMenu);
return false;
}
$(canvasWrapper).mousedown(startPan);
我们开始在mousedown
上进行平移并继续在mousemove
上进行平移。在mouseup
,我们取消平移;我们也取消了mouseup
- 取消函数本身。
右键菜单(也称为上下文菜单)将通过返回false
取消。菜单取消功能也会取消。因此,如果您随后在画布包装器外部单击,则上下文菜单将起作用。
以下是展示此方法的页面:
http://michaellaszlo.com/so/fabric-pan/
您将在Fabric画布上看到三个图像(可能需要一两个时间才能加载图像)。您将能够使用标准Fabric功能。您可以左键单击图像以移动它们,拉伸它们并旋转它们。但是,当您在画布容器中右键单击时,可以使用鼠标平移整个Fabric画布。
答案 1 :(得分:2)
不确定FabricJS,但它可能是这样的:
让它像第一个视频一样工作:
通过使用CSS cursor
属性,使用javascript在mousedown
和mouseup
事件上切换它。
事件处理程序使用事件(当用户释放鼠标右键时,阻止上下文菜单出现):
使用javascript,我们会在false
事件
contextmenu
醇>
CODE: 有一点问题 (*)
使用jQuery JS Fiddle 1
$('#test').on('mousedown', function(e){
if (e.button == 2) {
// if right-click, set cursor shape to grabbing
$(this).css({'cursor':'grabbing'});
}
}).on('mouseup', function(){
// set cursor shape to default
$(this).css({'cursor':'default'});
}).on('contextmenu', function(){
//disable context menu on right click
return false;
});
使用原始javascript JS Fiddle 2
var test = document.getElementById('test');
test.addEventListener('mousedown', function(e){
if (e.button == 2) {
// if right-click, set cursor shape to grabbing
this.style.cursor = 'grabbing';
}
});
test.addEventListener('mouseup', function(){
// set cursor shape to default
this.style.cursor = 'default';
});
test.oncontextmenu = function(){
//disable context menu on right click
return false;
}

(*) 问题:
上面的代码段可以正常工作但是存在跨浏览器问题,如果你在Firefox中检查上面的小提琴 - 或Opera - 你会看到正确的行为,在Chrome和IE11中检查时 - 没有使用Edge或Safari检查 - 我发现Chrome和IE不支持grabbing
光标形状,所以在在上面的代码片段中,将光标线更改为:
jQuery:$(this).css({'cursor':'move'});
JS Fiddle 3
原始javascript:this.style.cursor = 'move';
JS Fiddle 4
现在我们有一个工作代码,但没有手形光标。但有以下解决方案: -
<强>解:强>
Chrome和Safari支持grab
和grabbing
的{{1}}前缀如下:
-webkit-
但你需要首先进行浏览器嗅探,如果Firefox是默认和标准代码,如果Chrome和Safari然后使用$(this).css({'cursor': '-webkit-grabbing'});
前缀,这仍然会使IE退出游戏。
查看this example,使用Chrome,Safari,Firefox,Opera和IE进行测试,您可以看到-webkit-
在所有浏览器中正常运行。
Chrome,Safari,Firefox和Opera显示黄色微笑图像cursor: url(foo.bar)
,但IE显示红色球状光标smiley.gif
。
或者这个:
您可以使用上述图片,url(myBall.cur)
或png
格式,除了支持gif
的IE以外的所有浏览器,因此您需要找到一种方法将其转换为.cur
。 Google搜索显示了convert image to cur
请注意 ,尽管这个.cur
- 的回退支持用逗号分隔,但在上面显示的W3Schools示例中效果很好,我无法在javascript中以相同的方式使用它,我尝试cursor:url(smiley.gif),url(myBall.cur),auto;
但它没有工作。
我也试过把它作为CSS类
$(this).css({'cursor': 'grabbing, move'});
然后使用jQuery .myCursor{ cursor: grabbing, -webkit-grabbing, move; }
但无效。
所以你仍然需要让浏览器嗅探你是否要进行第二个解决方案或两个解决方案的混合修复,this is my code我已经用了几次来检测浏览器并且它在这篇文章的时间,但你并不需要&#34; Mobile&#34;和&#34; Kindle&#34;部分。
$(this).addClass('myCursor');
&#13;
<强>资源:强>
答案 2 :(得分:2)
我在Github上有一个使用fabric.js Canvas平移的示例:https://sabatinomasala.github.io/fabric-clipping-demo/
负责平移行为的代码如下:https://github.com/SabatinoMasala/fabric-clipping-demo/blob/master/src/classes/Panning.js
它是fabric.Canvas.prototype
上的一个简单扩展程序,可让您切换“拖动模式”&#39;在画布上如下:
canvas.toggleDragMode(true); // Start panning
canvas.toggleDragMode(false); // Stop panning
请查看以下代码段,整个代码中都提供了文档。
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);
});
&#13;
<div>
<label for="dragmode">
Enable panning
<input type="checkbox" id="dragmode" name="dragmode" />
</label>
</div>
<canvas width="300" height="300" 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>
&#13;
答案 3 :(得分:1)
我在jsfiddle上做了一个例子,我们实际上可以将整个画布及其所有对象拖动到父div中,就像图片一样,我将尝试逐步解释它。
首先我下载了拖动库jquery.dradscroll.js,你可以在网上找到它。这是一个小的js文件,只需很少的更改就可以帮助我们完成任务。 下载链接:http://www.java2s.com/Open-Source/Javascript_Free_Code/jQuery_Scroll/Download_jquery_dragscroll_Free_Java_Code.htm
创建保存画布的容器。
<div class="content">
<canvas id="c" width="600" height="700" ></canvas>
</div>
小css
.content{
overflow:auto;
width:400px;
height:400px;
}
的javascript:
一个。创建画布。
湾制作默认光标,当它在画布上时,打开手
canvas.defaultCursor = 'url(" http://maps.gstatic.com/intl/en_us/mapfiles/openhand_8_8.cur") 15 15, crosshair';
℃。覆盖__onMouseDown函数,以更改 closedhand 光标(结束时)。
fabric.Canvas.prototype.__onMouseDown = function(e){
// accept only left clicks
var isLeftClick = 'which' in e ? e.which === 1 : e.button === 1;
if (!isLeftClick && !fabric.isTouchSupported) {
return;
}
if (this.isDrawingMode) {
this._onMouseDownInDrawingMode(e);
return;
}
// ignore if some object is being transformed at this moment
if (this._currentTransform) {
return;
}
var target = this.findTarget(e),
pointer = this.getPointer(e, true);
// save pointer for check in __onMouseUp event
this._previousPointer = pointer;
var shouldRender = this._shouldRender(target, pointer),
shouldGroup = this._shouldGroup(e, target);
if (this._shouldClearSelection(e, target)) {
this._clearSelection(e, target, pointer);
}
else if (shouldGroup) {
this._handleGrouping(e, target);
target = this.getActiveGroup();
}
if (target && target.selectable && !shouldGroup) {
this._beforeTransform(e, target);
this._setupCurrentTransform(e, target);
}
// we must renderAll so that active image is placed on the top canvas
shouldRender && this.renderAll();
this.fire('mouse:down', { target: target, e: e });
target && target.fire('mousedown', { e: e });
if(!canvas.getActiveObject() || !canvas.getActiveGroup()){
flag=true;
//change cursor to closedhand.cur
canvas.defaultCursor = 'url("http://maps.gstatic.com/intl/en_us/mapfiles/closedhand_8_8.cur") 15 15, crosshair';
}//end if
覆盖__onMouseUp事件,将光标更改为openhand。
fabric.Canvas.prototype.__onMouseUp = function(e){
if(flag){
canvas.defaultCursor = 'url(" http://maps.gstatic.com/intl/en_us/mapfiles/openhand_8_8.cur") 15 15, crosshair';
flag=false;
}
};
初始化dragScroll()以处理托管画布的内容:
$('.content').dragScroll({});
对jquery.dragScroll.js文件进行一些小的更改,以便了解何时拖动画布以及何时不。在mousedown()事件中,我们添加一个if语句来检查我们是否有一个活动对象或组。如果是,则不拖动画布。
$($scrollArea).mousedown(function (e) {
if (canvas.getActiveObject() || canvas.getActiveGroup()) {
console.log('no drag');return;
} else {
console.log($('body'));
if (typeof options.limitTo == "object") {
for (var i = 0; i < options.limitTo.length; i++) {
if ($(e.target).hasClass(options.limitTo[i])) {
doMousedown(e);
}
}
} else {
doMousedown(e);
}
}
});
在 mousedown 事件中,我们抓取DOM元素(.content)并获取 top&amp;左侧位置
function doMousedown(e) {
e.preventDefault();
down = true;
x = e.pageX;
y = e.pageY;
top = e.target.parentElement.parentElement.scrollTop; // .content
left = e.target.parentElement.parentElement.scrollLeft;// .content
}
如果我们不想让滚动条可见:
.content{
overflow:hidden;
width:400px;
height:400px;
}
但是有一个小问题,jsfiddle只接受https库,所以它会阻止fabricjs,除非你从&#39; https://rawgit.com/kangax/fabric.js/master/dist/fabric.js&#39;添加它,但它仍然会阻止它有时(至少在我的chrome和mozilla上)。
jsfiddle示例:https://jsfiddle.net/tornado1979/up48rxLs/
在您的浏览器上,您可能会比我更好运,但它确实可以在您的实时应用上运行。
反正 我希望有所帮助,祝你好运。