stwhite
stwhite

Reputation: 3275

Add Mouse Wheel Scrolling to Konva JS Stage with Anchor at beginning and end of outermost objects

I'm working on a project that allows mousewheel scrolling within a Konva JS canvas stage. The goal is to mimic traditional CSS overflow scrolling that can be done with DIVs. I believe the problem with what I'm doing has to do with scaling the stage.

To simplify this question I have created a demo that shows what happens when the stage is scaled. Ideally the bottom of the image would be anchored to the bottom of the stage, just like when scrolling to the bottom of this SO page or any website (once you've reached the bottom, it stops).

When you scroll the demo, you'll notice the image doesn't stop at the bottom of the stage, it keeps scrolling past.

var stageWidth = window.innerWidth;
var stageHeight = 300;
var viewportPadding = 10;
var stage = new Konva.Stage({
		x: 0,
		y: 0,
    container: 'container',
    width: stageWidth,
    height: stageHeight
});
var zoom = .5;
stage.scaleX(zoom);
stage.scaleY(zoom);
stage.draw();

var layer = new Konva.Layer();
var background = new Konva.Rect({
		x: 0,
		y: 0,
		fill: 'red',
    width: stageWidth,
    height: stageHeight,
});


var img = new Image();

img.onload = function() {
		var imageWidth = stageWidth - (viewportPadding * 2);
  	var ratio = imageWidth / this.naturalWidth;
  	var imageHeight = this.naturalHeight * ratio;
    var floorImage = new Konva.Image({
    		x: viewportPadding,
        y: viewportPadding,
        image: img,
        width: imageWidth,
        height: imageHeight,
    });
    layer.add(floorImage);
    
    // update height of background
    background.height(imageHeight + (viewportPadding * 2));
    stage.draw();
};

img.src = 'https://dspncdn.com/a1/media/originals/fa/06/eb/fa06ebac2b188e309cff600400d34e41.jpg';

layer.add(background);
stage.add(layer);
stage.draw();




stage.on('wheel', function(e) {
  var deltaX = e.evt.deltaX;
  var deltaY = e.evt.deltaY;
  var scrollStep = Math.abs(deltaY * 1);

  // Scrolling up
    if (deltaY < 0) {
      var yPos = layer.y() + scrollStep;

      if (yPos > 0) {
      	yPos = 0;
      }

      layer.y(yPos);
      layer.batchDraw();

  // Scrolling down
    } else if (deltaY > 0) {
      var yPos = layer.y() - scrollStep;
    	var remainingDistance = background.height() - stage.height();
    
      if (yPos < -remainingDistance) {
        yPos = -remainingDistance;
      }

      layer.y(yPos);
      layer.batchDraw();
    }
});
html,body {
  margin:0;
}

#container {
  border: 2px solid red;
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
<script src="https://unpkg.com/[email protected]/konva.min.js"></script>
  <title>JS Bin</title>
</head>
<body>
  <div id="container"></div>
</body>
</html>

Upvotes: 2

Views: 2147

Answers (1)

lavrton
lavrton

Reputation: 20288

You just need to adjust remaining scroll by the scale of the stage:

var remainingDistance = background.height() - stage.height() / stage.scaleY();

var stageWidth = window.innerWidth;
var stageHeight = 300;
var viewportPadding = 10;
var stage = new Konva.Stage({
		x: 0,
		y: 0,
    container: 'container',
    width: stageWidth,
    height: stageHeight
});
var zoom = 0.5;
stage.scaleX(zoom);
stage.scaleY(zoom);
stage.draw();

var layer = new Konva.Layer();
var background = new Konva.Rect({
		x: 0,
		y: 0,
		fill: 'red',
    width: stageWidth,
    height: stageHeight,
});


var img = new Image();

img.onload = function() {
		var imageWidth = stageWidth - (viewportPadding * 2);
  	var ratio = imageWidth / this.naturalWidth;
  	var imageHeight = this.naturalHeight * ratio;
    var floorImage = new Konva.Image({
    		x: viewportPadding,
        y: viewportPadding,
        image: img,
        width: imageWidth,
        height: imageHeight,
    });
    layer.add(floorImage);
    
    // update height of background
    background.height(imageHeight + (viewportPadding * 2));
    stage.draw();
};

img.src = 'https://dspncdn.com/a1/media/originals/fa/06/eb/fa06ebac2b188e309cff600400d34e41.jpg';

layer.add(background);
stage.add(layer);
stage.draw();




stage.on('wheel', function(e) {
  var deltaX = e.evt.deltaX;
  var deltaY = e.evt.deltaY;
  var scrollStep = Math.abs(deltaY * 1);

  // Scrolling up
    if (deltaY < 0) {
      var yPos = layer.y() + scrollStep;

      if (yPos > 0) {
      	yPos = 0;
      }

      layer.y(yPos);
      layer.batchDraw();

  // Scrolling down
    } else if (deltaY > 0) {
      var yPos = layer.y() - scrollStep;
    	var remainingDistance = background.height() - stage.height() / stage.scaleY();
    
      if (yPos < -remainingDistance) {
        yPos = -remainingDistance;
      }

      layer.y(yPos);
      layer.batchDraw();
    }
});
html,body {
  margin:0;
}

#container {
  border: 2px solid red;
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
<script src="https://unpkg.com/[email protected]/konva.min.js"></script>
  <title>JS Bin</title>
</head>
<body>
  <div id="container"></div>
</body>
</html>

Upvotes: 3

Related Questions