Get coordinates out of click to work with - javascript

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);
});

Related

jQuery get the tager from event

I am using Hexagon.js and I need to get the .html() of the caller. If i do something like event.target and start moving with the slider, as long as the cursor is on the slider it works just fine, but if i move the cursor somewhere else (and still holding the slider, just like any other, dragging it with cursor and moving outisde of the slider box), I will get the data of that element I am currently hovering above. I need just the data of the caller, not form enyone else.
$(".slider").each(function() {
slider = new hx.Slider(this, {max:100});
slider.on('change', function(value){
var target = $( event.target );
console.log(target);
});
});
Thanks for any hep.
Without seeing the html it's a little bit hard to answer but well, according to docs you have to initialize the slider with an html element and, you do.
new hx.Slider(this, {max:100});
this in this line is the html element, so you could just use it.
Now the problem is that since you use function () {...} syntax, each function has its own this.
You may either use arrow function (they don't have their own this) as .on(...) callback (if it works ok, because sometimes it doesn't with JQuery) or save current this in a variable.
$(".slider").each(function(){
const slide = this;
const slider = new hx.Slider(
slide,
{max:100}
);
slider.on('change', function(value){
console.log(slide, `is html element!`);
console.log(value, `is the value that has just changed!`);
});
});

Customize dynamically created elements adding an option choosed via popup

I have a little code that creates elements (rectangles) and when I pass the mouse over them, a "customize yellow button appears on it". When I click this button, a popup with colors let us choose a colour to add in the selected rectangle.
Basically, I have 3 elements... click on 1 of them and choose a colour. This action, clones de tag and set it into the selected item. This works fine.
The problem appears when I click in the second item (or third)... I choose a new different colour but the action changes the selected rectangle and the sibling -applies to all elements that already have a cloned - (like propagation)...
I need to customize every single rectangle with its own colour and not all of them with the same. I pasted a little code here and a working (wrong) link in jsfiddle.
The action executes "on" cause the items are created dynamically (in this example I set them manually.
Can anybody help me? I don't understand what I'm doing wrong.
https://jsfiddle.net/martiniglesias/20Laxn84/2/
$(document).on("click","a.person",function (e)
{
e.preventDefault();
e.stopPropagation();
var elrel=$(this).attr('rel');
var elem=$("#ch_dndBoard1 span[data-id="+elrel+"]");
var elemrel=elem.attr("rel");
if (elemrel=="f1E")
{
$("body").append ("<div class='overlay'></div>").show();
$(".persE").fadeIn("fast");
$(".persE li").click(function(f)
{
f.preventDefault();
f.stopPropagation();
var ese=$(this).closest("li");
if ($(this).hasClass("nope"))
{
elem.find('b').fadeOut("slow",function() { elem.find('b').remove(); });
}
else
{
elem.find('b').remove();
var added=ese.find("b").clone();
added.css({"left":0+"px","top":+5.48+"px","position":"absolute"});
$(added).insertAfter(elem.find('em'));
}
$('.persE').fadeOut("fast",function(){ $(".overlay").remove(); });
});
}
return false;
});
I expect that every single rectangle can choose its own colour cloning it from the popup. For example, I want, rect1 blue, rect2 without color, rect3 red...
Thank you!
PS: Please, forgive my poor english :(
You have this issue because you are adding a click event listener to .persE li each time you click on a a.person.
You need to remove that listener when all your logic is over:
$(".persE li").click(function(f) {
// Your code
$(".persE li").off('click');
});
Be aware that if you listen an other click event with a different logic, that one will be destroyed too.
In order to avoid this, you need to reference your different logics in function:
const changeColorEvent = (e) => {
// Your code
$(this).off('click', changeColorEvent); // Here, "otherEvent" will still exist.
};
const otherEvent = (e) => {
// Different logic here
}
$(".persE li").click(changeColorEvent);
$(".persE li").click(otherEvent);

How to decide the triggering order of different mouseDown function

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

Stop propagation for a specific handler

Let's say I have custom dropdown(). When the button is clicked I want to bring up the menu, and when the user clicks outside of the menu I want it to close. So I do something like this:
$(myDropDown).mousedown(dropDownMouseDown);
$("html").mousedown(htmlMouseDown,myDropDown);
function dropDownMouseDown(event) {
event.target.open();
event.stopPropagation();//I need this line or else htmlMouseDown will be called immediately causing the dropDown-menu to close right before its opened
}
function htmlMouseDown() {
this.close();
}
Well, this works. But what if I add two of these? If I click to open the first, then the same on the second then both will be open because dropDownMouseDown stops the propagation so that htmlMouseDown never gets called for the first.
How do I get around this?
If I only had these two then adding some logic for that would of course be easy, but if the quantity is dynamic? Also I might not want to call event.stopPropagation() because it will do strange stuff to other libraries I'm using which listen for that event too?
I also tried putting this line:
$("html").mousedown(htmlMouseDown,myDropDown)
inside the dropDownMouseDown-handler but it will be called immediately anyway once the bubbling reaches the html-element.
Assuming you have a selector for your dropdows, (let's say ".dropdown"), I would try to use '.not()'
$('.dropdown').mousedown(dropDownMouseDown);
$("html").on('mousedown', htmlMouseDown);
function dropDownMouseDown(event) {
event.target.open();
}
function htmlMouseDown(event) {
$('.dropdown').not($(event.target)).close();
}
Here is a fiddle in the same idea with css classes :
http://jsfiddle.net/eFEL6/4/
What about using a variable that contains the last openened one ? There are probably many other ways of doing this, but here is a way I could think of:
var lastOpened = null; // initially nothing is open (unless something is)
Then:
function dropDownMouseDown(event) {
if (lastOpened != null) { // if one is still open
lastOpened.close(); // close it
lastOpened = null; // nothing is open anymore
}
event.target.open();
lastOpened = event.target; // now this one is open
event.stopPropagation();
}
function htmlMouseDown() {
this.close();
lastOpened = null; // nothing is open
}
That should work in a way that the last opened one always close itself before opening a new one.
Thanks for the answers. They're really appreciated. I did figure out a way of doing it that I'm satisfied with. Here's how:
$(myDropDown).mousedown(dropDownMouseDown);
$("html").mousedown(myDropDown,htmlMouseDown);//Pass in the dropDown as the data argument, which can then be accessed by doing event.data in the handler
function dropDownMouseDown(event) {
event.target.open();
}
function htmlMouseDown(event) {
if (event.target!=event.data)//event.target is the element that was clicked, event.data is set to the dropdown that this handler was added for. Unless these two elements are the same then we can...
event.data.close();///close the dropdown this handler was added for
}
Can't believe I didn't think of that. In my case though the element that opens/closes has child-elements so event.target could be one of the child elements instead of the element that the handler was attached to. So I changed my html-element-handler to this:
function htmlMouseDown(event) {
var element=event.target;
while (element) {
if (element==event.data)
return;
element=element.parentElement;
}
event.data.hide();
}

How do add anchor in the image dynamically

When we use Google Maps, after we search something, Google will add a marker in the map. When we click on this marker, a detailed information window will show, just like this :
I search the "white house",then it create a marker "A".
This is not difficult. However I found something more interesting:
In the map view, even we do not search anything, when the map zoom to some specified level, there will be some anchors generated. If the mouse over it or click it, it will show something accordingly, see the image:
Here see the point "14H and F st NW". I did not search for it, but it show me an anchor. When I click it, it show me a information window accordingly.
But when I use Firebug to see what is downloading, I found that they are just images. I can not find any <a> tag in the HTML.
Also, through Firebug, I found when the map level changed, the browser will send a request to the server to get the features inside the current map view. The response are JSON format. It contain the location and name of the features, then it add the anchors in the map.
But I wonder how do they implement it?
Possible manner to implement this:
1)when the map zoom or pan,request feature location data from server,suppose they get the following data(just take the white house for example):
data:{{name:'white house',Latitude:-77 longitude:38}}
2)bind mouse over event to the map div,something like this:
$("#map").mousemove(function(e){
for(var i=0;i<data.length;i++){
if(e.clientX=getImageX(data[i].x) && e.clientY=getImageY(data[i].y)){
//it mean that the mouse is overing this feature,now set the cousor and show the tip
//show tip,see the iamge:
}
}
});
3)bind the click event to the map div"
$("#map").mousemove(function(e){
for(var i=0;i<data.length;i++){
if(e.clientX=getImageX(data[i].x) && e.clientY=getImageY(data[i].y)){
//it mean that the mouse is clicking this feature,show the infomation window
//show tip,see the iamge:
}
}
});
The above is what I can thougth until now. But it seems that it is not enough, there are still some problems:
1) The tip can information window can show only if the user click or mouser over the very point which is the same as the Latitude and longitude of the feature,but in google Map,you will find that if the mouse over the marker(at any point of the marker),the tip will show. The area which will cause the tip show is the same as the the area of the marker.
It seems that google do someting like this:
$("#map").mousemove(function(e){
for(var i=0;i<data.length;i++){
if(e.clientX.insideTheMarker(data[i]) && e.clientY=insideTheMarker(data[i])){
//it mean that the mouse is clicking this feature,show the infomation window
}
}
});
But the marder size is not the same,how do they caculate the real area which will make the tip show?
2)in the eventhandle function,I haev to iterator all the features to see if the current mouse's location is match with any of the feature,if the featrues in current map view is so many,so it must cause performance problem.
It is likely an onclick event for the image or the map div. You can put an onclick handler on any DOM element. In this case they probably If they put the event on the map div since there is likely to be a lot of images that would have events and that could be a performance issue.
When you handle the click event for a child element in a parent element it is called event delegation. jQuery provides 2 functions for doing event delegation .live and .delegate. Other libraries also provide this functionality, but you can read about the basics this general javascript turorial or this jQuery specific tutorial.
They are probably doing something like (modified from here):
// Get the map canvas
var mapcanvas = document.getElementById('map_canvas');
// Quick and simple cross-browser event handler - to compensate for IE's attachEvent handler
function addEvent(obj, evt, fn, capture) {
if ( window.attachEvent ) {
obj.attachEvent("on" + evt, fn);
}
else {
if ( !capture ) capture = false; // capture
obj.addEventListener(evt, fn, capture)
}
}
// Check to see if the node that was clicked is an anchor tag. If so, proceed per usual.
addEvent(mapcanvas, "click", function(e) {
// Firefox and IE access the target element different. e.target, and event.srcElement, respectively.
var target = e ? e.target : window.event.srcElement;
if ( target.nodeName.toLowerCase() === 'img' ) {
alert("clicked");
return false;
}
});
As for making the the image look like an anchor (i.e. the pointer mouse icon), that can be set with css by setting the cursor property:
#map_canvas img { cursor: pointer }

Categories