Reputation: 3275
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
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