Imagine we have this scenario. There are a very large stage 3000x3000 with many nodes inside. User wants to take a look into all nodes, but they are not visible at once.
Lets think you have a very large canvas and you want to add ability to navigate on it.
I will show your 4 different approaches to achieve that:
1. Just make large stage This is the simplest approach. But it is very slow, because large canvases are slow. User will be able to scroll with native scrollbars.
Pros:
Cons:
Show source code!
Canvas Scrolling Large view raw <!DOCTYPE html > <html > <head > <script src ="https://unpkg.com/konva@4.0.18/konva.min.js" > </script > <meta charset ="utf-8" /> <title > Konva Canvas Scrolling Demo</title > <style > body { margin: 0; padding: 0; overflow: hidden; background-color : #f0f0f0 ; height: 100%; overflow: auto; } </style > </head > <body > <div id ="container" > </div > <script > var WIDTH = 3000 ; var HEIGHT = 3000 ; var NUMBER = 200 ; var stage = new Konva.Stage({ container: 'container' , width: WIDTH, height: HEIGHT }); var layer = new Konva.Layer(); stage.add(layer); function generateNode () { return new Konva.Circle({ x: WIDTH * Math .random(), y: HEIGHT * Math .random(), radius: 50, fill: 'red' , stroke: 'black' }); } for (var i = 0 ; i < NUMBER; i++) { layer.add(generateNode()); } layer.draw(); </script > </body > </html >
2. Make stage draggable (navigate with drag&drop) That one is better because stage is much smaller.
Pros:
Simple implementation
Fast
Cons
Sometimes drag&drop navigation is not the best UX
Show source code!
Canvas Scrolling Drag view raw <!DOCTYPE html > <html > <head > <script src ="https://unpkg.com/konva@4.0.18/konva.min.js" > </script > <meta charset ="utf-8" /> <title > Konva Canvas Scrolling Drag Demo</title > <style > body { margin: 0; padding: 0; overflow: hidden; background-color : #f0f0f0 ; } </style > </head > <body > <div id ="container" > </div > <script > var width = window .innerWidth; var height = window .innerHeight; var stage = new Konva.Stage({ container: 'container' , width: width, height: height, draggable: true }); var layer = new Konva.Layer(); stage.add(layer); var WIDTH = 3000 ; var HEIGHT = 3000 ; var NUMBER = 200 ; function generateNode () { return new Konva.Circle({ x: WIDTH * Math .random(), y: HEIGHT * Math .random(), radius: 50, fill: 'red' , stroke: 'black' }); } for (var i = 0 ; i < NUMBER; i++) { layer.add(generateNode()); } layer.draw(); </script > </body > </html >
You will have to draw them manually and implement all moving functionality. That is quite a lot of work. But works good for many apps.
Instruction: try to scroll with bars.
Pros:
Works ok
Intuitive scroll
Fast
Cons
Scrollbars are not native, so you have to implement many things manually (like scroll with keyboard)
Show source code!
Canvas Scrolling Bars view raw <!DOCTYPE html > <html > <head > <script src ="https://unpkg.com/konva@4.0.18/konva.min.js" > </script > <meta charset ="utf-8" /> <title > Konva Canvas Scrolling Drag Demo</title > <style > body { margin: 0; padding: 0; overflow: hidden; background-color : #f0f0f0 ; } </style > </head > <body > <div id ="container" > </div > <script > var width = window .innerWidth; var height = window .innerHeight; var stage = new Konva.Stage({ container: 'container' , width: width, height: height }); var layer = new Konva.Layer(); stage.add(layer); var WIDTH = 3000 ; var HEIGHT = 3000 ; var NUMBER = 200 ; function generateNode () { return new Konva.Circle({ x: WIDTH * Math .random(), y: HEIGHT * Math .random(), radius: 50, fill: 'red' , stroke: 'black' }); } for (var i = 0 ; i < NUMBER; i++) { layer.add(generateNode()); } layer.draw(); var scrollLayers = new Konva.Layer(); stage.add(scrollLayers); const PADDING = 5 ; var verticalBar = new Konva.Rect({ width: 10, height: 100, fill: 'grey' , opacity: 0.8, x: stage.width() - PADDING - 10, y: PADDING, draggable: true , dragBoundFunc: function (pos) { pos.x = stage.width() - PADDING - 10; pos.y = Math .max( Math .min(pos.y, stage.height() - this .height() - PADDING), PADDING ); return pos; } }); scrollLayers.add(verticalBar); scrollLayers.draw(); verticalBar.on('dragmove' , function () { const availableHeight = stage.height() - PADDING * 2 - verticalBar.height(); var delta = (verticalBar.y() - PADDING) / availableHeight; layer.y(-stage.height() * delta); layer.batchDraw(); }); var horizontalBar = new Konva.Rect({ width: 100, height: 10, fill: 'grey' , opacity: 0.8, x: PADDING, y: stage.height() - PADDING - 10, draggable: true , dragBoundFunc: function (pos) { pos.x = Math .max( Math .min(pos.x, stage.width() - this .width() - PADDING), PADDING ); pos.y = stage.height() - PADDING - 10; return pos; } }); scrollLayers.add(horizontalBar); scrollLayers.draw(); horizontalBar.on('dragmove' , function () { const availableWidth = stage.width() - PADDING * 2 - horizontalBar.width(); var delta = (horizontalBar.x() - PADDING) / availableWidth; layer.x(-stage.width() * delta); layer.batchDraw(); }); </script > </body > </html >
That demo works really good, but it may be tricky. The idea is:
We will use small canvas with the size of the screen
We will create container with required size (3000x3000), so native scrollbars will be visible
When user is trying to scroll, we will apply css transform for the stage container so it will be still in the center of user’s screen
We will move all nodes so it looks like you scroll (by changing stage position)
Props:
Works perfect and fast
Native scrolling
Cons:
You have to understand what is going on.
Instruction: try to scroll with native bars.
Show source code!
Canvas Scrolling Transform view raw <!DOCTYPE html > <html > <head > <script src ="https://unpkg.com/konva@4.0.18/konva.min.js" > </script > <meta charset ="utf-8" /> <title > Konva Canvas Scrolling Demo</title > <style > body { margin: 0; padding: 0; overflow: hidden; background-color : #f0f0f0 ; height: 100%; overflow: auto; } #large-container { width: 3000px; height: 3000px; overflow: hidden; } #scroll-container { width: calc(100% - 22px); height: calc(100vh - 22px); overflow: auto; margin: 10px; border: 1px solid grey; } </style > </head > <body > <div id ="scroll-container" > <div id ="large-container" > <div id ="container" > </div > </div > </div > <script > var WIDTH = 3000 ; var HEIGHT = 3000 ; var NUMBER = 200 ; var PADDING = 500 ; var stage = new Konva.Stage({ container: 'container' , width: window .innerWidth + PADDING * 2 , height: window .innerHeight + PADDING * 2 }); var layer = new Konva.Layer(); stage.add(layer); function generateNode () { return new Konva.Circle({ x: WIDTH * Math .random(), y: HEIGHT * Math .random(), radius: 50, fill: 'red' , stroke: 'black' }); } for (var i = 0 ; i < NUMBER; i++) { layer.add(generateNode()); } layer.draw(); var scrollContainer = document .getElementById('scroll-container' ); function repositionStage () { var dx = scrollContainer.scrollLeft - PADDING; var dy = scrollContainer.scrollTop - PADDING; stage.container().style.transform = 'translate(' + dx + 'px, ' + dy + 'px)' ; stage.x(-dx); stage.y(-dy); stage.batchDraw(); } scrollContainer.addEventListener('scroll' , repositionStage); repositionStage(); </script > </body > </html >