I am writing a simple drawing app to get an understanding of the HTML 5 canvas. The problem is that I simply can't seem to get the correct mouse position within the canvas element.I've looked at the other questions on stackoverflow like the one here getting mouse position with javascript within canvas that address this issue but their solutions don't seem to help me.
Here is my code:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Untitled Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script>
<style type="text/css">
#test {
border: solid black 1px;
width: 500px;
height: 500px;
}
</style>
<script type="text/javascript">
$(function(){
var canvas=document.getElementById('test');
if(canvas.getContext){
var ctx =canvas.getContext('2d');
var draw = false;
ctx.strokeStyle = "rgb(200,0,0)";
ctx.lineWidth = 3;
ctx.lineCap = "round";
$('#test').mousedown(function(){draw=true;});
$('#test').mouseup(function(){draw=false;});
$('#test').mousemove(function(e){
if(draw){
var x , y;
x = e.layerX;
y = e.layerY;
ctx.moveTo(x,y);
ctx.lineTo(x+1,y+1);
ctx.stroke();
}
});
}
});
</script>
</head>
<body>
<canvas id="test"></canvas>
</body>
</html>
What am I doing wrong here? I have tested this in both Chrome/Firefox.
Your canvas is missing width and height properties. In the current solution it just scales the default to fit your CSS. This in turn breaks your mouse coords. Try something along
<canvas id="test" width=500 height=500></canvas>
as your canvas markup.
Suppose your canvas has already been declared...
var Mouse = { //make a globally available object with x,y attributes
x: 0,
y: 0
}
canvas.onmousemove = function (event) { // this object refers to canvas object
Mouse = {
x: event.pageX - this.offsetLeft,
y: event.pageY - this.offsetTop
}
}
Mouse will update when you mouse move on the canvas
You should add pixel dimenstion to your canvas element:
<canvas id="test" width='500px' height='500px' ></canvas>
Here is working example - http://jsfiddle.net/gorsky/GhyPr/.
Related
This question already has answers here:
Size of HTML5 Canvas via CSS versus element attributes
(3 answers)
Closed 2 years ago.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Archade!</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div style="text-align: center;">
<canvas id="gameCanvas"></canvas>
</div>
<script>
var canvas;
var canvasContext;
window.onload = function () {
console.log("Game working!");
canvas = document.getElementById("gameCanvas");
canvasContext = canvas.getContext("2d");
canvasContext.fillStyle = "black";
canvasContext.fillRect(0, 0, canvas.width, canvas.height);
console.log("Loading red box");
canvasContext.fillStyle = "red";
canvasContext.fillRect(500, 500, 50, 25);
console.log("Red box should be loaded!");
};
</script>
</body>
</html>
This is my html code, [ in style.css i've just set width and height of the canvas ].
The black canvas is being displayed on the screen but the red box isn't displayed anywhere.
The console log above and below the red rectangle is also working fine.
Please help me fix this! I want the red rectangle to be displayed as well.
Thanks for your time :)
From this reference - https://www.w3schools.com/tags/canvas_fill.asp
You can do the following:
First draw the rectangle.
Then, set the fillStyle.
Then fill the rectangle.
Check the code below:
var canvas;
var canvasContext;
window.onload = function() {
console.log("Game working!");
canvas = document.getElementById("gameCanvas");
canvasContext = canvas.getContext("2d");
canvasContext.rect(0, 0, canvas.width, canvas.height);
canvasContext.fillStyle = "black";
canvasContext.fill();
console.log("Loading red box");
canvasContext.rect(500, 500, 50, 25);
canvasContext.fillStyle = "red";
canvasContext.fill();
console.log("Red box should be loaded!");
};
<div style="text-align: center;">
<canvas id="gameCanvas"></canvas>
</div>
Setting the canvas size in css might not be enough.
Try also setting the width/height attributes of the canvas element.
For example:
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
I think the red rectangle isn't displayed because it's position exceeds the default size of a canvas.
HTML5 document - Canvas Element is not running the JavaScript parameters for the customized 'rectangle' cursor. HELP PLEASE :)
<head>
<title>Canvas Element & Custom Cursor</title>
</head>
<body id="body" style="background-color:red;">
<canvas id="canvas" width="600" height="400" style="background-
color:white;"> </canvas>
<script>
funtion CanvasProperties(){
var canvas = document.getElementById("canvas");
canvas = canvas.getContext("2d");
window.addEventListener("mousemove", CustomCursor, false);}
function CustomCursor(){
canvas.clearRect(0,0,600,400);
var xPosition = clientX;
var yPosition = clientY;
canvas.fillRect(xPosition, yPosition, 100, 100);}
window.addEventListener("load", CanvasProperties, false);
</script>
</body> </html>
There are several issues here, some already pointed out in Scimonster's answer, but an important one remains.
For the rectangle to be placed correctly you need to "correct" the mouse positions. The mouse positions are relative to client window while you will need them relative to canvas element.
Also, you are overriding canvas with context. Use a separate variable for it, and place those in global (parent) scope.
Here is a full version (inside the script tags):
var canvas, context; // place this in global scope
function CanvasProperties(){
canvas = document.getElementById("canvas");
context = canvas.getContext("2d"); // separate var for context...
window.addEventListener("mousemove", CustomCursor, false);
}
function CustomCursor(e){
var canvasRect = canvas.getBoundingClientRect(); // get position of canvas element
var xPosition = e.clientX - canvasRect.left; // adjust mouse positions to
var yPosition = e.clientY - canvasRect.top; // become relative to canvas
context.clearRect(0,0,600,400); // use context
context.fillRect(xPosition - 50, yPosition - 50, 100, 100);
}
window.addEventListener("load", CanvasProperties, false);
<canvas id="canvas" width=600 height=400></canvas>
You're not using the event object at all -- clientX and clientY aren't global properties.
function CustomCursor(event){
canvas.clearRect(0,0,600,400);
var xPosition = event.clientX;
var yPosition = event.clientY;
canvas.fillRect(xPosition, yPosition, 100, 100);}
Thanks, guys! We now have a custom cursor for painting on canvas :)
<!DOCTYPE html>
<html>
<head>
<title>Canvas Element & Custom Cursor</title>
</head>
<body id="body" style="background-color:red;">
<canvas id="canvas" width="600" height="400" style="background-
color:white;"> </canvas>
<script>
var canvas; var context;
function CanvasProperties(){
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
window.addEventListener("mousemove", CustomCursor, false);}
function CustomCursor(event){
var xPosition = event.clientX;
var yPosition = event.clientY;
context.fillRect(xPosition, yPosition, 100, 100);}
window.addEventListener("load", CanvasProperties, false);
</script>
</body>
</html>
I'm trying to replace my cursor within the canvas with two perpendicular lines: one horizontal and one vertical. Example here: http://imgur.com/tUBkQn8
I need to do three things
1) Hide the cursor
2) Draw the crossing lines
3) Erase old lines on mouse move and draw new lines based on new mouse location
The following code is a non-performant way of achieving #2 and #3 (it's incredibly slow re-rendering the entire canvas every time the mouse moves):
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
canvas.addEventListener('mousemove', function(evt) {
// clear the canvas
ctx.clearRect(0, 0, xsize, ysize);
// re-draw the base
drawCanvas();
var mousePos = getMousePos(canvas, evt);
// draw vertical line
ctx.beginPath();
ctx.moveTo(mousePos.x,0);
ctx.lineTo(mousePos.x,ysize);
ctx.stroke();
ctx.closePath();
// draw horizontal line
ctx.beginPath();
ctx.moveTo(0,mousePos.y);
ctx.lineTo(xsize,mousePos.y);
ctx.stroke();
ctx.closePath();
}, false);
So my questions:
1) How do I hide the cursor but still display the lines?
2) Is there a way I can just re-render the crossing lines ONLY, rather than the whole canvas every time the mouse moves? Thanks!
Here's one way to create a custom cursor and maintain performance:
Create a second canvas on top of your main drawing canvas.
Hide the system mouse cursor on both the canvases.
Draw/Move your X-cursor and nothing else on the top canvas
Example code and a Demo: http://jsfiddle.net/m1erickson/abokzhn6/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
#wrapper{position:relative;}
#canvas,#cursor{position:absolute; cursor:none;}
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("cursor");
var ctx=canvas.getContext("2d");
var $canvas=$("#cursor");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
$("#cursor").mousemove(function(e){handleMouseMove(e);});
function handleMouseMove(e){
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
ctx.moveTo(mouseX,mouseY-15);
ctx.lineTo(mouseX,mouseY+15);
ctx.moveTo(mouseX-15,mouseY);
ctx.lineTo(mouseX+15,mouseY);
ctx.stroke();
}
}); // end $(function(){});
</script>
</head>
<body>
<div id='wrapper'>
<canvas id="canvas" width=300 height=300></canvas>
<canvas id="cursor" width=300 height=300></canvas>
</div>
</body>
</html>
Ad 1
I didn't test it but I think that you can hide cursor by changing cursor image in CSS to white 1x1 image.
Ad 2
Use http://kineticjs.com/
I need to scale polygons with the size of my screen. Originally the polygons are created on a canvas with a size of 640x480. I would like to scale them down or up to a new resolution of whatever I desire and maintain their relative positions and sizes. Here is the code I am currently using:
this.scale = function (x1, y1) {
for (var i = 0; i < this.points.length; i++) {
this.points[i].x *= x1;
this.points[i].y *= y1;
}
}
Where x1 and y1 equal the new size of the screen divided by the original size. The issue I am facing is that the polygons appear to be offset from where they should be relative to an image. I also tried translating the vectors first before scaling and then translating them back to the original centroid using(pseudocode):
centroid = points / number of points
points = points - centroid
points = points * scale
points = points + centroid
This further offsets the polygons from where they should be relative to the image drawn on the canvas. Is there something I am missing here?
Edit: Added an example image of the issue: http://i.stack.imgur.com/EGeSw.jpg
Thanks!
Just multiply all points by the scaling factor of the canvas.
Example Code and a Demo: http://jsfiddle.net/m1erickson/xEqU5/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var scale=1.00;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/scale8.jpg";
function start(){
drawAtScale();
}
function drawAtScale(){
canvas.width=img.width*scale;
canvas.height=img.height*scale;
drawImage();
drawPoly();
}
function drawImage(){
ctx.drawImage(img,0,0,img.width*scale,img.height*scale);
}
function drawPoly(){
ctx.save();
ctx.lineWidth=3;
ctx.beginPath();
ctx.moveTo(185*scale,46*scale);
ctx.lineTo(269*scale,53*scale);
ctx.lineTo(621*scale,170*scale);
ctx.lineTo(630*scale,329*scale);
ctx.lineTo(382*scale,304*scale);
ctx.lineTo(163*scale,234*scale);
ctx.closePath();
ctx.strokeStyle="gold";
ctx.stroke();
ctx.restore();
}
$("#smaller").click(function(){
scale/=1.10;
drawAtScale();
});
$("#larger").click(function(){
scale*=1.10;
drawAtScale();
});
}); // end $(function(){});
</script>
</head>
<body>
<button id="smaller">Scale Canvas Smaller</button>
<button id="larger">Scale Canvas Larger</button><br>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
I was able to fix my issue. I was scaling correctly however when the shapes were being created they were being created on a differently sized image which had black boxes at the top causing an offset.
Using a simple translation fixed the issue. The code looked something like this:
//My offset.
this.translate(-10, -50);
this.translate = function (x1, y1) {
for (var i = 0; i < this.points.length; i++) {
this.points[i].x += x1;
this.points[i].y += y1;
}
}
Please help me to understand the events of the canvas.
Take for example two of the square. Each has its own area where you need to process such events:
Hover the square fills it with colour.
Click invokes filling the square third color and displays in a separate block, for example, the ID of the square.
Accordingly, it is possible to work with only one square. Click on the second square will reset the first square and output data from the second.
While moving the mouse in the area of one of the squares near the mouse, a pop-up window that displays the ID of the square.
And how can I make a link to a separate square? That is, to the user clicks a link that invokes the event, similar to a click on a separate square.
HTML code
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="scripts/canvas.js"></script>
<script>
window.onload = function()
{
drawCanvas('mainCanvas');
};
</script>
</head>
<body style="margin: 0px;">
<canvas id="mainCanvas" width="300" height="200"></canvas>
<aside>ID of the square</aside>
</body>
</html>
JS code
function makeRect(x, y, w, h)
{
return { x: x, y: y, w: w, h: h };
}
function drawCanvas(canvasId)
{
//// General Declarations
var canvas = document.getElementById(canvasId);
var context = canvas.getContext('2d');
//// Color Declarations
var blackColor = 'rgba(0, 0, 0, 1)';
var whiteColor = 'rgba(255, 255, 255, 1)';
//// Frames
var frameOne = makeRect(64, 70, 50, 50);
var frameTwo = makeRect(194, 70, 50, 50);
//// RectangleOne Drawing
context.beginPath();
context.rect(frameOne.x, frameOne.y, 50, 50);
context.fillStyle = whiteColor;
context.fill();
context.strokeStyle = blackColor;
context.lineWidth = 1;
context.stroke();
//// RectangleTwo Drawing
context.beginPath();
context.rect(frameTwo.x, frameTwo.y, 50, 50);
context.fillStyle = whiteColor;
context.fill();
context.strokeStyle = blackColor;
context.lineWidth = 1;
context.stroke();
}
You ask a really broad question!
This will get you started:
About canvas rectangles
When you draw a rect on the canvas it becomes just “painted pixels” (like a painting of a rectangle on an artists canvas).
Nothing about the rect is “remembered” by canvas.
This means you can’t hit-test the rect to see if your mouse is hovering over that rect. The canvas doesn’t know anything about your rect.
Keeping track of rectangles
You must keep track of each rect’s properties yourself (x-coordinate, y-coordinate, width, height, color).
A convienient way to do this is creating a javascript object with the rect’s properties:
var rect1 = { x:30, y:30, width:50, height:25, color:"blue" };
Then use this rect1 object to draw the rect on your canvas
context.fillStyle=rect1.color;
context.fillRect( rect1.x, rect1.y, rect1.width, rect1.height );
Now you can always refer to rect1 to get the properties of your rectangle.
Mouse events
The canvas mouse events always relate to the canvas element itself, never to a rect drawn on the canvas.
Here’s how to listen to the mouse events on canvas:
// use jQuery to ask the browser to call `handleMouseMove` whenever the mouse is moved
$("#canvas").mousemove(function(e){handleMouseMove(e);});
// this is called every time your mouse moves
function handleMouseMove(e){
// get the mouses current X,Y position
// Note: offsetX/offsetY -- you must adjust for the offset of the canvas relative to the web page
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
}
Testing if the mouse is inside the rect
Remember that canvas knows nothing about your rect1, so use the rect1 object to “hit-test” whether the mouse is inside rect1:
if(
mouseX>=rect1.x &&
mouseX<=rect1.x+rect1.width &&
mouseY>=rect1.y &&
mouseY<=rect1.y+rect1.height
){
// the mouse is inside rect1
ctx.fillStyle="red";
ctx.fillRect(rect1.x,rect1.y,rect1.width,rect1.height);
}else{
// the mouse is not inside rect1
ctx.fillStyle=rect1.color;
ctx.fillRect(rect1.x,rect1.y,rect1.width,rect1.height);
}
This introduction should get you started coding…experiment for yourself!
Here’s a working demo: http://jsfiddle.net/m1erickson/tPjWX/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var rect1 = { x:30, y:30, width:50, height:25, color:"blue" };
ctx.fillStyle=rect1.color;
ctx.fillRect(rect1.x,rect1.y,rect1.width,rect1.height);
function handleMouseMove(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
if(
mouseX>=rect1.x &&
mouseX<=rect1.x+rect1.width &&
mouseY>=rect1.y &&
mouseY<=rect1.y+rect1.height
){
ctx.fillStyle="red";
ctx.fillRect(rect1.x,rect1.y,rect1.width,rect1.height);
}else{
ctx.fillStyle=rect1.color;
ctx.fillRect(rect1.x,rect1.y,rect1.width,rect1.height);
}
}
$("#canvas").mousemove(function(e){handleMouseMove(e);});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
Canvas is only an element.
You can catch event for all canvas not for squares, circle, line...
But you can hold the position of square , line, circle and check "if ( mouse's position in square position) and redraw canvas
Personally, you can try to use SVG and you can catch the events for individual element.