javascript mouse coordinates with canvas and css - javascript

well right now im trying to learn how to use the canvas tag on html, and im having trouble handling mouse events when i apply css to the document.
the issue starts when i move the div containing the canvas and center it on the page, the first poing of the canvas wouldnt be 0 because its centered and for some reason 0,0 would be the beginning of the screen and not the beginning of the canvas, which i found weird because im adding the event listener to the canvas directly.
here is the code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>test</title>
<style type="text/css">
body {
font: 100%/1.4 Verdana, Arial, Helvetica, sans-serif;
background: #42413C;
margin: 0;
padding: 0;
color: #000;
}
#divId {
width: 800px;
height: 600px;
text-align:center;
margin: 20px auto;
background-color:#0099FF;
}
</style>
<script>
window.onload = function () {
var canvas = document.getElementById('canvasId');
var c = canvas.getContext('2d');
alert("lol");
canvas.addEventListener('mousedown', hmd, false);
function hmd(e) {
alert ("x: " + e.clientX + " y: " + e.clientY);
}
}
</script>
</head>
<body>
<div id="divId">
<canvas height="300" width="800" id="canvasId" />
</div>
</body>
</html>
so i read somewhere that the issue was caused by the div, but when i tried to give css directly to the canvas tag it didnt work, so basically what i need to do, is to get that canvas centered or placed anywhere on the screen, but having its first pixel as 0,0.
adding a solution would be hard because its centering automatically, so i would need to know the user resolution to be able to calculate the offset so what im looking for is a way to do it simply with css or something.

To get the coordinates relatively to the canvas, do this:
function hmd(e) {
var rx = e.pageX, ry = e.pageY;
rx -= canvas.offsetLeft;
ry -= canvas.offsetTop;
alert ("x: " + rx + " y: " + ry);
}
This assumes your canvas variable definition is global.
Edit: another method:
function hmd(e) {
var rx, ry;
if(e.offsetX) {
rx = e.offsetX;
ry = e.offsetY;
}
else if(e.layerX) {
rx = e.layerX;
ry = e.layerY;
}
}

Here's what I've been using for my latest experimentation. It works with damn near everything: Borders, paddings, position:fixed elements offsetting the HTML element, etc. It also works on all touch devices and even if the browser is zoomed.
http://jsfiddle.net/simonsarris/te8GQ/5/
var stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(can, undefined)['paddingLeft'], 10) || 0;
var stylePaddingTop = parseInt(document.defaultView.getComputedStyle(can, undefined)['paddingTop'], 10) || 0;
var styleBorderLeft = parseInt(document.defaultView.getComputedStyle(can, undefined)['borderLeftWidth'], 10) || 0;
var styleBorderTop = parseInt(document.defaultView.getComputedStyle(can, undefined)['borderTopWidth'], 10) || 0;
var html = document.body.parentNode;
var htmlTop = html.offsetTop;
var htmlLeft = html.offsetLeft;
function getMouse(e) {
var element = can,
offsetX = 0,
offsetY = 0,
mx, my;
// Compute the total offset
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
// Add padding and border style widths to offset
// Also add the <html> offsets in case there's a position:fixed bar
offsetX += stylePaddingLeft + styleBorderLeft + htmlLeft;
offsetY += stylePaddingTop + styleBorderTop + htmlTop;
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
// We return a simple javascript object (a hash) with x and y defined
return {
x: mx,
y: my
};
}

Related

Save mouse coordinate in an array

I want to get mouse coordinate in an array. Also I click anywhere I can't get mouse coordinate.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Google Maps</title>
<style>body {background-color: ivory;}</style>
</head>
<body>
<p id="results">result</p>
<script>
var x = document.getElementById("body");
var offsetX = x.offsetLeft;
var offsetY = x.offsetTop;
x.addEventListener('click', handleClick, false);
function handleClick(e) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
document.getElementById("results").innerHTML = "You clicked at: " + mouseX + "/" + mouseY;
}
</script>
</body>
</html>
There is no element within your HTML that has id="body". You can access the <body> element using document.body.
Also, the body is rather small since it only contains your one <p> element, so you may want to add some css so that you can click anywhere in the window and your event will fire:
html, body {
height: 100%;
}
To store the calculated coordinates in an array, just create a blank array:
var coords = [];
Then add coordinates to them:
coords.push([mouseX, mouseY]);
Here is a working example:
var x = document.body;
var offsetX = x.offsetLeft;
var offsetY = x.offsetTop;
x.addEventListener('click', handleClick, false);
var coords = [];
function handleClick(e) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
coords.push([mouseX, mouseY]);
document.getElementById("results").innerHTML = "You have clicked at: " + JSON.stringify(coords);
}
html, body {
height: 100%;
}
<p id="results">result</p>
This would be how I approach it.
You have no element with an id of body so I created one with an id of bodyEquivalent
If you want to get an actual tag, you need to use
getElementsByTagName('tag_name'); which returns an array of matching elements (you can grab the first element from the array)
or more simply: document.body for the body tag
var x = document.getElementById("bodyEquivalent");
// or
// var x = document.body;
var offsetX = x.offsetLeft;
var offsetY = x.offsetTop;
x.addEventListener('click', handleClick, false);
// array to store click coords
var clickCoords = [];
// a point coord
var ClickPoint = function(x, y) {
this.x = x;
this.y = y;
};
ClickPoint.prototype.toString = function(){
return "(" + this.x + ", " + this.y + ")";
}
function handleClick(e) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// create click point and store it in array
var aClick = new ClickPoint(mouseX, mouseY);
clickCoords.push(aClick);
// update results
showArrayCoords(clickCoords);
}
function showArrayCoords(coords) {
var innerHtml = 'You clicked at:<br/>';
for (i = 0; i < coords.length; i++) {
innerHtml += coords[i] + "<br/>";
}
document.getElementById("results").innerHTML = innerHtml;
}
#bodyEquivalent {
background-color: ivory;
border: 1px solid black;
width: 400px;
height: 300px;
}
<div id="bodyEquivalent">
</div>
<p id="results">result</p>

magento dynamic cubes using interact.js in template .phtml

I used interact.js library to write this piece of code which works absolutely fine standalone on chrome, firefox and w3schools "Try it Yourself" (doesn't work on Edge and IE for some reason). The problem is that when I call a template.phtml with this code inside from the layout.xml, the magento renders it only once, thus the user is not allowed to resize the cubes.
<!-- CSS -->
<style type="text/css">
svg {
width: 100%;
height: 300px;
background-color: #CDC9C9;
-ms-touch-action: none;
touch-action: none;
}
.edit-rectangle {
fill: black;
stroke: #fff;
}
body { margin: 0; }
</style>
<!-- Content -->
<br>
<svg>
</svg>
<br>
<button onclick="location.href = 'square';" id="previousbutton">Go back</button>
<button onclick="location.href = 'squaresection';" style="float:right" id="nextButton">Proceed to next step</button>
<br>
<br>
<script type="text/javascript" src="interact.js">
</script>
<!-- JavaScript -->
<script type="text/javascript">
var svgCanvas = document.querySelector('svg'),
svgNS = 'http://www.w3.org/2000/svg',
rectangles = [];
labels = [];
rectNumb = 5;
function Rectangle (x, y, w, h, svgCanvas) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.stroke = 0;
this.el = document.createElementNS(svgNS, 'rect');
this.el.setAttribute('data-index', rectangles.length);
this.el.setAttribute('class', 'edit-rectangle');
rectangles.push(this);
this.draw();
svgCanvas.appendChild(this.el);
}
function Label (x, y, text, svgCanvas){
this.x = x;
this.y = y;
this.text = text;
this.el = document.createElementNS(svgNS, 'text');
labels.push(this);
this.draw();
svgCanvas.appendChild(this.el);
}
Label.prototype.draw = function () {
this.el.setAttribute('x', this.x);
this.el.setAttribute('y', this.y);
this.el.setAttribute('font-family', "Verdana");
this.el.setAttribute('font-size', 14);
this.el.setAttribute('fill', "black");
this.el.innerHTML = this.text;
}
Rectangle.prototype.draw = function () {
this.el.setAttribute('x', this.x + this.stroke / 2);
this.el.setAttribute('y', this.y + this.stroke / 2);
this.el.setAttribute('width' , this.w - this.stroke);
this.el.setAttribute('height', this.h - this.stroke);
this.el.setAttribute('stroke-width', this.stroke);
}
interact('.edit-rectangle')
// change how interact gets the
// dimensions of '.edit-rectangle' elements
.rectChecker(function (element) {
// find the Rectangle object that the element belongs to
var rectangle = rectangles[element.getAttribute('data-index')];
// return a suitable object for interact.js
return {
left : rectangle.x,
top : rectangle.y,
right : rectangle.x + rectangle.w,
bottom: rectangle.y + rectangle.h
};
})
/*
.draggable({
max: Infinity,
onmove: function (event) {
var rectangle = rectangles[event.target.getAttribute('data-index')];
rectangle.x += event.dx;
rectangle.y += event.dy;
rectangle.draw();
}
})
*/
.resizable({
onstart: function (event) {},
onmove : function (event) {
if (event.target.getAttribute('data-index') > 0)
{
// Main Rect
var rectangle = rectangles[event.target.getAttribute('data-index')];
var rectangle2 = rectangles[event.target.getAttribute('data-index') - 1];
if (rectangle.w - event.dx > 10 && rectangle2.w + event.dx > 10){
rectangle.x += event.dx;
rectangle.w = rectangle.w - event.dx;
rectangle2.w = rectangle2.w + event.dx;
}
rectangle.draw();
rectangle2.draw();
var label = labels[event.target.getAttribute('data-index')];
var label2 = labels[event.target.getAttribute('data-index') - 1];
label.text = rectangle.w + " mm";
label2.text = rectangle2.w + " mm";
label.x = rectangle.x + rectangle.w / 4;
label2.x = rectangle2.x + rectangle2.w / 4;
label.draw();
label2.draw();
}
},
onend : function (event) {},
edges: {
top : false, // Disable resizing from top edge.
left : true,
bottom: false,
right : false // Enable resizing on right edge
},
inertia: false,
// Width and height can be adjusted independently. When `true`, width and
// height are adjusted at a 1:1 ratio.
square: false,
// Width and height can be adjusted independently. When `true`, width and
// height maintain the aspect ratio they had when resizing started.
preserveAspectRatio: false,
// a value of 'none' will limit the resize rect to a minimum of 0x0
// 'negate' will allow the rect to have negative width/height
// 'reposition' will keep the width/height positive by swapping
// the top and bottom edges and/or swapping the left and right edges
invert: 'reposition',
// limit multiple resizes.
// See the explanation in the #Interactable.draggable example
max: Infinity,
maxPerElement: 3,
});
interact.maxInteractions(Infinity);
var positionX = 50,
positionY = 80,
width = 80,
height = 80;
for (var i = 0; i < rectNumb; i++) {
positionX = 50 + 82 * i;
new Rectangle(positionX, positionY, width, height, svgCanvas);
}
for (var i = 0; i < rectNumb; i++) {
positionX = 50 + 82 * i;
new Label(positionX + width/4, positionY + height + 20, width +" mm", svgCanvas);
}
</script>
Any suggestions of what I could do to implement this code into magento would be much appreciated.
Magento did not render the code only once. The problem was that canvas event listener always assumed that pointer coordinates were wrong. Since canvas is the first element of the page(because it is the first element in that .phtml file), event listener assumed it will be displayed at the top, but that was not the case because of the way magento page rendering works.
This issue was resolved simply by measuring the height of content above canvas and just mathematically subtracting that from pointers position before passing it to event listener.
The problem with this solution is that it works only for single page or with multiple pages that have the same height of content above canvas(=>same design). If anyone knows a way in which person would not need to "recalculate" the height for every single page that has different design, sharing knowledge would be much appreciated.

Get Click Coordinates on canvas inside DIV

I have a canvas inside a div which makes it scrollable to the right/left if its to large. I need to get the click coordinates on the canvas. I have tried so many different things I have seen but nothing is giving me the right coordinates. I have a rectangle in the canvas and when i click on the rectangle which is at a set coordinate.The "clicked" coordinates are not what they should be the x coordinate is 100px short. Could anyone point me in the right direction ?
HTML:
<div id="cv">
<canvas id="canvas" width="30000" height="600"></canvas>
</div>
CSS:
<style>
#cv{
display: block;
width: 1500px;
height: 500px;
overflow: auto;
}
<script>
canvas.addEventListener("mousedown", doMouseDown, false);
function doMouseDown(event){
var totalOffsetX = 0;
var totalOffsetY = 0;
var canvasX = 0;
var canvasY = 0;
var currentElement = this;
do{
totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
}
while(currentElement = currentElement.offsetParent)
canvasX = event.pageX - totalOffsetX;
canvasY = event.pageY - totalOffsetY;
}
</script>
I just used a mouse following function, and if there was a click it takes the coordinates of that. It isnt how I wanted it to go but it seems to be working fine.

Drag/drop in javascript - element can move by x but not y?

So I'm trying to do a drag/drop on elements in javascript. The video tutorial I used is here; https://www.youtube.com/watch?v=KTlZ4Hs5h80. I've coded it exactly as it says and I am able to move an object by it's x value but not it's y. So, in summary, whenever I move my mouse the position of the image changes by x, but is constant for y so I can only move my image left and right, and not up and down.
This is my html file:
<!DOCTYPE html>
<html lang="en">
<html>
<head>
<LINK href="gameStyle.css" rel="stylesheet" type="text/css">
</head>
<body>
<section id="main">
<img id="bowl" src="images/bowl.gif">
<img id="egg" src="images/egg.gif">
</section>
<script type="text/javascript" src="gameScript2.js">
</script>
</body>
</html>
This is my javascript file:
function eggIntoBowl()
{
function Draggable(element, dragStart, dragDrop){
this.element = element;
this.dragStart = dragStart;
this.dragDrop = dragDrop;
this.element.classList.add('draggable');
var self = this;
var move = function(event){
event.stopPropagation();
event.preventDefault();
var originalX = parseInt(window.getComputedStyle(this).left);
var originalY = parseInt(window.getComputedStyle(this).top);
var mouseDownX = event.clientX;
var mouseDownY = event.clientY;
function dragEgg(event)
{
self.element.style.left = originalX + event.clientX - mouseDownX + "px"
self.element.style.top = originalY + event.clientY - mouseDownY + "py"
event.stopPropagation();
}
function dropEgg(event)
{
document.removeEventListener('mousemove', dragEgg, true);
document.removeEventListener('mouseup', dropEgg, true);
event.stopPropagation();
}
document.addEventListener('mouseup', dropEgg, true);
document.addEventListener('mousemove', dragEgg, true);
};
this.element.addEventListener('mousedown',move,false);
};
var egg = document.getElementById('egg');
var dragObject = new Draggable(egg);
};
window.addEventListener("load", eggIntoBowl, false);
and this is my css:
body{
width: 896px;
height: 652px;
background: #fff url(images/eggsToBowlScene.jpg) no-repeat;
}
#egg{
position:absolute;
top:190px;
left:56px;
}
#bowl{
position:absolute;
top:141px;
left:231px;
}
.draggable:hover{
cursor: move;
}
Any ideas? I can't work out what I've done wrong. I used another drag/drop tutorial in the past and the same thing happened so I tried this other one, therefore I'm guessing it has something to do with my html file or css..?
In the dragEgg() method you are using "py" instead of "px". This is not meant to be an x and y value, it is short for "pixels". The browser doesn't understand what unit a "py" is so it won't move. Changing it to "px" will tell the browser how many pixels to offset on the Y axis.
self.element.style.top = originalY + event.clientY - mouseDownY + "px";
Why are you using this code if you can use simply the jQuery UI draggable interacion?
http://jqueryui.com/draggable/

Drawing line in Canvas having issue

I'm currently working on an iOS app which uses HTML 5 and JavaScript for drawing Graphs.
I just did a sample App.
My Code:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
var a = 0;
var b = 0;
function init()
{
var can = document.getElementById('can');
can.addEventListener("click",click, false);
}
function click(event)
{
var can = document.getElementById('can');
var c = can.getContext('2d');
var parentPosition = getPosition(event.currentTarget);
c.lineWidth = 1;
c.strokeStyle = '#FFFFFF';
c.beginPath();
c.moveTo(a, b);
a = event.clientX - parentPosition.x;
b = event.clientY - parentPosition.y;
c.lineTo(a, b);
c.stroke();
}
function getPosition(element)
{
var xPosition = 0;
var yPosition = 0;
while (element)
{
xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
element = element.offsetParent;
}
return { x: xPosition, y: yPosition };
}
</script>
</head>
<body oncopy='copy();' onpaste='paste();'onload ='init();'>
<canvas id="can" style="height:300px;width:300px;background-color:black;">Oops!</canvas>
</body>
</html>
My Issue:
When a user Taps on the screen, I'm drawing a line to that particular point from previous point.
But in my case when I tap on the screen the line is drawn to some other point. Say if I tapped on point (100,100) the line will be drawn to (100, some arbitrary value). Always the Y position is wrong.
What I did:
Tested it on simulator
Tested it on device
Tested it on Firefox
Tested it on Chrome
All results are same. I couldn't find the issue. I alerted the clicked x and y co-ordinate. It's coming correctly. Only problem is with the draw functionality.
Screenshots:
As you can see the X-coordinate is correct. But Y-coordinate is always coming wrong.
Please help me, Thanks in advance.
Can you please make these changes.
In html line#47,
<canvas id="can" height=300 width=300 style="background-color:red;">Oops!</canvas>
In script line#23,
c.beginPath();
c.moveTo(a, b);
a = event.clientX - parentPosition.x;
b = event.clientY - parentPosition.y;
console.log('a:'+a+'--b:'+b);
c.lineTo(a, b);
c.stroke();
TO CLEAR
This is the code that you have to change to have a reusable code:
c.moveTo(a/(can.clientWidth/can.width), b/(can.clientHeight/can.height));
a = event.clientX - parentPosition.x;
b = event.clientY - parentPosition.y;
console.log('a:'+a+'--b:'+b);
c.lineTo(a/(can.clientWidth/can.width), b/(can.clientHeight/can.height));
If you don't use this, the code below works only for 300x300 canvas size.
LAST EDIT:
By analyzing the 2d context (var c = can.getContext('2d');console.log(c);) you can easily understand this error: there is a relation (not explicit) from the canvas and it's 2d context.
As you can see from the image:
the height and the width of the canvas(this is 500*500) are differents from its offset,scroll and client size. So, before to draw, you need to calculate the ratio: 500/150 will be the height coefficient and 500/300 the width one, so a will be multiplied by 1.66667 and b will be multiplied by 3.33333.
Same for the old example (canvas 300*300) the coefficent are 300/300=1 (a:width) 300/150=2 (b:height)
OLD REPLY:
But now, you have to guess why..cause actually I have no time
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script type="text/javascript">
var a = 0;
var b = 0;
function init()
{
var can = document.getElementById('can');
can.addEventListener("click",click, false);
}
function click(event)
{
var can = document.getElementById('can');
var c = can.getContext('2d');
var parentPosition = getPosition(event.currentTarget);
console.log(parentPosition);
console.log(event);
c.lineWidth = 1;
c.strokeStyle = '#FFFFFF';
c.beginPath();
c.moveTo(a, b/2);
a = event.clientX - parentPosition.x;
b = event.clientY - parentPosition.y;
console.log('a:'+a+'--b:'+b);
c.lineTo(a, b/2);
c.stroke();
}
function getPosition(element)
{
var xPosition = 0;
var yPosition = 0;
while (element)
{
xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
element = element.offsetParent;
}
return { x: xPosition, y: yPosition };
}
</script>
</head>
<body oncopy='copy();' onpaste='paste();'onload ='init();'>
<canvas id="can" style="height:300px;width:300px;background-color:black;">Oops!</canvas>
<br>
pagex<input type="text" id="ics">pagey<input type="text" id="ips"><br>
screenx<input type="text" id="ics2">screeny<input type="text" id="ips2">
<script>
$("#can").mousemove(function(event) {
var msg = "Handler for .mousemove() called at ";
document.getElementById('ics').value= event.pageX
document.getElementById('ips').value= event.pageY;
document.getElementById('ics2').value= event.screenX;
document.getElementById('ips2').value= event.screenY;
});
</script>
</body>
</html>

Categories