HTML5 Canvas circles on click - javascript

I've been playing around with the HTML5 canvas lately and one of the things I've wanted to do is create a simple page with a canvas that'll draw a circle wherever you click. I have some code that looks like it should work, and I've been attempting to debug with some console output, but I've been unable to see any errors at the moment.
I'm using Codepen though, so I'm unsure how fully featured that console is, and I unfortunately can't use the dev console on my laptop at the moment (locked down school Chromebook).
Could someone take a look? I'll put the code in here and drop a link to the pen as well. Thanks!
HTML:
<canvas id="canvas" onclick="drawCircle(event)"></canvas>
CSS:
canvas {
position: relative;
background: #f1c40f;
width: 100%;
height: 100%;
}
JS:
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
function drawCircle(e) {
var pos = getCursorPosition(c, e);
var clickX = pos.x;
var clickY = pos.y;
ctx.fillStyle = "#2980b9";
ctx.beginPath();
ctx.arc(clickX, clickY, 10, 0, 2 * Math.PI);
ctx.fill();
console.log(clickX, clickY);
console.log("drawcircle");
}
function getCursorPosition(canvas, e) {
// Gets click position
rect = canvas.getBoundingClientRect();
console.log('getcursorpos');
return {
x: e.clientX - rect.left,
y: e.clientY - rect.top
};
}
Codepen link: https://codepen.io/wolverine1621/pen/gWvjgx
Any help is appreciated. It's probably something pretty simple but this is really my first time working with canvas, so any input is helpful!
Thanks!

The issue is occurring because, you set the canvas's width and height using css.
You should rather set it using javascript, like so ...
c.width = window.innerWidth;
c.height = window.innerHeight;
and to make the canvas flexible, so that it maintains it's size, use ...
window.onresize = function() {
c.width = window.innerWidth;
c.height = window.innerHeight;
}
Here is the working codepen

A couple of things:
1) you are not setting a width and height for your canvas, so there is going to be distortion and the x/y values are going to be weird. Solution: set the width and height of the canvas to the window height and width
2) Your method for determining clickX and clickY is overly complicated. Solution: use event.clientX and event.clientY
After getting your context, set the width and height:
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
Note: I would also encourage you to remove the margin on the body in CSS
body { margin: 0 }
Now you can get rid of getCursorPosition (because it is giving you wrong values)
var clickX = e.clientX
var clickY = e.clientY

Related

Canvas, diagonal lines are thicker

i have following problem. Im trying to draw a border with notches on my buttons and slider. thats working fine. but i noticed that my diagonal lines are twice as thick as the normal ones.
I saw that i have to work on the width/height settings in the canvas/tag itself. but i cant get it working!
Maybe i dont understand realy to make it work. pls help :)
button_canvas_border
slider_canvas_border
thats my html
<canvas width="1290" height="738" class="slider_canvas" id="slider_canvas" ></canvas>
or
<canvas class="slider_canvas" id="slider_canvas" ></canvas>
both dont work
and my js
jQuery(document).ready(function($) {
$('.slider_canvas').each(function(index, canvas) {
var wrapper_height = $('.nsaw_slider_front_wrapper').height() + 30;
var wrapper_width = $('.nsaw_slider_front_wrapper').width() + 30;
/* doesnt matter what i do on the below, its just not working */
canvas.width = wrapper_width;
canvas.height = wrapper_height;
canvas.style.width = wrapper_width;
canvas.style.height = wrapper_height;
canvas.setAttribute('width', wrapper_width);
canvas.setAttribute('height', wrapper_height);
/* doesnt matter what i do on the above, its just not working */
var point_01_cord = wrapper_width * 0.85;
var point_02_cord = wrapper_height * 0.25423;
var point_03_cord = wrapper_width * 0.15;
var point_04_cord = wrapper_height * 0.74577;
var ctx = canvas.getContext('2d');
var gradient = ctx.createLinearGradient(0, 0, 170, 0);
gradient.addColorStop("0", "#0033ff");
gradient.addColorStop("1" ,"#ffff00");
ctx.strokeStyle = gradient;
ctx.lineWidth = 5;
ctx.beginPath();
ctx.translate(0.5,0.5);
ctx.moveTo(0,0);
ctx.lineTo(point_01_cord,0);
ctx.lineTo(wrapper_width,point_02_cord);
ctx.lineTo(wrapper_width,wrapper_height);
ctx.lineTo(point_03_cord,wrapper_height);
ctx.lineTo(0,point_04_cord);
ctx.lineTo(0,0);
ctx.stroke();
});
});
maybe someone can help :)
Strokes do overlap from both sides of the coordinates, that's by the way why you saw some say you should translate by 0.5, so that lineWidth = 1 covers a full pixel instead of two halves. (More on that here).
Here you are drawing a 5px wide line so you really don't want that offset (5 pixels can be rendered perfectly fine), even though it's not your actual problem here.
Your drawing is at the edges of the canvas boundaries. This means that only half of your line is visible.
To workaround that, offset all your lines coordinates to take into account its lineWidth. For instance the top line instead of having its y values set to 0 should have it set to 2.5 without the initial translate or to 2 with if you really want to keep it.

how to make the fixed content with position(x,y)on the canvas responsive with mobile device? using h5 and javascript

i use something below to make my canvas responsive, and it is accutlly works fine but only for the image that draw on the canvas, the problem is that i also added some slot on the canvas as condition to tell if the mouseclick on the right place(use addeventlisenter('click')).after scale the canvas all this slot become doesn't work, anyone can give some suggestion on how to achieve my goal? Thanks in advance.
for example:i set a slot[x:185,y:290,w:70,h:70], if the mouseclick in the slot, it will trigger some other event,but after make the canvas responsive, this function doesn't work.
var c=document.getElementById("canvas");
var ctx = c.getContext("2d");
function resizecanvas(){
var height = window.innerHeight;
var ratio = c.width / c.height;
var width = height * ratio;
c.style.width = width + 'px';
c.style.height = height + 'px';
}
window.addEventListener('load',resizecanvas,false);
window.addEventListener('resize', resizecanvas, false);

get canvas mouse position on canvas

** Read before you mark as duplicate! **
Getting the mouse position on the canvas nearly works fine.
My window size is 800 x 600
My canvas size is 400 x 300:
canvas.width = 400;
canvas.height = 300;
My canvas css size is 100% x 100%:
canvas {width: 100vw; height: 100vh;}
The problem is: if my mouse is in the middle of the canvas I get this mouse position: 400, 300. If my window size was 1600 x 1200 I would get 800, 600.
I would like to get the canvas position of the mouse. What I mean by this, is I'm looking to get 200, 150, regardless of the window size.
How would I do this?
Thank's for the help.
You have to create conversion from model coordinates to screen coordinates and back. Here is good explanation for it: http://www.ckollars.org/canvas-two-coordinate-scales.html
You could paste this into your code.
document.getElementById("canvasId").addEventListener('mousemove',function(event){mousePos(event);});
function getMousePos(e){
var rect = canvas.getBoundingClientRect();
//this gets your canvas size.
return {
x: Math.round(e.clientX - rect.left),
y: Math.round(e.clientY - rect.top)
};
function mousePos(e){
var pos = getMousePos(e);
var mouseX = pos.x;
var mouseY = pos.y;
}
then you could just reference the mouseX and mouseY somewhere else.
//enter the rest of your code here.

How to increase the resolution of lines in canvas

window.onload=function(){
var c = document.getElementById('canvas'),
ctx = c.getContext('2d'),
x=0, y=0, cnt=1;
for(var i=0;i<(window.innerWidth)/10;i++){
ctx.moveTo(x, y); x+=5;
if(cnt%2){
y=5; cnt++;
ctx.lineTo(x, y);ctx.stroke();
}else{
y=0; cnt++;
ctx.lineTo(x, y);ctx.stroke();
}
}
}
<canvas id="canvas" style="width:100%; height:250px"></canvas>
If you run the above code then the resolution of lines in the zig-zag pattern in the if fine but in here you can see the image the resoultion of this pattern is very poor (please click on this image to view this problem):
what i have tried is that i have changed the condition (window.innerWidth)/10 to (winodw.innerWidth)/4 and x+=5 to x+=2
but what it does is that it makes the line so thick and bad that you don't want to see it.
so, what should i do to increase the resolution of the lines of the pattern?
Just make sure your canvas element is as big as you are displaying it.
i added c.width = windows.innerWidth and also c.heigth = 250 and the resolution looks correct now.
window.onload=function(){
var c = document.getElementById('canvas'),
ctx = c.getContext('2d'),
x=0, y=0, cnt=1;
c.width = window.innerWidth;
c.height = 250;
for(var i=0;i<(window.innerWidth);i++){
ctx.moveTo(x, y); x+=5;
if(cnt%2){
y=5; cnt++;
ctx.lineTo(x, y);ctx.stroke();
}else{
y=0; cnt++;
ctx.lineTo(x, y);ctx.stroke();
}
}
}
<canvas id="canvas" style="width:100%; height:250px"></canvas>
There are a couple of things, but mostly it comes down to this: you are drawing at a width of 100%, which is stretching the default size of a canvas you are drawing in - thats why it blurs. Set your width correctly using javascript and the sharpness increases. The only thing is, a difference of 5 pixels is barely noticeable, so you have to increase your size to something more... average. I have opted for 1/100 of the windows width, but you can turn it into anything.
// For safety, use event listeners and not global window method overwriting.
// It will become useful if you have multiple scripts you want to
// execute only after loading them!
window.addEventListener('DOMContentLoaded', function(){
var c = document.getElementById('canvas'),
ctx = c.getContext('2d'),
x = 0, y = 0;
// Set the correct width and height
c.width = window.innerWidth;
c.height = window.innerWidth / 100;
// Use moveTo once, then keep drawing from your previous lineTo call
ctx.moveTo(x, y);
// You only need your x value here, once we are off screen we can stop drawing and end the for loop!
for(; x < window.innerWidth; x += window.innerWidth / 100){
// Use lineTo to create a path in memory
// You can also see if your y needs to change because y = 0 = falsy
ctx.lineTo(x, (y = y ? 0 : window.innerWidth / 100));
}
// Call stroke() only once!
ctx.stroke();
// And for safety, call closePath() as stroke does not close it.
ctx.closePath();
}, false);
<canvas id="canvas"></canvas>
<!-- Remove all styling from the canvas! Do this computationally -->
maybe you can find your ans here
Full-screen Canvas is low res
basically it summarizes that instead of setting height and width in the css, you should set it via html (inside the canvas element via width and height attr) or via javaScript.
because when doing it in css, you are basically scaling it and thus reducing the resolution, so you have to mention the actual size in html element and not scale it in css.

Make canvas line show

Ok, here is something simple, I hope. I've a div container in which I can click and what I'm trying to do is to create two perpendicular lines which cross each other where I've clicked. So far I've written those:
#fr{
float: right;
margin-top: 5%;
height: 720px;
width: 1280px;
position: relative;
background-image: url(blueboard.jpg);
border: 1px solid black;
clear:none;
}
canvas{
border:1px solid red;
float: right;
height: 720px;
width: 1280px;
clear:none;
}//css part, I actually place the canvas on top of my div
//and on html...
<canvas id="line"></canvas>
//js
function saveOO(e){
var xo, yo;
xo=e.clientX;
yo=e.clientY;
...
document.getElementById("saved").innerHTML="The (0;0) = " +"("+xo+";"+yo+")";
document.getElementById("ball").style.left=xo+'px';
document.getElementById("ball").style.top=yo+'px';
xylines(xo, yo);
...;
}
function lines(xo, yo){
var xo, yo, xl, xline, yl, yline, Dx, Dy, a, b, c, d, e;
xo=xo;
yo=yo;
a=$("#fr").position();
b=$("#fr").width();
c=$("#fr").height();
Dy=a.top+100;
Dx=a.left;
d=Dx+b;
e=Dy+c;
xline = document.getElementById("line");
xl=xline.getContext("2d");
xl.beginPath();
xl.moveTo(Dx,yo);
xl.lineTo(d,yo);
xl.lineWidth = 15;
xl.stroke();
yline = document.getElementById("line");
yl=yline.getContext("2d");
yl.beginPath();
yl.moveTo(xo,Dy);
yl.lineTo(xo,e);
yl.lineWidth = 15;
yl.stroke();}
I have, as well, checked whether all variables assign a value and everything is good with that. The crossing point should be exactly where the blue ball is, it also positions on the place where it's clicked. As you can see on the image no lines show, even if I remove the blue background. Please, help me, maybe something is missing. I'm looking forward to your answers.
:)
P.S. Dy is Y of the top left corner, Dx respectively X of the top left corner
Update 2
A slightly amended fiddle where the lines span the entire width/height of the canvas:
https://jsfiddle.net/0y37qwvw/5/
This is by using 0 as the starting point for each and canvas.width/canvas.height as the ending point.
Update
Here is a fiddle demonstrating the use of a canvas overlay and responding to a click events.
https://jsfiddle.net/0y37qwvw/4/
The important thing is to get the relative x and y co-ordinates right, which I have done using event.offsetX and event.offsetY and a fallback for when they are not implemented:
document.getElementById("canvas-overlay").addEventListener("click", function( event ) {
var x, y, clientRect;
clientRect = event.target.getBoundingClientRect();
x = (typeof event.offsetX !== 'undefined' ? event.offsetX : (event.clientX - clientRect.left));
y = (typeof event.offsetY !== 'undefined' ? event.offsetY : (event.clientY - clientRect.top));
lines(x, y, 50, 50);
}, false);
Original answer
Your code is incomplete, so it is hard to be sure what the exact problems are.
One problem though is that you have not directly set the width and height of the canvas element, which will result in the canvas being scaled.
You can do this on the canvas element:
<canvas id="line" height="720" width="1280"></canvas>
Demonstrated at:
https://jsfiddle.net/0y37qwvw/1/
You could also set the width and height programmatically:
var canvas = document.getElementById("line");
canvas.width = 1280;
canvas.height = 720;
https://jsfiddle.net/0y37qwvw/3/
Compare to what happens if the width and height are only set by CSS:
https://jsfiddle.net/0aph7yno/
If you still can't get it to work, set up a plunker/fiddle with the broken code.
Here is some code I have written, I tried to use as much as OOP style so it's easier to expand it. But still simple and clear.
http://jsfiddle.net/eeqhc2tn/2/
var canvas = document.getElementById('can');
var ctx = canvas.getContext('2d');
var drawThese = [];
canvas.width = 500;
canvas.height = 500;
render();
//Line Code
function Line(sx, sy, ex, ey) {
this.sx = sx;
this.sy = sy;
this.ex = ex;
this.ey = ey;
}
Line.prototype.draw = function () {
ctx.beginPath();
ctx.moveTo(this.sx, this.sy);
ctx.lineTo(this.ex, this.ey);
ctx.stroke();
};
Line.drawCrossLines = function (x, y) {
var horizontal = new Line(0, y, canvas.width, y);
var vertical = new Line(x, 0, x, canvas.height);
drawThese.push(horizontal);
drawThese.push(vertical);
}
canvas.addEventListener('click', function (e) {
Line.drawCrossLines(e.offsetX, e.offsetY);
});
//Circle code
function Circle(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
}
Circle.prototype.draw = function () {
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI);
ctx.fill();
};
//Moving Circle Code that extends Circle
function MovingCircle() {
Circle.call(this,0,0,10);
}
MovingCircle.prototype = Object.create(Circle.prototype);
MovingCircle.prototype.constructor = MovingCircle;
MovingCircle.prototype.move = function (x, y) {
this.x = x;
this.y = y;
}
var pointer = new MovingCircle();
drawThese.push(pointer);
canvas.addEventListener('mousemove',function(e){
pointer.move(e.offsetX, e.offsetY);
});
//Rendering and animation code
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawThese.forEach(function (e) {
e.draw();
});
requestAnimationFrame(render);
}
I've found a working solution on my own, of course inspired by rpn. If you would like to make same or similar thing to what I this topic is about, a system including a container, canvas and a mouse event (click, in this case) you will have to follow this steps.
1. You cannot draw directly to a div, you've to create something like an invisible overlay for canvas and to place it perfectly over the div.
2. An important part is getting the proper coordinates, take into account that there are some tad but important differences between the various coords get methods. (`clientX/Y`, `offsetX/Y` and so on). It matters a lot.
3. Last but not at least, you should carefully consider how you get container's dimensions, as you'll need them later. Remember! We are in a container, a.k.a. working with an area which is just part of the whole window (your browser).
At first I was receiving my coordinates with clientX/Y but maybe due to some mismatches between the get method for coordinates and the one for div's dimensions I was hammered by bugs. To solve this, I've created a method from which I take mouse click coordinates with offsetX/Y. This way you have to think of you container as if it is a separate coordinate system, different from your window's(which by default is general). This means that now the top left corner of this div has x:y = (0;0);
function getcooords(){
xo = e.offsetX;
yo = e.offsetY;
DrawLines(x0, y0); //invoke func DrawLines
}
Now we go to the moment where we should draw our lines.
function DrawLines(x0,y0){
//your variables here...
w=$("#yourcontainer").width();
h=$("#yourcontainer").height();
Dy=0;
Dx=0;
}
That's the second step, Dx and Dy are the top and left properties of the div. Hence, from the what I've just said above, they will be equal to 0, both. Width and height of the container I take simply with jq but you can do it on another preferred way.
Generally speaking, that's the core of your drawing algorithm after we've taken needed dimensions and coordinates:
xl.beginPath();
xl.moveTo(b,yo);//start point of line
xl.lineTo(Dx,yo);//end point of line
xl.stroke(); //DRAW IT :)
Now, I've forgot to tell you that you have to define your lines at first, where should they be, what properties, styles should they have, etc..:
var xline = document.getElementById("line");
xl=xline.getContext("2d");
Remember! If you would like to delete, to erase the what you've drawn you'd have to define your lines FIRST and delete them after their definition. I'm saying definition, not drawing and you can draw the next 1, 2, 3... n lines and delete them over and over again if you follow this principle.
That's it guys, I hope I've explained it well, sorry for my English, probably I've made some tad mistakes but I hope you understand me. If you have any questions, please feel free to ask me, I'll try to do my best in order to help you.
:)

Categories