Konva drag drop without moving drag element - drag-and-drop

My question is how to drag and drop a shape, but with cloning the draggable shape, and dragging that clone to the droppable shape.
I am new to Konva. While looking around the documentation & examples I could find how to drag and drop a shape.
I found reference to cloning of the shape, but I am not sure how to do this.
If someone could show me the way that would be very much appreciated.
Thank you

rect.on('dragstart', function() {
// stop dragging original rect
rect.stopDrag();
// clone it
var clone = rect.clone({
x : 50,
y : 50
});
// events will also be cloned
// so we need to disable dragstart
clone.off('dragstart');
// then add to layer and start dragging new shape
layer.add(clone);
clone.startDrag();
});
http://jsbin.com/hujulasaro/1/edit?html,js,output
for drop events see demo: http://konvajs.github.io/docs/drag_and_drop/Drop_Events.html

Related

Can QML drag-and-drop mechanic work without drag item moving?

I have a listview and a rectangle on top of it. The ListView's delegates have DropAreas in them and the rectangle has drag enabled on Y axis with its relevant properties (hotspot, target).
When I move the rectangle up and down on the ListView, the DropAreas of the delegates are registering onEntered signals. Working as intended.
However, I am using SmoothedAnimation to scroll the list up and down when the rectangle is at the most top and bottom coordinates (list.y = 0 and list.height). So the rectangle is not moving, and the DropAreas of the list's delegates are moving under it. In that case, the onEntered is not registered because there is no dragging, the rectangle is completely still and although its hotspot is entering and leaving the DropAreas, there is no interaction.
This is because dragging mechanic is sending events all the time when moving and any DropAreas it comes inside can register the event. In my case there is no dragging and therefore no events.
Question: Can drag events be manually activated? Can I somehow simulate drag?
At first, you should change the drag.target: parent to drag.target: this. In this way instead of dragging the parent item, you drag only the mouseArea. After that, you should grab an image from the item that you want to drag. The code is here:
Rectangle {
id: rec
width: 100
height: 100
Drag.active: dragArea.drag.active
Drag.dragType: Drag.Automatic
Drag.supportedActions: Qt.CopyAction
MouseArea {
id: dragArea
anchors.fill: parent
drag.target: this
onPressed:{
parent.grabToImage(function(result) {
parent.Drag.imageSource = result.url
})
}
}
}
I have managed to induce drag events by manually changing the hotSpot property of the rectangle above the list. QML Drag documentation says:
Changes to hotSpot trigger a new drag move with the updated position.
So I have done this every time Listview contentY changes (vertical scrolling happens)
onContentYChanged:
{
rectangle.Drag.hotSpot.x += 0.0001
rectangle.Drag.hotSpot.x -= 0.0001
}
In hindsight, however, this is a 'hacky' solution. hotSpot property is a QPointF class property (link). This means it can be set using various methods (setX, setY, rx, ry..). For example, this:
rectangle.hotSpot += Qt.point(0,0)
or
rectangle.hotSpot = Qt.point(rectangle.hotSpot.x,rectangle.hotSpot.y)
should work in theory by resetting the hotSpot point when contentY changes, but testing revealed it unfortunately does not trigger a new drag move. (bug or intended, I don't know)
Now some of you that are more into Qt and QML might know more about this and how to properly adress the issue, but the above solution works for me and after testing everything I could imagine to get a cleaner solution, I settled on it.

Change dragging state for all markers

I'm using Leaflet.markercluster 1.0.1
I'm trying to add button on my map, so users can enter in 'edit mode'. On click on that button it should toggle dragging state for all markers. I don't really know how to implement that correctly, but I wrote that code
var drag = false;
$('#button').on('click', function () {
drag = !drag;
markers.eachLayer(function (marker) {
marker.options.draggable = drag;
if (marker.dragging) {
drag ? marker.dragging.enable() : marker.dragging.disable();
}
});
});
It works for some time, but then I get Exception on .enable()
Uncaught TypeError: Cannot read property 'classList' of null
Is anyone know any correct way to do that?
Thanks in advance!
It seems that the logic for the forEach method in MarkerClusterGroup iterates through markers not visible on the map after dragging a spiderified marker. Then the logic for enabling dragging fails, as the marker does not have an icon instance, because it has been removed from the map.
I've cleaned up the reproducible example a bit, and left a copy at https://playground-leaflet.rhcloud.com/qate/1/edit?html,output - I strongly suggest that you turn this into a good bug report in the Leaflet.MarkerCluster.
You may also check if each of the markers has a marker._map private property to check if they are on the map, and skip those which are not, but this may lead to other issues down the road.

KineticJS: Animate an item to go back to initial position when not dropped in drop target

I made an application which performs drag and drop of different items: images and shapes. I limited the drop target to a specific layer: rightLayer in my case using a simple test with if ... else. Everything works great, except that I want to make an item revert back to its original position in the leftLayer when it doesn't attempt the borders of rightLayer (just like jquery, but in kineticJS). Or just disappear instantly.
Here's a JSFIDDLE . For a better understanding, try this use case:
drag the rectangle,
drop it right before the grid,
click on an item from the left layer.
You can self-destruct any clone dropped other than in the dropzone with a test in dragend.
A Demo: http://jsfiddle.net/m1erickson/2T68g/
clone1.on("dragend",function(){
// destroy this clone if dropped outside the dropzone
if(this.x()<dropzone.x()){
this.destroy();
layer.draw();
}
});

Click-through markers and polylines in Leaflet

In Leaflet, is it possible to define a marker or polyline with {clickable:false}, so that a click is passed through to whatever lies beneath - be it the map or a clickable geometry object?
At the moment I solve this problem by making the marker/polyline clickable and passing the event onwards myself. But this leads to the mouse cursor always showing as the hand symbol. Ideally, the mouse cursor should look like the normal pointer or the hand, depending on whether what is beneath the marker/polyline is clickable.
This may not be the answer you are looking for, but you can use featureGroups to have all of your clickable polylines come to the front so that the actions are surfaced.
var lg_noclick = new L.FeatureGroup().addTo(map);
var lg_click = new L.FeatureGroup().addTo(map);
// Add lines
lg_click.bringToFront();
updated fiddle
Also if you can afford to know your lines before hand, correct ordering of when you add the lines it will work as well.
I know this is not ideal but it suited my situation just fine, so it might be good for you as well.
This hides the icon and brings it back after a second using mouseenter and mouseleave events:
$('.leaflet-marker-icon').mouseenter(function() {
$(this).hide();
});
$('.leaflet-marker-icon').mouseleave(function() {
$(this).delay(1000).show(0);
});

Highlight a possible drop target while dragging a shape/group in KineticJS

I am using KineticJS for implementing a graphical editor. I would like to drag a KineticJS Group and drop it into another shape. So far so good, done binding the "dropend" event to a handler in the group.
But I would like to change color to the potential destination shape while hovering on it during dragging, so as to give evidence that it is a suitable shape for drop.
I can't see a way of doing it and I am not been able to find any help in Kinetic documentation. How could I do?
Thanks,
eca
After some mumbling, I think I have found a solution:
var aShape = new Kinetic.Shape(...);
:
aShape.on("dragmove", function(evt) {
// Detect shapes under mouse position
var pos = aShape.getStage().getUserPosition(evt);
var collidingShapes = aShape.getStage().getIntersections(pos);
:
// If needed, filter out colliding shapes not suitable for drop
:
// Highlight drop target candidates, e.g. simulating a "mouseover"
for (var iTarget = 0; iTarget < collidingShapes.length; ++iTarget)
collidingShapes[iTarget].simulate("mouseover");
// If you need to remove highlighting, keep track of previously
// highlighted shapes and call simulate("mouseout") on those
// not currently in the candidates set.
});
Though what you did is actually working, I find it very slow. What I did, was to replace the line 3142 of kineticjs (v4.0.1):
else if(this.targetShape && !go.drag.moving)
with
else if (this.targetShape)
and it works like a charm. The mouseout and mouseover events are now fired.
Anyway, I don't know why, but there had been a property of the stage object (shapedragging or so) which pointed to a potential target, but it had been removed.