Kinetic.js: Prevent draggable stage from abroad

I am trying to make a Pan-and-zoom canvas for use as a minimap in the game. I created a drag and drop scene so that the player can move with the mouse, as well as move individual objects on the layers of the scene. However, I do not want to fit the scene into the surrounding empty space. In other words, I want to enable panning while zooming so you never encounter this gap. To try to hold back the scene, I set up dragBoundFunc:

dragBoundFunc: function(pos) { return { x: (pos.x < 0 ? 0 : pos.x > width ? width : pos.x), y: (pos.y < 0 ? 0 : pos.y > height ? height : pos.y) }; } 

(Full JSFiddle example: http://jsfiddle.net/4Brry/ )

I have two problems:

  • Firstly, the canvas can still move up and to the left.
  • Secondly, and more annoyingly, restrictions begin to behave badly when we begin to scale up. When scaling, limitations do not take this fact into account. So what if we add scene offsets?

      dragBoundFunc: function(pos) { return { x: ((ui.stage.getOffset().x+pos.x) < 0 ? 0 : pos.x > width ? width : pos.x), y: ((ui.stage.getOffset().y+pos.y) < 0 ? 0 : pos.y > height ? height : pos.y) }; } 

    (Full JSFiddle example: http://jsfiddle.net/2fLCd/ )

This is much better, but now the performance "leans back" when you go too far. It would be better if he simply stopped moving in a forbidden direction.

Does anyone know how I can fix these problems?

+4
source share
1 answer

Well, I turned on the Zynga Scroller functionality with the KineticJS framework to get what I wanted.

Code in action

Let the step take a look at the code, which is the union of the things that I found on the Internet and wrote myself.

First, we create the canvas using KineticJS:

 var width = 700; var height = 700; var stage = new Kinetic.Stage({ container: 'container', width: width, height: height }); var layer = new Kinetic.Layer({}); stage.add(layer); /* I skipped some circle generation code. */ 

Then we define some events that trigger when you drag something onto the layer. We will use them to populate a global variable called somethingIsBeingDraggedInKinetic . We will use this variable in the Zynga Scroller pan code so that the whole scene does not move when you drag the KineticJS form.

 var somethingIsBeingDraggedInKinetic = false; layer.on('dragstart', function(evt) { // get the thing that is being dragged var thing = evt.targetNode; if( thing ) somethingIsBeingDraggedInKinetic = true; }); layer.on('dragend', function(evt) { // get the thing that is being dragged var thing = evt.targetNode; if( thing ) somethingIsBeingDraggedInKinetic = false; }); 

Next is the Zynga Scroller initialization code. Zynga Scroller code processes input and transformation, and then passes three values ​​to the rendering function: top , left and zoom . These values ​​are ideal for moving to the KineticJS infrastructure:

 // Canvas renderer var render = function(left, top, zoom) { // Constrain the stage from going too far to the right if( (left + (width / zoom)) > width ) left = width - (width / zoom ); // Constrain the stage from going too far to the left if( (top + (height / zoom)) > height ) top = height - (height / zoom ); stage.setOffset(left, top); stage.setScale(zoom); stage.draw(); }; // Initialize Scroller this.scroller = new Scroller(render, { zooming: true, animating: false, bouncing: false, locking: false, minZoom: 1 }); 

After that, we need to properly place the Zynga Scroller. I admit that this part is a little black for me. I copied the rest of the code from the file "asset / ui.js".

 var container = document.getElementById("container"); var rect = container.getBoundingClientRect(); scroller.setPosition(rect.left + container.clientLeft, rect.top + container.clientTop); scroller.setDimensions(700, 700, width, height); 

Finally, I also copied the pan code and added code that checks that the KineticJS framework is moving something:

 var mousedown = false; container.addEventListener("mousedown", function(e) { if (e.target.tagName.match(/input|textarea|select/i)) { return; } scroller.doTouchStart([{ pageX: e.pageX, pageY: e.pageY }], e.timeStamp); mousedown = true; }, false); document.addEventListener("mousemove", function(e) { if (somethingIsBeingDraggedInKinetic) return; if (!mousedown) { return; } scroller.doTouchMove([{ pageX: e.pageX, pageY: e.pageY }], e.timeStamp); mousedown = true; }, false); document.addEventListener("mouseup", function(e) { if (!mousedown) { return; } scroller.doTouchEnd(e.timeStamp); mousedown = false; }, false); 

Oh and the scaling handler.

 container.addEventListener(navigator.userAgent.indexOf("Firefox") > -1 ? "DOMMouseScroll" : "mousewheel", function(e) { scroller.doMouseZoom(e.detail ? (e.detail * -120) : e.wheelDelta, e.timeStamp, e.pageX, e.pageY); }, false); 

This is perfect for a scalable map!

+1
source

Source: https://habr.com/ru/post/1479389/


All Articles