How to delete a konva shape/image , when using node.destroy() - javascript

While using konva I am using a button to add a shape multiple times on to my Stage
using something similar to
document.getElementById('Rect').addEventListener( "click" , function () {
let layer = new Konva.Layer();
let item = new Konva.Rect({
x: 20,
y: 20,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 4,
draggable: true,
});
This appends a rectangle shape, if clicked multiple times it also appends extra shapes
I want to provide user with an option of deleting a particular shape that he wishes to delete with a button.
I tried to use context Menu tutorial available at Konva Tutorials but when implementing the delete function available there
document.getElementById('delete-button').addEventListener('click', () => {
currentShape.destroy();
layer.draw();
});
It is unable to delete the transformer layer added to the shape
document.getElementById('delete-button').addEventListener('click', () => {
tr.detach();
currentShape.destroy();
layer.draw();
});
I tried to detach the transformer / hide it but it removes it from all available instances of the shape
How can I solve this problem, Thanks a lot !!

You are adding a new click event listener for the "delete" button INSIDE click event of "add" button. That means every time you click on "delete" ALL listeners will be triggered. That removes all transformers.
Instead, you need just add a click listener once and find active Transformer manually to delete it.
document.getElementById('delete-button').addEventListener('click', () => {
const tr = layer.find('Transformer').toArray().find(tr => tr.nodes()[0] === currentShape);
tr.destroy();
currentShape.destroy();
layer.draw();
});
https://codepen.io/lavrton/pen/VweKqrp?editors=0010

Related

Event dispatching in Javascript [duplicate]

This question already has answers here:
How do I simulate a mouseover in pure JavaScript that activates the CSS ":hover"?
(6 answers)
Closed last year.
I'm trying to puzzle out the event dispatching in Javascript.
The example below uses Fabricjs library.
AS IS: if we mouseover the redBox, it becomes black.
TO BE: I'm trying to invoke the redBox mouseover event from greyBox mouseover event.
So if we mouseover the greyBox, it must work as if we mousever the redBox.
As a result the redBox must become black.
But I don't understand what to write instead of interrogation mark.
var greyBox = new fabric.Rect({
fill: 'grey',
width: 100,
height: 100
});
var redBox = new fabric.Rect({
left:300,
top:300,
fill: 'red',
width: 100,
height: 100
});
function createCanvas(id){
canvas = new fabric.Canvas(id);
canvas.add(greyBox);
canvas.add(redBox);
redBox.on("mouseover", function(e){
redBox.set({fill: 'black'});
})
greyBox.on("mouseover", function(e){
// ????
})
return canvas;
}
You could move the logic to a separate function and invoke it when necessary:
const makeRedBoxBlack = () => redBox.set({fill: 'black'});
redBox.on("mouseover", makeRedBoxBlack);
greyBox.on("mouseover", makeRedBoxBlack);
You only have to add that red box set statement, so it should something like :-
greyBox.on("mouseover", function(e){
redBox.set({fill: 'black'});
})

Can I bind a click event to the stage and a doubleclick to an element within it?

In Konva, I want to apply a click to the stage, but a doubleclick to a shape within the stage. Wondering what the best way to do this is.
Ultimately, wanted to create a floor plan where I can add tables (rectangles) to a map. If I click on the tables, Konva will allow me to add a rotation transformer. If I click outside the tables, the transformers on the stage disappear. I'm hoping that if I double click the tables, I can delete that shape. BUT - it doesn't appear I can both do a click on the stage, and check for a double click on an element within the stage. The code I have is the simplest example I know of to relate my ignorance about clicking and doubleclicking both on the stage and in an element on the stage.
//If you click on the stage, it creates the circle. And if you click on the circle, once created, I'm hoping it will be destroyed. It doesn't seem to like clicks and doubleclicks together in one area.
stage.on('click', function (e) {
var circle = new Konva.Circle({
x: 100,
y: 100,
fill: 'blue',
radius: 30,
draggable: true,
name: "circle"
});
layer.add(circle);
layer.draw();
});
circle.on('dblclick', function (e) {
this.destroy();
});
Wish I could delete the circle. The circle doesn't delete.
stage.on('click', function (e) {
const clickedOnEmptyArea = e.target === stage;
if (!clickedOnEmptyArea) {
return;
}
var circle = new Konva.Circle({
x: stage.getPointerPosition().x,
y: stage.getPointerPosition().y,
fill: 'blue',
radius: 30,
draggable: true,
name: "circle"
});
layer.add(circle);
layer.draw();
});
stage.on('dblclick', function (e) {
const clickedOnEmptyArea = e.target === stage;
if (clickedOnEmptyArea) {
return;
}
e.target.destroy();
layer.draw();
});
Demo: https://jsbin.com/hogahegame/edit?html,js,output

jointjs element mouse click event

I'm using jointjs to draw graphs.
I'm wondering how to listen to the mouse click event on an element?
I found on http://www.jointjs.com/api#joint.dia.Element, there is only change:position option but no onclick option lol.
There's only cell:pointerclick option on the whole paper instead of the single element.
How can I achieve only listen to mouse click element on the single element? (Say I want to resize the paper after the click)
Thanks!
You can use the pointerclick event to capture the click events on elements. The view is passed as a parameter to the function and you can obtain the model of the view through cellView.model
paper.on('cell:pointerclick', function (cellView) {
// your logic goes here
);
A way to do that it's using classes and javascript events, look:
First, you assign a class to the joint js element via markup , for example a class called 'myclass' in this case:
var rect1 = new joint.shapes.basic.Rect({
markup: '<g class="rotatable"><g class="scalable"><image id="myrect1" class="myclass"/></g><text/></g>',
size: { width: 30, height: 73.2 },
attrs: {
rect: { fill: bgcolor1,'stroke-width': 0 },
}
});
Then, you capture the click event on that class objects via javascript, not in the canvas but in the document :
$(document).on('click', '.myclass', function () {
//alert('yayy!');
});
Hope it helps !
you need to listen on view not on the model. Trace all caught events on the element:
var a = new joint.shapes.basic.Rect({
size: { width: 100, height: 100 },
position: { x: 300, y: 300 }
}).addTo(graph);
paper.findViewByModel(a).on('all', function() {
console.log(arguments);
});
https://jsfiddle.net/vtalas/0z6jyq70/

Leaflet clicking on features

So, I'm trying to map bus routes using leaflet w/geojson for the coordinates. I'm having a difficult time with one aspect where, on a click, the bus line is boldened, and, ideally, the last clicked on feature returns to the default style.
What I have so far
function $onEachFeature(feature, layer) {
layer.on({
click: function(e) {
//calls up the feature clicked on
var $layer = e.target;
var highlightStyle = {
opacity: 1,
weight: 5
};
$layer.bringToFront();
$layer.setStyle(highlightStyle);
}
});
}
//imagine all the leaflet map tile code here
//this is where the features get added in and the $oneachfeature function
var busFeature = L.geoJson(busRoutes, {
style: defaultBusRouteColor,
onEachFeature : $onEachFeature
});
busFeature.addTo(map);
Above, what I have now successfully changes the style of the feature to what's in highlightStyle. However, when another feature is clicked, the style remains. How do I remove the previously clicked on feature's style so that only one feature at a time has the style highlightStyle?
Things I've already tried: using addClass/removeClass to jQuery methods, layer.resetStyle() with leaflet, and a bunch of other things that still didn't work. Note: this would ideally be used in a mobile version, as the desktop version uses a hover function that emphasizes the features, with no problem. this:
function $oneachfeature(feature, layer){
layer.on({
mouseover: function (e){makes feature bold}
});
layer.on({
mouseout: function (e){makes feature normal again}
});
}
Any suggestions?
Store a reference to the highlighted layer so you can later call resetStyle on it:
// Variable to store selected
var selected
// Create new geojson layer
new L.GeoJSON(collection, {
// Set default style
'style': function () {
return {
'color': 'yellow',
}
}
}).on('click', function (e) {
// Check for selected
if (selected) {
// Reset selected to default style
e.target.resetStyle(selected)
}
// Assign new selected
selected = e.layer
// Bring selected to front
selected.bringToFront()
// Style selected
selected.setStyle({
'color': 'red'
})
}).addTo(map)
Example: http://embed.plnkr.co/RnQO1s/preview
Reference: http://leafletjs.com/reference.html#geojson-resetstyle
using resetStyle() would seem to be an easier solution...simply reset the style of the layer before applying the new style to the feature. This requires only a sinlge line of code adding to your original function:
function $onEachFeature(feature, layer) {
layer.on({
click: function(e) {
//calls up the feature clicked on
var $layer = e.target;
var highlightStyle = {
opacity: 1,
weight: 5
};
busFeature.resetStyle();
$layer.bringToFront();
$layer.setStyle(highlightStyle);
}
});
}
Remove previous Highlight before adding the next:
.removeLayer() works to remove the previously set geoJSON selection using .addTo()
theMap = yourMap.Map
geoJson = yourMap.geoJSON();
onclick() {
const highlightedFeature = {
'color': '#12FF38',
'fillColor': '#30D8E0',
'fillOpacity': 0.3
};
this.theMap.removeLayer(this.geoJson);
this.geoJson = yourMap.geoJSON( Feature, {
style: highlightedFeature
});
this.geoJson.addTo(this.theMap);
}

How do you make a highlighted outline appear in leaflet.js on mouseover and by hyperlink?

I need to make an outline appear around an object when the user mouses over the object in leaflet. Right now, I can make the object highlighted all the time or not at all. Here is a sample of my code:
var polygon1 = L.polygon([
[83.34425, -19.51172],
[83.2571, -15.86426],
[83.07408, -16.04004],
[82.78192, -17.31445],
[82.62569, -11.42578],
[82.36164, -11.29395],
[82.11236, -12.48047],
[82.37332, -22.71973],
[82.64822, -22.93945],
[83.34425, -19.51172]
], {
color: 'yellow',
opacity: 0.0,
fillColor: '#fff',
fillOpacity: 0.0
});
polygon1.bindLabel(popup_csb);
polygon1.bindPopup(content_csb);
polygon1.addTo(map);
I need to make an event for the object to be outlined in two circumstances.
When the mouseover takes place, to show the highlight as well as the popup label. The highlight would then go away when the mouse moves off the object.
When the user clicks on a link on the page (a list of buildings) and the object is outlined to show the user where the building is on the map.
The second case would also have to have a disable event when the user clicks another building.
Thanks very much for your help!
First you would need to have your default and highlight styles handy:
var style = {
'default': {
'color': 'yellow'
},
'highlight': {
'color': 'red'
}
};
Create some polygons and group them so they're easily accessible:
var group = new L.LayerGroup([
new L.Polygon([
[-50, -50], [50, -50], [50, -10], [-50, -10]
], {
'label': 'Polygon 1',
'popup': 'Polygon 1'
}),
new L.Polygon([
[-50, 10], [50, 10], [50, 50], [-50, 50]
], {
'label': 'Polygon 2',
'popup': 'Polygon 2'
})
]).addTo(map);
Create a variable to store the highlighted layer and function for setting and unsetting the highlight:
// Variable for storing highlighted layer
var highlight;
function setHighlight (layer) {
// Check if something's highlighted, if so unset highlight
if (highlight) {
unsetHighlight(highlight);
}
// Set highlight style on layer and store to variable
layer.setStyle(style.highlight);
highlight = layer;
}
function unsetHighlight (layer) {
// Set default style and clear variable
layer.setStyle(style.default);
highlight = null;
}
Iterate over layers, set style, bind label and popup and add handlers:
// Iterate
group.eachLayer(function (layer) {
// Set default style
layer.setStyle(style.default);
// Bind label with polygon option variable
layer.bindLabel(layer.options.label);
// Bind popup with polygon option variable
layer.bindPopup(layer.options.popup);
// Mouseover handler
layer.on('mouseover', function (e) {
// Set highlight
setHighlight(layer);
});
// Mouseout handler
layer.on('mouseout', function (e) {
// Unset highlight
unsetHighlight(layer);
});
// Fetch list from DOM
var list = L.DomUtil.get('list'),
// Add list item
item = L.DomUtil.create('li', 'item', list),
// Add link
link = L.DomUtil.create('a', 'link', item);
// Set link text
link.textContent = layer.options.label;
// Set link href
link.href = '#';
// Add clickhandler to link
L.DomEvent.addListener(link, 'click', function (e) {
// Set highlight
setHighlight(layer);
});
});
Example: http://plnkr.co/edit/LjzFbI?p=preview

Categories