首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何用Fabric.js实现画布平移

如何用Fabric.js实现画布平移
EN

Stack Overflow用户
提问于 2015-12-22 20:18:30
回答 4查看 13.5K关注 0票数 19

我有一个Fabric.js画布,我想实现软件包通常使用“手工”工具进行的全画布平移。这是当你按下一个鼠标按钮,然后移动到画布上,同时按住鼠标按钮,画布的可见部分也相应地发生了变化。

你可以看到在这个视频里我想要达到的目标。

为了实现这个功能,我编写了以下代码:

代码语言:javascript
运行
复制
$(canvas.wrapperEl).on('mousemove', function(evt) {
    if (evt.button == 2) { // 2 is the right mouse button
        canvas.absolutePan({
            x: evt.clientX,
            y: evt.clientY
        });
    }
});

但不起作用。您可以看到在这个视频里发生了什么。

如何按照以下顺序修改代码:

  1. 像第一段视频那样工作吗?
  2. 事件处理程序是否需要使用该事件?当用户按下或释放鼠标右键时,应防止出现上下文菜单。
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-12-25 08:16:23

一种简单的方法是计算鼠标事件之间的光标位移,并将其传递给relativePan

观察如何使用上一个鼠标事件的screenXscreenY属性来计算当前鼠标事件的相对位置:

代码语言:javascript
运行
复制
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-cancelling函数本身。

右键单击菜单(也称为上下文菜单)将通过返回false取消.菜单取消功能也取消了自己。因此,如果您随后单击画布包装之外的内容,则上下文菜单将工作。

这里有一页演示了这种方法:

http://michaellaszlo.com/so/fabric-pan/

您将在织物画布上看到三个图像(加载图像可能需要一两分钟)。您将能够使用标准的织物功能。你可以左键点击图片来移动它们,拉伸它们,旋转它们。但是当您在画布容器内右键单击时,您可以用鼠标将整个织物帆布平移。

票数 17
EN

Stack Overflow用户

发布于 2017-10-21 09:52:01

我有一个使用fabric.js画布平移的Github示例:https://sabatinomasala.github.io/fabric-clipping-demo/

负责摇摄行为的代码如下:https://github.com/SabatinoMasala/fabric-clipping-demo/blob/master/src/classes/Panning.js

它是fabric.Canvas.prototype上的一个简单扩展,它允许您在画布上切换“拖动模式”,如下所示:

代码语言:javascript
运行
复制
canvas.toggleDragMode(true); // Start panning
canvas.toggleDragMode(false); // Stop panning

看看下面的片段,文档在整个代码中都是可用的。

代码语言:javascript
运行
复制
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);
});
代码语言:javascript
运行
复制
<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>

票数 5
EN

Stack Overflow用户

发布于 2015-12-26 12:55:40

我在jsfiddle上做了一个例子,我们实际上可以将整个画布和它的所有对象拖到父div中,就像图片一样,我将尝试一步一步地解释它。

  1. 首先我下载了拖动库jquery.dradscroll.js,你可以在网上找到它。这是一个很小的js文件,只要稍加修改,就可以帮助我们完成任务。下载链接:Code.htm
  2. 创建容纳我们画布的容器。
  3. 小css .content{溢出:auto;宽度:400;高度:400;}
  4. javascript: 创作画布。 使默认光标,当它超过画布时,张开手 canvas.defaultCursor = 'url(" http://maps.gstatic.com/intl/en_us/mapfiles/openhand_8_8.cur") 15 15, crosshair'; c.重写__onMouseDown函数,以更改关闭的游标(末尾)。 fabric.Canvas.prototype.__onMouseDown =函数(E){ //只接受左击变量isLeftClick =‘哪’?e.which === 1: e.button === 1;if (!isLeftClick && !fabric.isTouchSupported) {返回;} if (this.isDrawingMode) { this._onMouseDownInDrawingMode(e);} //忽略,如果此时正在转换某个对象,如果(this._currentTransform) {返回;} var ==== this.findTarget(e),指针= this.getPointer(e,true);//保存指针以检查__onMouseUp事件this._previousPointer =指针;var shouldRender =this._shouldRender(目标、指针),shouldGroup = this._shouldGroup(e,目标);if (this._shouldClearSelection(e,目标)){ this._clearSelection(e,目标,指针);} if (shouldGroup) { this._handleGrouping(e,目标);shouldGroup= this.getActiveGroup();} if (target & target.selectable &shouldGroup){ this._beforeTransform(e,target);this._setupCurrentTransform(e,target);} //我们必须将活动图像放置在顶层画布shouldRender & this.renderAll();this.fire(‘鼠标:向下’,{塔吉特:目标,e: e });塔吉特&target.fire(鼠标向下,{ e: e });如果(!canvas.getActiveObject()\x{canvas.getActiveGroup()){ flag=true;//将光标更改为closedhand.cur canvas.defaultCursor = 'url("8.cur“) 15,十字头发‘;}//如果
  5. 重写__onMouseUp事件,将光标更改为openhand。 fabric.Canvas.prototype.__onMouseUp =函数(E){if(标志){ canvas.defaultCursor = 'url(“8.cur“) 15,十字线‘;flag=false;};
  6. 初始化dragScroll()以处理承载画布的内容: $('.content').dragScroll({});
  7. 对jquery.dragScroll.js文件进行一些小的更改,以便了解何时拖动画布,何时不拖动。在mousedown()事件中,我们添加一个if语句来检查我们是否有一个活动对象或group.If真,没有画布拖放。 $($scrollArea).mousedown(函数(e) { if (canvas.getActiveObject()欧元/ canvas.getActiveGroup()) {console.log(‘无拖动’);}console.log{console.log(‘body’));( i++) { if ($(e.target).hasClass(options.limitToi)) { doMousedown(e);}}{ doMousedown(e);}};
  8. 鼠标向下的事件中,我们获取DOM元素(.content),并获取顶部和左侧位置 函数doMousedown(e) { e.preventDefault();down = true;x= e.pageX;y= e.pageY;top =doMousedown // .content left = e.target.parentElement.parentElement.scrollLeft;// .content }
  9. 如果我们不希望滚动条可见: .content{溢出:隐藏;宽度:400;高度:400; }
  10. 但是有一个小问题,jsfiddle只接受https库,所以它会阻塞编译is,除非您从'https://rawgit.com/kangax/fabric.js/master/dist/fabric.js‘中添加它,但是它仍然会阻塞它几次(至少在我的chrome和mozilla上)。

弹琴示例:https://jsfiddle.net/tornado1979/up48rxLs/

你可能比我更幸运,在你的浏览器,但它肯定会在你的现场应用程序工作。

不管怎样,我希望能帮上忙,祝你好运。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34423822

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档