I have two div elements and one img element:
<div class="game-container">
<div class="bubble-container">
<img src="https://raw.githubusercontent.com/diegoleonardoro/bronx_tourism/master/line.png" class="line" width="128"
height="12" />
</div>
</div>
In my JavaScript, I am trying to add and an event listener to the div "game-container". This event listener is supposed add some movement to the image tag, like so:
var yellowBox = document.querySelector(".game-container");
var line = document.querySelector(".line");
yellowBox.addEventListener("mousemove", function (e) {
var r = e.clientX;
line.style.left = r + "px";
line.style.left = r + "px";
console.log("Black Line", line.getBoundingClientRect());
console.log("r", r);
})
The result that I am expecting is the result of the variable r to be the same as the variable line, as I move the mouse. However, this not what I am getting. As I move the muse, the position of the these two elements is not the same. When If check the two console logs this is what I get:
console.log("Black Line", line.getBoundingClientRect());:
console.log("r", r);
Thanks in advance!
I was able to fix it just by subtracting the difference of the result of console.log("r", r); and the result of console.log("Black Line", line.getBoundingClientRect().left) ;
I don't understand why I had do to this subtraction. If anyone has any insight please share it.
Related
I am trying to implement drag and drop an image element onto an SVG canvas but the elements are not in the same div. I have tried to use clientX and clientY properties but they are out by about 20 pixels when I come to drop the element. I think the problem is that the SVG coordinates work from the top of the root SVG element but drag and drop coordinates are from the visible view port. When I try to release the rock image on the canvas it just seems to go to any random place on it and sometimes off the canvas completely.
I have uploaded all my code to https://github.com/kiwiheretic/gravity
(It shouldn't be too difficult to just clone the repo and open index.html within the browser to see the problem.)
The relevant HTML code is as follows:
<div style="background-color:black; width: min-content;">
<svg id="space" width="600" height="400" xmlns="http://www.w3.org/2000/svg" onload="makeDraggable(evt)">
</svg>
</div>
<div id="object-block-1" class="objects">
<div class="box">
<img src="asteroid.png" alt="asteroid">
</div>
</div>
</div>
The relevant javascript code is:
var objblock = document.getElementById("object-block-1");
objblock.addEventListener("dragstart", function(evt) {
draggedObject = evt.target;
});
objbl
objblock.addEventListener("dragend", function(evt) {
var x = evt.clientX;
var y = evt.clientY;
var src = draggedObject.getBoundingClientRect();
console.log([x,y]);
var space = document.getElementById("space");
var tgt = space.getBoundingClientRect();
if (doesPointCollide(x,y,tgt)) {
//asteroid = makeAsteroid(x, y, 50, 50);
//space.appendChild(asteroid);
}
});
objblock.addEventListener("drag", function(evt) {
var space = document.getElementById("space");
var rect = space.getBoundingClientRect();
var src = draggedObject.getBoundingClientRect();
var x = (src.x - rect.x) + evt.clientX;
var y = (src.y + rect.y) + evt.clientY;
document.getElementsByName("drag-x")[0].value = parseInt(x);
document.getElementsByName("drag-y")[0].value = parseInt(y);
});
I am using the right hand input boxes as kind of a debugging aid. I am not sure why drag-x and drag-y are not resolving to suitable SVG coordinates within the canvas and what needs to be done to fix that.
Any idea what javascript mouse event attributes and element attributes to work out my SVG coordinates for drag and drop?
I have been trying to figure out a way to find the color of a pixel on my webpage. As I have searched for an answer, all I have found is how to do this in a canvas element. Is there a way to do this for the entire page, and if so, how?
Here is an example piece of code that shows a basic part of what I am doing.
//this executes whenever the mouse is moved
document.addEventListener('mousemove', (event) => {
//this just simplifies the varables
mouseX = event.clientX;
mouseY = event.clientY;
document.getElementById("info").innerHTML = "Position: ( " + mouseX + " , " + mouseY + " ) | Color: " + getColor();
// What command do you use to do this? Is it related to the document object? ^
});
function getColor() {
return (" rgb ( 2, 5, 7 ) ");
};
<!DOCTYPE html>
<html>
<body>
<p id="info"><br></p>
<img width="250" src="https://pngimg.com/uploads/chicken/chicken_PNG2160.png"/>
</body>
</html>
I don't know if this is best practice, but you could set up all the elements on the page with a mouseover event that would tell your app what element being hovered. The app could check the element to find out what color it is.
I have a canvas in html:
<canvas id="canvas" width="450" height="450"></canvas>
That I made nine equally sized squares in. I would like to see what square I have clicked as an alert function. How would I do that?
Full Code is here: https://jsfiddle.net/ckd6g1ac/1/
Sorry, I do not have any code relevant to my problem in the JSFiddle, but I have no clue on how to start writing it.
Thanks!
This is your onclick function:
$("#canvas").click(function(e) {
var yNames = ['upper', 'middle', 'lower'],
xNames = ['left', 'middle', 'right'];
alert(('The '
+ yNames[Math.floor((e.offsetY * 3) / canvas.height)] + '-'
+ xNames[Math.floor((e.offsetX * 3) / canvas.width)] + ' box was clicked.')
.replace('middle-middle', 'middle'));
});
Also you had a semantic error in your loop: it should be i<9 instead of 1<9.
offsetX and offsetY were used because these measure the offset from the element itself, which means that it doesn’t matter where the canvas is on the page.
Working JSFiddle.
I haven't been able to calculate the click coordinates (x and y) relative to the element triggering the event. I have not found an easy example online.
I have a simple svg (with 100px left margin) in an HTML page. It contains a group (translated 30px 30px) which has an onclick listener attached. And inside that group I have a rect with 50px width and height.
After I click any part of the group element, I get an event object with coordinates relative to the HTML page (evt.clientX and evt.clientY).
What I need to know is where exactly the user clicked inside the group element (the element holding the onclick listener).
How do I convert clientX and clientY coordinates to the group element coordinates. So say, if I click the top leftmost part of the rect it should give me x=0 and y=0.
Here is currently what I have:
<!DOCTYPE html>
<html>
<head>
<style>
body{
background:black;
}
svg{
fill:white;
background:white;
position: absolute;
top:100px;
left:100px;
}
</style>
<script>
function clicked(evt){
alert("x: "+evt.clientX+" y:"+evt.clientY);
}
</script>
</head>
<body>
<div>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200">
<g transform="translate(30 30)" onclick="clicked(evt)">
<rect x="0" y="0" width="50" height="50" fill="red"/>
</g>
</svg>
</div>
</body>
</html>
Tolokoban's solution has the limitation that it doesn't work if your viewBox deviates from the default, that is if it is different from viewBox="0 0 width height". A better solution that also takes viewBox into account is this:
var pt = svg.createSVGPoint(); // Created once for document
function alert_coords(evt) {
pt.x = evt.clientX;
pt.y = evt.clientY;
// The cursor point, translated into svg coordinates
var cursorpt = pt.matrixTransform(svg.getScreenCTM().inverse());
console.log("(" + cursorpt.x + ", " + cursorpt.y + ")");
}
(Credit goes to Smerk, who posted the code)
If the viewBox is not set or set to the default, this script will return the same values as Tolokoban's script. But if you have an SVG like <svg width="100px" height="100" viewBox="0 0 200 200">, only this version will give you the correct results.
Try to use getBoundingClientRect(): http://jsfiddle.net/fLo4uatw/
function clicked(evt){
var e = evt.target;
var dim = e.getBoundingClientRect();
var x = evt.clientX - dim.left;
var y = evt.clientY - dim.top;
alert("x: "+x+" y:"+y);
}
The proposed solutions are great, but they won't work in all scenarios.
The OP's post is titled
How to get the click coordinates relative to SVG element holding the
onclick listener?
So if you put the onclick listener onto your root svg element, whenever you click on any of its child elements, getBoundingClientRect will give you the child's Rect and you won't get the click coordinates relative to the root svg.
This was my case as I needed the coordinates relative to the root at all times, and the solution that worked for me was to use e.target.farthestViewportElement. Here's an excerpt from my (JSX) code:
const onClickSvg = e => {
const { farthestViewportElement: svgRoot } = e.target;
const dim = svgRoot.getBoundingClientRect();
const x = e.clientX - dim.left;
const y = e.clientY - dim.top;
console.log(`x: ${x}, y: ${y}`);
};
<svg onClick={onClickSvg}>...</svg>
Adding notes after many researchs (and fails!).
For a css translated svg, to get the coordinates of a clicked point for drawing.
In my case, using a mouse wheel event to translateX, so the actual rendering depends of the screen size and of the actual translated value.
I recommend for your use case to make a little drawing like the following, it will help a lot for figuring out what's going on.
Let's say my svg has for id: shoke
To get the total computed width, in pixels:
shoke.getBoundingClientRect()["width"]
Need to know the actual translateX value. (From the right, so it is a negative number, on this case)
shoke.style.transform.substr(11).slice(0,-3)
Note that it return a string and not an integer, so:
+shoke.style.transform.substr(11).slice(0,-3)
Now to get the coordinates of the mouse, related to the pixel x0 of the screen.
let pt = document.querySelector('svg').createSVGPoint();
pt.matrixTransform(shoke.getScreenCTM().inverse())["x"]
So, at the end, to obtain the precise x point:
svg_width - (svg_width + translated) + from_pixel x0 of the screen_click
Is something like this:
shoke.getBoundingClientRect()["width"] - (shoke.getBoundingClientRect()["width"] + +shoke.style.transform.substr(11).slice(0,-3)) + pt.matrixTransform(shoke.getScreenCTM().inverse())["x"]
createSVGPoint is deprecated according to Mozilla. Use static method of DOMPoint.fromPoint(svg_element);
function dom_track_click(evt) {
//<svg onclick='dom_track_click(event); >
let pt = DOMPoint.fromPoint(document.getElementById('svg_canvas'));
pt.x = evt.clientX;
pt.y = evt.clientY;
// The cursor point, translated into svg coordinates
let cursorpt = pt.matrixTransform(document.getElementById('svg_canvas').getScreenCTM().inverse());
console.log("(" + cursorpt.x + ", " + (cursorpt.y) + ")");
}
I've created a running example of a content assistant in an editable area on a html document. So if the user hits ctrl and space on the keyboard a context menu appears. Currently (see demo bellow) the context menu is on the right y position (bellow the text). But it goes not along with the x-axis (if the text becomes longer the box will be sown on the beginning of the line).
Can you help me solving this problem?
Greetings,
mythbu
Example code:
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Test</title>
<script type="text/javascript">
var iframe = null, iwindow = null, iDocument = null;
function setUpInput() {
iframe = document.createElement( 'iframe' );
iframe.setAttribute( 'id', 'iframe-test' );
iframe.setAttribute( 'frameborder', 0 );
iframe.setAttribute( 'style', 'width:100%; height:100%;border: solid 1px red;' );
document.getElementById( "input" ).appendChild( iframe );
iwindow = iframe.contentWindow;
idocument = iwindow.document;
idocument.open();
idocument.write("<p></p>");
idocument.close();
idocument.body.setAttribute( 'spellcheck', false );
idocument.body.setAttribute( 'style', 'font-family: Consolas,serif;font-size: 0.8em;' );
idocument.body.contentEditable = true;
iwindow.onkeydown = function(e) {
if (e.ctrlKey && e.keyCode == 32) {
createSuggestObject();
return false;
}
if (e.ctrlKey) return false;
};
iwindow.onkeypress = function(e) {if (e.ctrlKey) return false;};
}
function createSuggestObject() {
suggest = new Object();
suggest.box = document.createElement( 'div' );
suggest.box.style.position = 'absolute';
suggest.box.style.width = '120px';
suggest.box.style.overflow = 'auto';
suggest.box.style.border = '1px solid #BEC7E4';
suggest.box.style.display = 'block';
suggest.box.style.marginTop = '16px';
suggest.box.innerHTML = "Example 1";
document.body.appendChild( suggest.box )
var position = iframe.getBoundingClientRect();
var selObj = iwindow.getSelection();
var selRange = selObj.getRangeAt(0);
var p2 = selObj.anchorNode.parentNode.getBoundingClientRect();
suggest.box.style.top = Math.round( window.scrollY + position.top + p2.top) + 'px';
suggest.box.style.left = Math.round( window.scrollX + position.left + p2.left) + 'px';
}
window.onload = function() {
setUpInput();
};
</script>
</head>
<body>
<div id="input"></div>
</body>
</html>
Main problem with your solution was that you were using bounding rectangle of the p element (which as you assumed contained text inputed by user) as a reference to where to place suggest object.
First of all you didn't account bounding rectangle width into the position of the suggest object, so your suggestion box stayed on the left no matter how long the text was.
However, that approach would fail eventually because if the text would have more than one line (where the second line would be shorter than the first one), the width of bounding rectangle would equal length of the first line (more or less). Hence, the suggestion object would be positioned incorrectly.
My first idea of how to fix your code was to append some inline element to the text (beacon, if you will), measure it's position, remove it from the DOM and use that calculated position to properly set suggestion object.
It turned out to almost work. Almost, because as it turned out, different browsers use different methods of dealing with contentEditable line endings. Firefox for example inserts <br _moz_dirty=""/> at the end of the line, while Chrome does not. So when I tried to append my beacon element after the text it was appended after that <br/> causing incorrect position again.
Solution was to change the way of getting text node we're dealing with and insert beacon right before nextSibling of it.
Here's working example http://jsfiddle.net/MmKXS/10/
Note 1: I've removed addition of empty <p></p> element to the document of the iframe since in Chrome text inputed by user wasn't inserted into it, causing yet another problems with positioning suggest object.
Note 2: As for now my solution only works for positioning suggestion object at the end of the text, not at the cursor position as it would involve splitting textNodes, inserting the beacon, checking its position and merging textNodes again. Depending on use case you have for that code that could lead to poor performance and/or could require changing the whole approach of how to deal with positioning your suggestion object.