I'm using Paper.js and I need to do something on mouseup on a raster. However the event does not seem to fire when I use the global tool space.
Note this sketch, where clicking and dragging yields a log something like this:
raster mousedown
raster mousedrag
... [more "raster mousedrag"] ...
raster mousedrag
raster mouseup
indicating the raster.on('mouseup' function() {...}); was hit properly, as expected.
However, in this sketch, which contains functionality for displaying the dragged area, the raster.on('mouseup' function() {...}); is not hit properly. Note that the log does not contain "raster mouseup", only "raster mousedown" and "raster mousedrag".
Why in the second instance does mouseup not fire on the raster? How can I adjust the code in the second sketch so that it does fire?
Well, the simple answer is that the problem is that the on('mouseup', ...) handler is never called. The paper code gets the most recent hit, i.e., the red rectangle you're drawing, and checks to see if that responds to the 'mouseup' event. It doesn't. Then it checks the parent chain and the parent of the red rectangle is the layer, so it doesn't pass the .responds test either. Because the raster is at the same level as the red rectangle handlers associated with the raster are never called.
The simplest answer is to install the handlers on the view, not the raster, by using the global tool, e.g.,
function onMouseUp(event) {
console.log('vup');
}
See the paperjs code (in CanvasView.js):
function callEvent(view, type, event, point, target, lastPoint) {
var item = target,
mouseEvent;
function call(obj) {
if (obj.responds(type)) {
if (!mouseEvent) {
mouseEvent = new MouseEvent(type, event, point, target,
lastPoint ? point.subtract(lastPoint) : null);
}
if (obj.emit(type, mouseEvent) && mouseEvent.isStopped) {
event.preventDefault();
return true;
}
}
}
while (item) {
if (call(item))
return true;
item = item.getParent();
}
if (call(view))
return true;
return false;
}
Related
So, I've been trying to render some div instead of the context menu once the use user right-click anywhere on the page, and for this, I need to receive the coordinates of the click. Currently, I'm doing it like this
function printMousePos(event) {
let coordinates = [event.clientX, event.clientY];
//console.log(coordinates);
return coordinates;
}
document.addEventListener("click", printMousePos);
In the console, I got an array with x and y, but I can't work with them outside the function. I've been trying something like
let a = function (event){...}
but it doesn't seem to return the array in any case, so how could I refer to x and y? The problem is that those are dynamic and change only when the event occurs. Should I just render the menu inside of the printMousePos(event)
? Or is there any other way to get x and y?
EDIT
Thanks a lot for your answers, works for me now. I did the following - rendered the menu outside everything, hide it using CSS, and on click it changes class to visible and appears in the coordinates of the click. Goes something like
rendering the menu in window =>
rootNode.addEventListener('contextmenu', event => {
event.preventDefault();
//console.log('123');
menu.classList.add('active');
menu.style.top = `${event.clientY}px`;
menu.style.left = `${event.clientX}px`;
});
and it shows on click. So, no need to get the coordinates outside.
As Teemu said "You can't return anything from an event listener". And you don't need to.
You can either declare the coordinates array outside the event listener and fill it with data once the event fired OR (and I'd prefer that) write the function that is supposed to work with the coordinates and then call it inside the event listener (which is pretty much what you suggested yourself):
function handleClick(x,y) {
// do stuff with x and y here, like drawing a div...
}
document.addEventListener("click", function(event) {
handleClick(event.clientX, event.clientY);
});
I am registering the "click" event on the map to get the Lon and Lat of the mouse click like this:
map.events.register("click", map, function(e) {
var lonlat = map.getLonLatFromPixel(e.xy);
});
This works fine on my PC(click), but doesn't get triggered on my Android tablet(touch). So it gets triggered on click, but not on touch. I have to register the event to my layer to get it to trigger on touch(https://gis.stackexchange.com/q/20859) like this:
layer.events.register("touchstart", layer, function(e) {
//e.xy is undefined
});
This gets triggered, but for some reason event.xy is undefined?
How do I get the touch coordinates when using touch on a tablet?
It's not so easy to get the coordinates from the touchstart event.
Touchstart event comes with a touches array, each one containing some coordinates, but using different properties.
OpenLayers normalizes the touchstart event in the OpenLayers.Event class method getTouchClientXY.
Also, I can't find any click/touchstart event in the layer class. Maybe you are using some other subclass or a custom one...
However, depending on your needs, you could
create a drawfeature control, with a point handler and listen to the featureadded event
define a custom control that use the OpenLayers.Handler.Click (that handles click/touchstart correctly)
if you need to select a vector feature, use the SelectFeature control
Handle the "touchstart" event using a for loop to find xy coordinates in the touches property
I found a solution that works for me. This also triggers click event with touch:
OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, {
defaultHandlerOptions: {
'single': true,
'double': false,
'pixelTolerance': 0,
'stopSingle': false,
'stopDouble': false
},
initialize: function(options) {
this.handlerOptions = OpenLayers.Util.extend(
{}, this.defaultHandlerOptions
);
OpenLayers.Control.prototype.initialize.apply(
this, arguments
);
this.handler = new OpenLayers.Handler.Click(
this, {
'click': this.trigger
}, this.handlerOptions
);
},
trigger: function(e) {
var coordinates = map.getLonLatFromViewPortPx(e.xy);
}
});
var click = new OpenLayers.Control.Click();
map.addControl(click);
click.activate();
i use
e.clientX
instead of
e.x
or the touch.
Have a look in my code if you want In taphold.js
[http://ozonforages.free.fr/mobile.html]
I have two kinds of functions which will detect the mousedown event and trigger some functions.
window.onmousedown = function(...)
Raphael object:
var rec = paper.rect(10,10,10,10)
rec.mousedown(...)
the second one is a rectangle create by Raphael.js and the function will be triggered when you click the rectangle.
I need the second one to be triggered before the first one, but it seems that the order of triggering of the two functions is randomly decided by the browser?
Do I have any way to control it !?
thanks!!
I need the second one to be triggered before the first one
Look at the DEMO, mousedown even triggers on circle before window's.
window.onmousedown = function()
{
alert('Yes');
}
var paper = new Raphael(document.getElementById('paper'),500,400);
var circle = paper.circle(100,100,50).attr({fill:'orange', stroke:'green', 'stroke-width':3});
circle.mousedown(function() {
alert('No');
this.attr({fill:'green', stroke:'red', 'stroke-width':3});
});
circle.mouseout(function() {
this.attr({fill:'orange', stroke:'green', 'stroke-width':3});
});
Click on the circle and see that the alerts. Good luck
So far I have a circle with a marker.
http://jsfiddle.net/x5APH/1/
I would like to grab and drag the marker around the circle, however the current functionality only nudges the marker when you click it.
What changes can I make to the code so that the marker can be dragged around the circle while the mouse is held down?
Note
If you could update the fiddle with your solution I would greatly appreciate it.
changed some code
$(document).ready(function(){
$('#marker').on('mousedown', function(){
$('body').on('mousemove', function(event){
rotateAnnotationCropper($('#innerCircle').parent(), event.pageX,event.pageY, $('#marker'));
});
});
});
also add this code
$('body').on('mouseup', function(event){ $('body').unbind('mousemove')});
in the function
this is the jsfiddle http://jsfiddle.net/sandeeprajoria/x5APH/11/
To do anything of this sort:
On mousedown on the desired element, set:
mousemove event on the document to update the position of the target
mouseup event on the document to remove the mousemove and mouseup events you just set.
Example in plain JS:
elem.onmousedown = function() {
document.body.onmousemove = function(e) {
e = e || window.event;
// do stuff with e
};
document.body.onmouseup = function() {
document.body.onmousemove = document.body.onmouseup = null;
};
};
Personally I like to improve this further by creating a "mask" element over the whole page to capture events, so that (for example) dragging a selection or image does not trigger default browser actions (which are strangely immune to all event cancelling methods in this case...)
for the moment I have implemented different actions for when a person clicks on a canvas and when a person clicks and drags something. I did this by binding the mousedown event to my canvas and in that function there is made the difference between a drag or a mouseup. This works very good, but I have a problem when I also want to support doubleclicking on elements.
The normal way to implement this is like this:
$(canvas).click(function1);
$(canvas).dblclick(function2);
but I didn't implemented that way because I had to check whether or not the mouse moved (i.e. dragged). This is my current implementation:
var handler = {
clicked:function(e){
...
$(canvas).bind('mousemove', handler.dragged);
$(window).bind('mouseup', handler.dropped);
},
dragged:function(e){
...
},
dropped:function(e){
function loop(ctr){
if (ctr < 50) {
setTimeout(function(){loop(ctr+1)}, 2);
} else {
$(canvas).mousedown(handler.clicked);
handler.singleClick(e);
}
}
$(canvas).mousedown(handler.doubleclicked);
loop(0);
},
doubleClick: function(e){
...
},
singleClick: function(e){
...
}
}
$(canvas).mousedown(handler.clicked);
I tried to combine those two things (recognition of dragging and doubleclick) by implementing the dropped-function which waits for a period of time to listen for another click and if it didn't occur within that period it goes to the singleclick function. For the moment this not yet recognizes the second click.
I assume that there exist better ways to do this?
You might want to look at this:
http://threedubmedia.com/code/event/drag
It provides you with additional functionality .drag() in addition to .click() and .dblclick().
Theres also a drop version:
http://threedubmedia.com/code/event/drop