0

I am using KonvaJs in my project. I need to implement drag bound to Konva.Layer. My layer has so many other shapes and images. I need to restrict the movement of layer up to 50% of it's width and height. The way I have done in this plunkr. The problem arises when user zoom-in or zoom-out the layer using mouse wheel. After the zoom, I don't know why the drag bound is behaving differently. Seems like I am not able to do the Math correctly. I need to have the same behavior i.e. the way movement of layer is restricted when user does not perform zoom. This is what I am doing:

//... a helper object for zooming
var zoomHelper = {
    stage: null,
    scale: 1,
    zoomFactor: 1.1,
    origin: {
        x: 0,
        y: 0
    },
    zoom: function(event) {
        event.preventDefault();
        var delta;
        if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
            if (event.originalEvent.detail > 0) {
                //scroll down
                delta = 0.2;
            } else {
                //scroll up
                delta = 0;
            }
        } else {
            if (event.originalEvent.wheelDelta < 0) {
                //scroll down
                delta = 0.2;
            } else {
                //scroll up
                delta = 0;
            }
        }
        var evt = event.originalEvent,
            mx = evt.clientX - zoomHelper.stage.getX(),
            my = evt.clientY - zoomHelper.stage.getY(),
            zoom = (zoomHelper.zoomFactor - delta),
            newscale = zoomHelper.scale * zoom;
        zoomHelper.origin.x = mx / zoomHelper.scale + zoomHelper.origin
            .x - mx / newscale;
        zoomHelper.origin.y = my / zoomHelper.scale + zoomHelper.origin
            .y - my / newscale;
        zoomHelper.stage.setOffset({
            x: zoomHelper.origin.x,
            y: zoomHelper.origin.y
        });
        zoomHelper.stage.setScale({
            x: newscale,
            y: newscale
        });
        zoomHelper.stage.draw();
        zoomHelper.scale *= zoom;
        preCalculation();
    }
};


// Code goes here
var w = window.innerWidth;
var h = window.innerHeight;
var height, minX, minY, maxX, maxY;
var stage = new Konva.Stage({
  container: 'container',
  width: w,
  height: h
});
zoomHelper.stage =stage;
var layer = new Konva.Layer({
  draggable: true,
  dragBoundFunc: function(pos) {
    console.log('called');
    var X = pos.x;
    var Y = pos.y;
    if (X < minX) {
      X = minX;
    }
    if (X > maxX) {
      X = maxX;
    }
    if (Y < minY) {
      Y = minY;
    }
    if (Y > maxY) {
      Y = maxY;
    }
    return ({
      x: X,
      y: Y
    });
  }
});

stage.add(layer);

function preCalculation(){
  // pre-calc some bounds so dragBoundFunc has less calc's to do
height = layer.getHeight();
minX = stage.getX() - layer.getWidth() / 2;
maxX = stage.getX() + stage.getWidth() - layer.getWidth() / 2;
minY = stage.getY() - layer.getHeight() / 2;
maxY = stage.getY() + stage.getHeight() - layer.getHeight() / 2;
console.log(height, minX, minY, maxX, maxY);
}
preCalculation();

var img = new Image();
img.onload = function() {
  var floorImage = new Konva.Image({
    image: img,
    width: w,
    height: h
  });
  layer.add(floorImage);
  layer.draw();
};
img.src = 'https://s.yimg.com/pw/images/coverphoto02_h.jpg.v3';

$(stage.container).on('mousewheel DOMMouseScroll', zoomHelper.zoom);
Hitesh Kumar
  • 3,508
  • 7
  • 40
  • 71

1 Answers1

3

While using dragBoundFunc you have to return absolute position of layer. As you are changing attributes of top node (stage) it can be hard to maintain absolute position. So you can try to set bound function inside 'dragmove' event:

layer.on('dragmove', function() {
  var x = Math.max(minX, Math.min(maxX, layer.x()));
  var y = Math.max(minY, Math.min(maxY, layer.y()));
  layer.x(x);
  layer.y(y);
});

http://plnkr.co/edit/31MUmOjXBUVuaHVJsL3c?p=preview

lavrton
  • 18,973
  • 4
  • 30
  • 63
  • Thanks for the answer lavrton. You said that I should set bound function inside 'dragmove' like the way you did. That's fine I'll do it. But the challenge is that when zoom operation happens the area in which user can drag, is shrinking. I need to restrict the drag move to 50% of the width and height of layer. If the layer is scaled then the drag area should be scaled accordingly. – Hitesh Kumar Jan 28 '16 at 04:37
  • What do you mean 50% of height of layer? Is it 50% of stage? Or is it 50% of layer contents (image)? What height will be after scaling? – lavrton Jan 28 '16 at 06:22
  • The layer contents which is image and in my case height and width of stage and image are same. – Hitesh Kumar Jan 28 '16 at 06:57