Interactive Scatter Plot with 20,000 Nodes

The purpose of this lab is to demonstrate she shear number of nodes that Konva can handle by rendering 20,000 circles which are sensitive to mouseover events and can be drag and dropped. This lab is also a great demonstration of event delegation, in which a single event handler attached to the stage handles the circle events.

Instructions: Mouse over the nodes to see more information and then drag and drop them around the stage.

Konva 20000 Nodes Demoview raw
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.rawgit.com/konvajs/konva/1.6.0/konva.min.js"></script>
<meta charset="utf-8">
<title>Konva Interactive Scatter Plot with 20,000 Nodes 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;
function addNode(obj, layer) {
var node = new Konva.Circle({
x: obj.x,
y: obj.y,
radius: 4,
fill: obj.color,
id: obj.id
});
layer.add(node);
}
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
var tooltipLayer = new Konva.Layer();
var dragLayer = new Konva.Layer();
var tooltip = new Konva.Label({
opacity: 0.75,
visible: false,
listening: false
});
tooltip.add(new Konva.Tag({
fill: 'black',
pointerDirection: 'down',
pointerWidth: 10,
pointerHeight: 10,
lineJoin: 'round',
shadowColor: 'black',
shadowBlur: 10,
shadowOffset: 10,
shadowOpacity: 0.2
}));
tooltip.add(new Konva.Text({
text: '',
fontFamily: 'Calibri',
fontSize: 18,
padding: 5,
fill: 'white'
}));
tooltipLayer.add(tooltip);
// build data
var data = [];
var colors = ['red', 'orange', 'cyan', 'green', 'blue', 'purple'];
for(var n = 0; n < 20000; n++) {
var x = Math.random() * width;
var y = height + (Math.random() * 200) - 100 + (height / width) * -1 * x;
data.push({
x: x,
y: y,
id: n,
color: colors[Math.round(Math.random() * 5)]
});
}
// render data
var nodeCount = 0;
var layer = new Konva.Layer();
for(var n = 0; n < data.length; n++) {
addNode(data[n], layer);
nodeCount++;
if(nodeCount >= 1000) {
nodeCount = 0;
stage.add(layer);
layer = new Konva.Layer();
}
}
stage.add(dragLayer);
stage.add(tooltipLayer);
stage.on('mouseover mousemove dragmove', function(evt) {
var node = evt.target;
if (node) {
// update tooltip
var mousePos = node.getStage().getPointerPosition();
tooltip.position({
x : mousePos.x,
y : mousePos.y - 5
});
tooltip.getText().setText("node: " + node.getId() + ", color: " + node.getFill());
tooltip.show();
tooltipLayer.batchDraw();
}
});
stage.on('mouseout', function(evt) {
tooltip.hide();
tooltipLayer.draw();
});
var startLayer;
stage.on('mousedown', function(evt) {
var shape = evt.target;
if (shape) {
startLayer = shape.getLayer();
shape.moveTo(dragLayer);
startLayer.draw();
// manually trigger drag and drop
shape.startDrag();
}
});
stage.on('mouseup', function(evt) {
var shape = evt.target;
if (shape) {
shape.moveTo(startLayer);
dragLayer.draw();
startLayer.draw();
}
});
</script>
</body>
</html>