首页 > 解决方案 > 使用 EaselJS 平移缩放行为

问题描述

我在使用 EaselJS 将平移/缩放行为与在画布上拖动移动一些形状的能力相结合时遇到了一些麻烦。

我希望只有在鼠标按下时才能移动形状,但如果我在舞台上按下鼠标(即不在形状上),那么我希望能够平移舞台。无论“缩放”级别(由鼠标滚轮更改)如何,此行为都需要保持一致。

我已阅读此内容:如何停止 easljs 中的事件泡沫?这表明无论我是点击了形状还是空白空间,舞台 mousedown 事件都会触发,因此最好创建一个“背景”形状来捕获不在“正确”形状上的 mousedown 事件。

这个小提琴是我设置它的方式:https ://jsfiddle.net/hmcleay/mzheuLbg/

var stage = new createjs.Stage("myCanvas");
console.log('stage.scaleX: ', stage.scaleX);
console.log('stage.scaleY: ', stage.scaleY);

function addCircle(r,x,y){
    var g=new createjs.Graphics().beginFill("#ff0000").drawCircle(0,0,r);
    var s=new createjs.Shape(g)
    s.x=x;
    s.y=y;

  s.on('pressmove',  function(ev) {
    var localpos = stage.globalToLocal(ev.stageX, ev.stageY)
    s.x = localpos.x;
    s.y = localpos.y;
    stage.update();
    });

    stage.addChild(s);
    stage.update();
}

// create a rectangle 'background' Shape object to cover the stage (to allow for capturing mouse drags on anything except other shapes). 
bg = new createjs.Shape();
bg.graphics.beginFill("LightGray").drawRect(10, 10, stage.canvas.width - 20, stage.canvas.height - 20); //deliberately smaller for debugging purposes (easier to see if it moves). 
bg.x = 0;
bg.y = 0;
stage.addChild(bg);
stage.update();


//create a rectangle frame to represent the position of the stage. 
stageborder = new createjs.Shape();
stageborder.graphics.beginStroke("Black").drawRect(0, 0, stage.canvas.width, stage.canvas.height);
stageborder.x = 0;
stageborder.y = 0;
stage.addChild(stageborder);
stage.update();


// MOUSEWHEEL ZOOM LISTENER - anywhere on canvas.
var factor
canvas.addEventListener("wheel", function(e){
    if(Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)))>0){
        factor = 1.1;
    } else {
        factor = 1/1.1;
  }

  var local = stage.globalToLocal(stage.mouseX, stage.mouseY);
  stage.regX=local.x;
  stage.regY=local.y;
    stage.x=stage.mouseX;
    stage.y=stage.mouseY;   

    stage.scaleX = stage.scaleX * factor;
    stage.scaleY = stage.scaleY * factor;

  //re-size the 'background' shape to be the same as the canvas size.
  bg.graphics.command.w = bg.graphics.command.w / factor;
  bg.graphics.command.h = bg.graphics.command.h / factor;

  // re-position the 'background' shape to it's original position of (0,0) in the global space.  
  var localzero = stage.globalToLocal(0, 0);

  bg.x = localzero.x;
  bg.y = localzero.y;

    stage.update();
});

// listener to add circles to the canvas. 
canvas.addEventListener('dblclick', function(){
var localpos = stage.globalToLocal(stage.mouseX, stage.mouseY);
    addCircle(10, localpos.x, localpos.y);
});

bg.addEventListener("mousedown", function(ev1){
  // purpose of this listener is to be able to capture drag events on the 'background' to pan the whole stage. 
  // it needs to be a separate 'shape' object (rather than the stage itself), so that it doesn't fire when other shape objects are drag-moved around on the stage. 

  // get the initial positions of the stage, background, and mousedown. 
  var mousedownPos0 = {'x': ev1.stageX, 'y': ev1.stageY};
  var stagePos0 = {'x': stage.x, 'y': stage.y};
  var bgPos0 = {'x': bg.x, 'y': bg.y};

  bg.addEventListener('pressmove', function(ev2){
    //logic is to pan the stage, which will automatically pan all of it's children (shapes). 
    // except we want the 'background' shape to stay where it is, so we need to offset it in the opposite direction to the stage movement so that it stays where it is. 
    stageDelta = {'x': ev2.stageX - mousedownPos0.x, 'y': ev2.stageY - mousedownPos0.y};

    //adjust the stage position
    stage.x = stagePos0.x + stageDelta.x;
    stage.y = stagePos0.y + stageDelta.y;

    // return the 'background' shape to global(0,0), so that it doesn't move with the stage. 
    var localzero = stage.globalToLocal(0,0);
    bg.x = localzero.x;
    bg.y = localzero.y;

    stage.update();


  });

});

灰色框是我的背景形状。我特意让它比画布小一点,这样我就可以看到它在哪里(对调试很有用)。双击画布上的任意位置以添加一些红色圆圈。如果你拖动一个圆圈,它只会移动那个圆圈。

如果在圆圈之间的灰色“背景”区域上拖动,它会移动整个舞台(以及因此属于舞台的所有子形状)。因为灰色的背景也是舞台的孩子,它想跟着它移动。所以我包含了一些代码来始终将灰色框返回到它开始的位置。黑色边框代表“舞台”的位置,我只是添加它以帮助可视化舞台的位置。

鼠标滚轮缩放控制是基于对这个问题的回答:EaselJS - 缩放图像上的破碎平移

与拖动平移类似,缩放时我必须调整灰色“背景”框的大小和位置,使其呈现在画布上的相同位置。但是,它并没有完全停留在我想要的位置……当我缩小时,它似乎爬向画布的左上角。我花了很长时间试图诊断这种行为,但无法找出它发生的原因。我怀疑这可能与舍入有关..但我真的不确定。

谁能解释为什么当我放大和缩小时我的灰色框没有保持静止?

另一种方法是废弃用于捕获不在“正确”形状上的鼠标按下事件的“背景”形状。相反,可能可以使用“舞台”mousedown 事件,但如果鼠标悬停在“形状”上,则阻止它移动舞台。这会是处理这种行为的更好方法吗?有什么建议可以防止它移动舞台吗?

在此先感谢,休。

标签: javascriptcanvascreatejseaseljs

解决方案


好的,

所以像往常一样,在最终寻求帮助之后,我设法解决了这个问题。

该问题是由于使背景形状(灰色矩形)比画布小 10px 引起的,以便我可以更清楚地看到它的位置(以帮助调试)。具有讽刺意味的是,这种抵消导致了这个问题。应用缩放时,10px 偏移量未转换为“本地”空间。通过使灰色矩形的图形位置在 (0,0) 处的宽度和高度等于画布的位置,问题就消失了!

希望这在某个时间点对某人有用。

干杯,休。


推荐阅读