Detect which canvas rectangle is clicked - javascript

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.

Related

How do you get the color of a specific pixel on a webpage in javascript? (no canvas)

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.

Unsuccessfully, trying to set the position of an html element using clientX

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.

How to get the click coordinates relative to SVG element holding the onclick listener?

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

How to get a rotate animation to trigger on every mouse click using Raphael.js?

So I've been working on this problem for a bit and I've hit yet another roadblock.
Essentially, I'm attempting to have a mouse click trigger a rotation animation on a set of svg objects drawn up with Raphael.js. And while I've got the actual animation solved I can't seem to get it to run on subsequent clicks...just runs the one time and thats it.
So I'd imagine there is a bit of code that I'm neglecting to include..or that possibly the animation breaks after do to the change in coordinates after the applied animation? Anyway, I'm stumped...
Here's the JSFiddle demo.
Here's the code:
var rsr = Raphael('rsr', 320, 240),
circle_01 = rsr.circle(160, 120, 20).attr({fill:"#666666"}),
circle_02 = rsr.circle(160, 220, 20),
circle_03 = rsr.circle(160, 20, 20),
circle_04 = rsr.circle(20, 120, 20),
circle_05 = rsr.circle(300, 120, 20),
group = rsr.set();
group.push(
circle_02,
circle_03,
circle_04,
circle_05
);
var aa = group.getBBox();
circle_01.click(function() {
var group_x_center = aa.x + (aa.width / 2),
group_y_center = aa.y + (aa.height / 2);
group.animate({
transform: group.attr("transform") + "R360,"
+ group_x_center + ","
+ group_y_center
}, 1000);
});
I think that problem you're seeing is that when you first run the animation, it rotates your set the desired number of degrees -- and then when the same animation is fired subsequently, it does nothing because the set has already been rotated to that angle.
I would solve this problem by appending to the transform instead of setting it absolutely:
group.animate({transform: group.attr("transform") + "...R45,"+group_x_center+","+group_y_center}, 1000);
Alternatively, you could keep track of the current angle, increment it on each click, and then set it variably -- but that'd probably be more work =)

Add and remove textbox using javascript

At onclick event I am adding marker (image pin.png):
var relativeX = event.pageX;
var relativeY = event.pageY;
R.image("pin.png", relativeX, relativeY, 22, 22);
R in this code is Raphael paper: var R = Raphael("paper", 500, 500);
And I have to add also textbox next to this pin. It will be something like description of this marker. There should also be delete icon next to it that would remove both marker and textbox. User can add unlimited number of markers.
How can I add this textbox and icon/button to remove both marker and it's textbox?
I am using JQuery and Raphael.
Raphael's ability to handle text is absolutely horrible. I recently had to do something simular for a project, and i ended up using an HTML5 canvas to generate an image, and then load that image into my project.
So say you create your rect in Raphael, then you'll want to generate an image with your description in it:
var width = myRect.getBBox().width
var height = myRect.getBBox().height
var canvas = jQuery("<canvas width="+width+"px height="+height+"px />");
var context = canvas[0].getContext("2d");
context.font = "10pt Calibri ";
context.textAlign = "left";
context.textBaseline = "top";
context.fillText("this is text", xPos, yPos);
and then you'll want to move it into raphael:
var img = canvas[0].toDataURL("image/png"); //turns the canvas object into a png and returns the dynamic url
var bb = myRect.getBBox();
paper.image(img,bb.x,bb.y,300,400)
Its not the 'easiest solution in the world.. but i think you'll find that other options are not very fun to deal with.
Other options include
var description = paper.text(0,0,"this is text");
which may work better for you, but if you're doing any thing with zooming in and out, or even possibly dragging objects, you will have a hard time.
as for your adding markers bit, you'll probably want a function that says something like
function addMarker(x,y){
var marker = paper.set();
marker.push(
paper.rect(x,y,5,20).attr({fill:"#000"}),
paper.rect(x,y,10,5).attr({fill:"#000"}),
);
}
and you'll want a click function as well, something like
$("paper").click(function(e){
addMarker(e.offsetX,e.offsetY)
});
I hope this helps some. Feel free to comment if you need any more help.
edit:
To remove raphael elements, you can use
myElement.remove();
or even
myElement.hide();
edit:
I thought you might have been looking for an input field... Which is something that Raphael can't handle. So you're going to have to do some work arounds.
If you create an input field and then position it absolutely on top of your raphael program you can achieve this.
var textbox = $("<textarea/>");
textbox.css({"z-index" : 2, "position" : "absolute"});
textbox.css("left",myRaphaelElement.getBBox().x)
textbox.css("top",myRaphaelElement.getBBox().y)
$("body").append(textbox)
and i imagine you're going to want the user to be able to save what they write.. which is where you'll add a butotn and do something like
button.onclick(function(){
// write code here that involves the bit i wrote earlier in my post
// that takes textbox.val() as your text.
});
better?
I ended using simple javascript:
var relativeX = event.pageX;
var relativeY = event.pageY;
$('.marker').append('<div class="pin_container" style="top:' + relativeY + 'px; left:' + relativeX + 'px;"> <input type="text" name="textbox" id="textbox' + counter + '" value="" class="pin_textbox"><input type="button" id="remove" class="delete_button" value=" "></div>');
counter++;
$(".delete_button").click(function () {
$(this).parent().remove();
});
Operations on text in Raphael are way to much complicated.

Categories

Resources