About
In this post, we’ll take a look at the Konva.js.
Konva is a pretty nice 2D javascript graphics library for the browser. I discovered it when I needed a 2D library for a project at work. It supports both Vue and React frameworks. The reason a library is useful compared to just drawing objects on a canvas is that it provides you with an easy way to draw, style, find, manipulate and attach events to objects.
In the first example, we’ll learn how to draw a grid, add objects and snap those objects to the grid. In the second example, we’ll learn how to draw/move/delete lines, how to calculate the drawing angle and restrict it to 90 degrees.
Full code can be found here. Also, check out the official documentation as it has a lot of great code examples.
Note: The application architecture demonstrated here is not the best. If you want to make an app that utilizes konva consider organizing the project files and functions, classes, … differently than I did and define some data structure to store your state. These are just examples to demonstrate how to implement the features.
Item Snapping On A Grid:
index.html
<!DOCTYPE html>
<html>
<head>
<title>Konva.js Object Grid Snapping Demo</title>
</head>
<script src="code.js"></script>
<script src="konva.min.js"></script>
<style>
body{
font-family: Arial, Helvetica, sans-serif;
}
.toolBarItem{
width: 75px;
height: auto;
border: 1px solid black;
list-style: none;
text-align: center;
float: left;
padding: 2px;
}
#toolbar{
padding: 0px;
margin: 0px;
}
.row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
}
.column {
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 1;
}
</style>
<body>
<div>
<h1>Konva.js Object Grid Snapping Demo</h1>
<div>
<div class="row">
<ul id="toolbar">
<li class="toolBarItem">
<select id="backgroundSelection">
<option value="lines">Lines</option>
<option value="dottedLines">Dots</option>
<option value="none">None</option>
</select>
</li>
<li id="add" class="toolBarItem">Add Item</li>
</ul>
</div>
<div id="container" class="row"></div>
</div>
</div>
</body>
</html> code.js
//Global variables///////////////////////////////
let app;
/////////////////////////////////////////////////
//Main///////////////////////////////////////////
//Run this when the HTML gets loaded.
window.onload = () => {
let settings = {
containerSizeX: 1000,
containerSizeY: 700,
blockSnapSize: 20,
draggable: false //enable this if you want to be able to drag the canvas around.
};
//Make an instance of the app.
app = new KonvaDemoApp(settings);
}
/////////////////////////////////////////////////
//Code///////////////////////////////////////////
class KonvaDemoApp{
//Initialize///////////////////////////////////////
constructor(settings){
//Add settings.
this.settings = settings;
//No currently selected item.
this.selectedItem = null;
//Initialize container.
this.stage = this.makeContainer();
//Draw background grid. (stage ref., dots or lines, block snap size)
this.drawGrid("lines");
//Add the layer for the items.
let itemLayer = new Konva.Layer({id:"itemLayer"});
//Add the new layer.
this.stage.add(itemLayer);
//Register toolbar controls events.
this.registerControls();
}
//////////////////////////////////////////////////
//////////////////////////////////////////////////
makeContainer(){
return new Konva.Stage({
container: "container",
width: this.settings.containerSizeX,
height: this.settings.containerSizeY,
x:0,
y:0,
scaleX:1,
scaleY:1,
draggable: this.settings.draggable
});
}
drawGrid(gridType){
//Make a new layer for the grid.
let gridLayer = new Konva.Layer({id:"grid"});
const padding = this.settings.blockSnapSize;
//Grid size.
const height = this.stage.attrs.height*15;
const width = this.stage.attrs.width*15;
if(gridType == "dottedLines"){
//Draw dotted lines for background to improve performance vs drawing dots as individual objects.
for(var i = /*-(width / padding)*/0; i < width / padding; i++){
gridLayer.add(new Konva.Line({
points: [Math.round(i * padding) + 0.5, 0, Math.round(i * padding) + 0.5, height],
stroke: "#000",
strokeWidth: 3,
name: "backgroundLine",
lineCap: "round",
lineJoin: "round",
dash: [ 0, this.settings.blockSnapSize, 0, this.settings.blockSnapSize ]
}));
}
gridLayer.add(new Konva.Line({points: [0,0,10,10]}));
}
/*
//Draw dots as individual objects.
if(gridType == "dots"){
//Draw dots for backgrouond.
for(var i = 0; i < width1 / padding; i++){
for(var j = 0; j < height1 / padding; j++){
gridLayer.add(new Konva.Circle({
x: Math.round(i * padding),
y: Math.round(j * padding),
stroke: "#000",
strokeWidth: 0,
fill: "#000",
radius: 1,
name: "backgroundDot"
}));
}
}
}
*/
if(gridType == "lines"){
//Draw lines for backgrouond.
for(var i = 0; i < width / padding; i++){
gridLayer.add(new Konva.Line({
points: [Math.round(i * padding) + 0.5, 0, Math.round(i * padding) + 0.5, height],
stroke: "#000",
strokeWidth: 0.5,
name: "backgroundLine"
}));
}
gridLayer.add(new Konva.Line({points: [0,0,10,10]}));
for(var j = 0; j < height / padding; j++){
gridLayer.add(new Konva.Line({
points: [0, Math.round(j * padding), width, Math.round(j * padding)],
stroke: "#000",
strokeWidth: 0.5,
name: "backgroundLine"
}));
}
}
//Add layer to stage.
this.stage.add(gridLayer);
if(this.stage.find("Layer").length > 1) //Another layer must be present in stage to be able to use setZIndex().
gridLayer.setZIndex(0); //Will be above any lower numbered layers.
}
/////////////////////////////////////////////////
//Feature specific functions/////////////////////
addItem(x, y, width, height){
//Make the width/height fit(match) the grid.
width = this.settings.blockSnapSize * width;
height = this.settings.blockSnapSize * height
//Add a new rectangle.
let rectangle = this.newRectangle(0, 0, width, height);
//Add a snap location indicator rectangle for the new rectangle.
let snapLocationRectangle = this.newSnapLocationRectangle(x, y, width, height);
//Make item group.
let item = new Konva.Group({name: "itemGroup"});
item.add(rectangle);
item.add(snapLocationRectangle);
//Add snapLocationRectangle to a new layer.
this.stage.find("#itemLayer")[0].add(item);
}
newSnapLocationRectangle(x, y, width, height){
let snapRect = new Konva.Rect({
name: "snapLocationRectangle",
x: x,
y: y,
width: width,
height: height,
fill: "#26dd02",
opacity: 0.7,
stroke: "#168201",
strokeWidth: 4
});
//Keep the snap location rectangle hidden by default.
snapRect.hide();
return snapRect;
}
newRectangle(x, y, width, height) {
//Make new object.
let rectangle = new Konva.Rect({
x: x,
y: y,
width: width,
height: height,
fill: "#fff",
stroke: "#ddd",
strokeWidth: 1,
shadowColor: "black",
shadowBlur: 2,
shadowOffset: { x : 1, y : 1 },
shadowOpacity: 0.4,
draggable: true
});
//Events////////////////////////////////////////////
//When the object dragging starts show snap location, then move the object on top.
rectangle.on("dragstart", (event) => {
event.currentTarget.parent.find(".snapLocationRectangle").forEach((shape) => shape.show());
event.currentTarget.moveToTop();
this.stage.batchDraw();
});
//When moving stops snap item to grid and hide snap location item.
rectangle.on("dragend", (event) => {
event.currentTarget.position({
x: Math.round(rectangle.x() / this.settings.blockSnapSize) * this.settings.blockSnapSize,
y: Math.round(rectangle.y() / this.settings.blockSnapSize) * this.settings.blockSnapSize
});
this.stage.batchDraw();
event.currentTarget.parent.find(".snapLocationRectangle").forEach((shape) => shape.hide());
});
//On move snap location indication rectangle.
rectangle.on("dragmove", (event) => {
event.currentTarget.parent.find(".snapLocationRectangle").forEach((shape) => shape.position({
x: Math.round(rectangle.x() / this.settings.blockSnapSize) * this.settings.blockSnapSize,
y: Math.round(rectangle.y() / this.settings.blockSnapSize) * this.settings.blockSnapSize
}));
this.stage.batchDraw();
});
//On item click set it as the selected item.
rectangle.on("click", (event) => {
this.selectedItem = rectangle;
});
///////////////////////////////////////////////////////
return rectangle;
}
/////////////////////////////////////////////////
//Events/////////////////////////////////////////
registerControls(){
//Grid selection.
document.getElementById("backgroundSelection").addEventListener("change", (event) => {
//Clear current grid.
this.stage.find("#grid")[0].destroy();
//Draw grid with lines.
this.drawGrid(event.target.value);
//Redraw stage.
this.stage.draw();
});
//Delete selected item.
document.addEventListener('keydown', (event) => {
if(event.keyCode == 46){
this.selectedItem.destroy();
this.selectedItem = null;
this.stage.batchDraw();
}
});
//Add item.
document.getElementById("add").addEventListener("click", (event) => {
//Add item.
this.addItem(0, 0, 6, 3);
//Redraw stage.
this.stage.draw();
});
}
/////////////////////////////////////////////////
} Drawing Lines:
index.html
<!DOCTYPE html>
<html>
<head>
<title>Konva.js Drawing Lines Demo</title>
</head>
<script src="code.js"></script>
<script src="konva.min.js"></script>
<style>
body{
font-family: Arial, Helvetica, sans-serif;
}
.toolBarItem{
width: 120px;
height: auto;
border: 1px solid black;
list-style: none;
text-align: center;
float: left;
padding: 2px;
}
#toolbar{
padding: 0px;
margin: 0px;
}
.row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
}
.column {
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 1;
}
</style>
<body>
<div>
<h1>Konva.js Drawing Lines Demo</h1>
<div>
<div class="row">
<ul id="toolbar">
<li class="toolBarItem">
<select id="backgroundSelection">
<option value="lines">Lines</option>
<option value="dottedLines">Dots</option>
<option value="none">None</option>
</select>
</li>
<li class="toolBarItem"><label>Angle Snap</label><input type="checkbox" onchange="angleSnapping(event)" /></li>
<li class="toolBarItem"><label>Draw</label><input id="drawLine" checked="checked" name="tool" type="radio" onchange="setTool(event)" /></li>
<li class="toolBarItem" style="width: 150px;"><label>Delete</label><input id="delete" name="tool"name="tool" type="radio" onchange="setTool(event)" /></li>
<li class="toolBarItem" style="width: 150px;"><label>Move</label><input id="move" name="tool" type="radio" onchange="setTool(event)" /></li>
</ul>
</div>
<div id="container" class="row"></div>
</div>
</div>
</body>
</html> code.js
//Global variables///////////////////////////////
let app;
/////////////////////////////////////////////////
//Functions//////////////////////////////////////
function registerControls(){
//Grid selection.
document.getElementById("backgroundSelection").addEventListener("change", (event) => {
//Clear current grid.
app.stage.find("#grid")[0].destroy();
//Draw grid with lines.
app.drawGrid(event.target.value);
//Redraw stage.
app.stage.draw();
});
}
function setTool(eventArgs){
app.action = eventArgs.target.id;
}
function angleSnapping(eventArgs){
app.angleSnapping = eventArgs.target.checked;
}
/////////////////////////////////////////////////
//Main///////////////////////////////////////////
//Run this when the HTML gets loaded.
window.onload = () => {
let settings = {
containerSizeX: 1000,
containerSizeY: 700,
blockSnapSize: 20,
draggable: false //enable this if you want to be able to drag the canvas around.
};
//Make an instance of the app.
app = new KonvaDemoApp(settings);
}
/////////////////////////////////////////////////
//Code///////////////////////////////////////////
class KonvaDemoApp{
//Initialize/////////////////////////////////////
constructor(settings){
//Add settings.
this.settings = settings;
//No currently selected item.
this.selectedItem = null;
//Initialize container.
this.stage = this.makeContainer();
this.action = "drawLine";
this.lineStatus = "start";
this.angleSnapping = false;
this.lineStartX = 0;
this.lineStartY = 0;
this.registerStageEvents(this.stage);
//Draw background grid. (stage ref., dots or lines, block snap size)
this.drawGrid("lines");
//Add the layer for the items.
let itemLayer = new Konva.Layer({id:"itemLayer"});
//Add the new layer.
this.stage.add(itemLayer);
//Register toolbar controls events.
registerControls();
}
/////////////////////////////////////////////////
/////////////////////////////////////////////////
makeContainer(){
return new Konva.Stage({
container: "container",
width: this.settings.containerSizeX,
height: this.settings.containerSizeY,
x:0,
y:0,
scaleX:1,
scaleY:1,
draggable: this.settings.draggable
});
}
drawGrid(gridType){
//Make a new layer for the grid.
let gridLayer = new Konva.Layer({id:"grid"});
const padding = this.settings.blockSnapSize;
//Grid size.
const height = this.stage.attrs.height*15;
const width = this.stage.attrs.width*15;
if(gridType == "dottedLines"){
//Draw dotted lines for background to improve performance vs drawing dots as individual objects.
for(var i = /*-(width / padding)*/0; i < width / padding; i++){
gridLayer.add(new Konva.Line({
points: [Math.round(i * padding) + 0.5, 0, Math.round(i * padding) + 0.5, height],
stroke: "#000",
strokeWidth: 3,
name: "backgroundLine",
lineCap: "round",
lineJoin: "round",
dash: [ 0, this.settings.blockSnapSize, 0, this.settings.blockSnapSize ]
}));
}
gridLayer.add(new Konva.Line({points: [0,0,10,10]}));
}
/*
//Draw dots as individual objects.
if(gridType == "dots"){
//Draw dots for backgrouond.
for(var i = 0; i < width1 / padding; i++){
for(var j = 0; j < height1 / padding; j++){
gridLayer.add(new Konva.Circle({
x: Math.round(i * padding),
y: Math.round(j * padding),
stroke: "#000",
strokeWidth: 0,
fill: "#000",
radius: 1,
name: "backgroundDot"
}));
}
}
}
*/
if(gridType == "lines"){
//Draw lines for backgrouond.
for(var i = 0; i < width / padding; i++){
gridLayer.add(new Konva.Line({
points: [Math.round(i * padding) + 0.5, 0, Math.round(i * padding) + 0.5, height],
stroke: "#000",
strokeWidth: 0.5,
name: "backgroundLine"
}));
}
gridLayer.add(new Konva.Line({points: [0,0,10,10]}));
for(var j = 0; j < height / padding; j++){
gridLayer.add(new Konva.Line({
points: [0, Math.round(j * padding), width, Math.round(j * padding)],
stroke: "#000",
strokeWidth: 0.5,
name: "backgroundLine"
}));
}
}
//Add layer to stage.
this.stage.add(gridLayer);
if(this.stage.find("Layer").length > 1) //Another layer must be present in stage to be able to use setZIndex().
gridLayer.setZIndex(0); //Will be above any lower numbered layers.
}
/////////////////////////////////////////////////
//Helper functions///////////////////////////////
getScaledPointerPosition(){
const pointerPosition = this.stage.getPointerPosition();
const stageAttrs = this.stage.attrs;
const x = (pointerPosition.x - stageAttrs.x) / stageAttrs.scaleX;
const y = (pointerPosition.y - stageAttrs.y) / stageAttrs.scaleY;
return {x: x, y: y};
}
snapToGrid(axis){
return Math.round(axis / this.settings.blockSnapSize) * this.settings.blockSnapSize;
}
angleBetweenPoints(p1, p2){
//Angle in radians.
//var angleRadians = Math.atan2(p2.y - p1.y, p2.x - p1.x);
//Angle in degrees.
let angleDeg = Math.atan2(p1.y - p2.y, p1.x - p2.x) * 180 / Math.PI;
//Make 360 degree from 180/-180 degree.
angleDeg = angleDeg + 180
//Mirror.
angleDeg = 360 - angleDeg;
return angleDeg;
}
snapToGridAngle(p1, p2){
let angle = this.angleBetweenPoints(p1, p2);
let angleSnappedX = p2.x;
let angleSnappedY = p2.y;
if(angle > 0 && angle < 90){
//1. quadrant
if(angle < 45){
angleSnappedX = p2.x;
angleSnappedY = p1.y;
}else{
angleSnappedX = p1.x;
angleSnappedY = p2.y;
}
}else if(angle > 90 && angle < 180){
//2. quadrant
if(angle < 135){
angleSnappedX = p1.x;
angleSnappedY = p2.y;
}else{
angleSnappedX = p2.x;
angleSnappedY = p1.y;
}
}else if(angle > 180 && angle < 270){
//3. quadrant
if(angle < 225){
angleSnappedX = p2.x;
angleSnappedY = p1.y;
}else{
angleSnappedX = p1.x;
angleSnappedY = p2.y;
}
}else if(angle > 270 && angle < 360){
//4. quadrant
if(angle < 315){
angleSnappedX = p1.x;
angleSnappedY = p2.y;
}else{
angleSnappedX = p2.x;
angleSnappedY = p1.y;
}
}
return { x: this.snapToGrid(angleSnappedX), y: this.snapToGrid(angleSnappedY)};
}
getLength(x1, y1, x2, y2){
const distance = Math.sqrt(Math.abs(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)));
return distance;
//return Math.round((distance/this.settings.blockSnapSize)*100);
}
MakeID(prefix){
let i = 0;
while(this.stage.find("#"+prefix+i)[0] != undefined && i < 1000){
if(i > 980)
console.log("Over " +i+ "of type " +prefix+ "in existance! This might start causing problems soon!");
i++;
}
return prefix+i;
}
/////////////////////////////////////////////////
//Event callback functions///////////////////////
adjustDisplayGroup(){
//Get current mouse position.
//pos = stage.getPointerPosition();
let pos = this.getScaledPointerPosition();
let pos1 = { x: this.snapToGrid(this.lineStartX), y: this.snapToGrid(this.lineStartY) };
let pos2 = { x: this.snapToGrid(pos.x), y: this.snapToGrid(pos.y) };
//Snap to angle.
if(app.angleSnapping)
pos2 = this.snapToGridAngle(pos1, pos2);
//Get array of points for line.
let p = [ this.snapToGrid(this.lineStartX), this.snapToGrid(this.lineStartY), pos2.x, pos2.y];
//Get length.
let length = this.getLength(this.snapToGrid(this.lineStartX), this.snapToGrid(this.lineStartY), pos.x, pos.y);
//Get angle.
const angle = this.angleBetweenPoints(pos1, pos2);
//Get length label.
let lengthLabel = this.stage.find("#displayLabel")[0];
//Update label text. BlockSnapSize is 20, lets say each square is 10mm, so divide by 2.
lengthLabel.text(Math.trunc(length/2) + "mm " +Math.trunc(angle) + " Deg.");
//Update label position.
lengthLabel.position({ x: pos2.x, y: pos2.y });
//Get display line label.
let displayLine = this.stage.find("#displayLine")[0];
//Update display line points.
displayLine.setPoints(p);
//Get item layer.
let layer = this.stage.find("#itemLayer")[0];
//Redraw layer.
layer.batchDraw();
}
drawLineDisplayGroup(){
//Get mouse position.
//pos = stage.getPointerPosition();
let pos = this.getScaledPointerPosition();
//Make temp display group.
let displayGroup = new Konva.Group({
/*draggable: true*/
id: "displayGroup"
});
//Make display line.
let displayLine = new Konva.Line({
points: [this.snapToGrid(pos.x), this.snapToGrid(pos.y)],
stroke: 'black',
tension: 1,
strokeWidth: 6,
draggable: false,
id: "displayLine"
});
displayGroup.add(displayLine);
//Make line start point displayCircle.
let displayCircleStart = new Konva.Circle({
x: this.snapToGrid(pos.x),
y: this.snapToGrid(pos.y),
radius: 7,
fill: '#34eb5b',
stroke: 'black',
strokeWidth: 2,
draggable: false,
name: "circle"
});
displayGroup.add(displayCircleStart);
let lengthLabel = new Konva.Text({
x: 0,
y: 0,
text: "",
fontSize: 20,
fontFamily: "Calibri",
fill: "green",
id: "displayLabel"
});
displayGroup.add(lengthLabel);
//Save line starting postions.
this.lineStartX = pos.x;
this.lineStartY = pos.y;
//Get main item layer.
let layer = this.stage.find("#itemLayer")[0];
//Add current display group to the layer.
layer.add(displayGroup);
//Redraw layer.
layer.draw();
//Change line status to being drawn.
this.lineStatus = "drawing";
}
addNewLine(){
//Get mouse position, adjusted for current scalling/zoom.
let pos = this.getScaledPointerPosition(); //stage.getPointerPosition(); //non adjusted mouse position.
let layer = this.stage.find("#itemLayer")[0];
//Snap starting position coordinates to grid.
let pos1 = { x: this.snapToGrid(this.lineStartX), y: this.snapToGrid(this.lineStartY) };
//Snap end position coordinates to grid.
let pos2 = { x: this.snapToGrid(pos.x), y: this.snapToGrid(pos.y) };
//Snap to angle.
if(app.angleSnapping)
pos2 = this.snapToGridAngle(pos1, pos2);
//Grid snap.
const p = [this.snapToGrid(this.lineStartX), this.snapToGrid(this.lineStartY), pos2.x, pos2.y];
//Get length.
let length = this.getLength(pos1.x, pos1.y, pos2.x, pos2.y);
//Make sure the line length spans at least one block.
if(length < this.settings.blockSnapSize){
this.stage.find("#displayGroup")[0].destroy();
layer.draw();
return;
}
//Line Group/////////////////////////////////////////////////////////////
//Make new group for the line and it's endpoint circles.
let group = new Konva.Group({
name: "lineGroup"
});
//Make line start point circle.
let circleStart = new Konva.Circle({
x: pos1.x,
y: pos1.y,
radius: 7,
fill: '#34eb5b',
stroke: 'black',
strokeWidth: 2,
draggable: true,
name: "circleStart"
});
//Make line end point circle.
let circleEnd = new Konva.Circle({
x: pos2.x,
y: pos2.y,
radius: 7,
fill: 'red',
stroke: 'black',
strokeWidth: 2,
draggable: true,
name: "circleEnd"
});
//Make drawn line.
let drawnLine = new Konva.Line({
points: p,
tension: 0,
fill: 'red',
stroke: 'black',
strokeWidth: 6,
draggable: false,
name: "drawLine",
id: this.MakeID("drawLine"),
length: length
});
/////////////////////////////////////////////////////////////////////////
//Add events.
circleStart.on('dragmove', this.adjustLineCirclePoint);
circleEnd.on('dragmove', this.adjustLineCirclePoint);
//Add to group.
group.add(drawnLine);
group.add(circleEnd);
group.add(circleStart);
//Event used to delete a line.
group.on("click", this.groupClicked);
//Add to layer.
layer.add(group);
//Put group on the bottom so line doesn't overlap existing line endpoint circle.
group.moveToBottom();
}
adjustLineCirclePoint(event){
if(app.action != "move")
return;
//Get mouse position, adjusted for current scalling/zoom.
let pos = app.getScaledPointerPosition(); //stage.getPointerPosition(); //non adjusted mouse position.
//Get Line from group.
let currentLine = event.target.parent.find('.drawLine')[0];
//Snap starting position coordinates to grid.
let pos1 = { x: currentLine.attrs.points[0], y: currentLine.attrs.points[1] };
if(event.target.attrs.name == "circleStart")
pos1 = { x: currentLine.attrs.points[2], y: currentLine.attrs.points[3] };
//Snap end position coordinates to grid.
let pos2 = { x: app.snapToGrid(pos.x), y: app.snapToGrid(pos.y) };
//Snap to angle.
if(app.angleSnapping)
pos2 = app.snapToGridAngle(pos1, pos2);
//Get length.
let length = app.getLength(pos1.x, pos1.y, pos2.x, pos2.y);
//Do nothing if set length is too short.
if(length < app.settings.blockSnapSize)
return;
//Set the targets x,y to new grid snaped mouse pointer position.
event.target.attrs.x = pos2.x;
event.target.attrs.y = pos2.y;
let points = [pos1.x, pos1.y, pos2.x, pos2.y]; //Make an array from circle start/end postiotns and assign the new position values array to the line(so that the line will be drawn between the two circles).
if(event.target.attrs.name == "circleStart")
points = [pos2.x, pos2.y, pos1.x, pos1.y]; //Make an array from circle start/end postiotns and assign the new position values array to the line(so that the line will be drawn between the two circles).
//Set the curently selected line points.
currentLine.setPoints(points);
//Get items layer.
let layer = app.stage.find("#itemLayer")[0];
//Redraw layer.
layer.batchDraw();
}
groupClicked(event){
if(app.action != "delete")
return
//Get parent layer clicked of item(so we can redraw it after).
let parentLayer = event.currentTarget.parent;
//Delete line group and all of its children.
event.currentTarget.destroy();
//Redraw layer.
parentLayer.draw();
}
/////////////////////////////////////////////////
//Events/////////////////////////////////////////
registerStageEvents(stage){
//Get container.
let container = stage.container();
container.addEventListener('mousedown', function(e) {
e.preventDefault();
if(app.action == "drawLine" && app.lineStatus == "start")
app.drawLineDisplayGroup(); //Draw temporary display group.
});
container.addEventListener('mouseup', function(e) {
e.preventDefault();
if(app.action == "drawLine" && app.lineStatus == "drawing"){
//Make final line.
app.addNewLine();
//Delete temp. display elements.
app.stage.find("#displayGroup")[0].destroy();
app.stage.find("#itemLayer")[0].draw();
//Reset line status back to default to enable drawing a new line.
app.lineStatus = "start";
}
});
container.addEventListener('mousemove', function(e) {
if(app.lineStatus == "drawing")
app.adjustDisplayGroup();
});
}
/////////////////////////////////////////////////
}






Last compatible Konva version is 7.2.5
Version 8.0.0 introduced breaking changed
Thanks for the comment. I updated the code.