Drawing a circle on the canvas using mouse events - javascript

I am trying to draw a circle using mouse on the canvas using mouse events, but it does not draw anything:
tools.circle = function () {
var tool = this;
this.started = false;
this.mousedown = function (ev) {
tool.started = true;
tool.x0 = ev._x;
tool.y0 = ev._y;
ctx.moveTo(tool.x0,tool.y0);
};
this.mousemove = function (ev) {
var centerX = Math.max(tool.x0,ev._x) - Math.abs(tool.x0 - ev._x)/2;
var centerY = Math.max(tool.y0,ev._y) - Math.abs(tool.y0 - ev._y)/2;
var distance = Math.sqrt(Math.pow(tool.x0 - ev._x,2) + Math.pow(tool.y0 - ev._y));
context.circle(tool.x0, tool.y0, distance/2,0,Math.PI*2 ,true);
context.stroke();
};
};
What am I doing wrong?

Well, this code snippet doesn't tell us much, but there are a couple of obvious errors in your code.
First, DOM Event object doesn't have _x and _y properties. but rather clientX and clientY or pageX and pageY.
To get relative mouse coordinates from the current event object, you would do something like:
element.onclick = function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
}
Next, canvas' 2d context doesn't have a method called circle, but you could write your own, maybe something like:
var ctx = canvas.context;
ctx.fillCircle = function(x, y, radius, fillColor) {
this.fillStyle = fillColor;
this.beginPath();
this.moveTo(x, y);
this.arc(x, y, radius, 0, Math.PI*2, false);
this.fill();
}
Anyhow, here's a test html page to test this out: http://jsfiddle.net/ArtBIT/kneDX/
I hope this helps.
Cheers

Related

Dragging points dynamically content in canvas

I have an application where I need to move the points I created to a certain part of the canvas. How can I do it?
$("#canvas").click(function(e){
getPosition(e);
});
var pointSize = 1;
function getPosition(event){
var rect = canvas.getBoundingClientRect();
var x = event.clientX - rect.left;
var y = event.clientY - rect.top;
console.log(x,y)
drawCoordinates(x,y);
}
function drawCoordinates(x,y){
var ctx = document.getElementById("canvas").getContext("2d");
ctx.fillStyle = "#ff2626"; // Red color
ctx.beginPath();
ctx.arc(x, y, pointSize, 0, Math.PI * 2, true);
ctx.fill();
}
http://jsfiddle.net/bfe8160h/
There's no easy way to drag drawn things on canvas, so you're gonna have to store all points' positions, and redraw the whole canvas.
Something like this:
var points = []
var drag_point = -1
$("#canvas").mousedown(function(e){
var pos = getPosition(e)
drag_point = getPointAt(pos.x,pos.y)
if(drag_point==-1){ // no point at this position, add new point
drawCoordinates(pos.x,pos.y)
points.push(pos)
}
});
$("#canvas").mousemove(function(e){
if(drag_point!=-1){ // if currently dragging a point...
var pos = getPosition(e)
//...update points position...
points[drag_point].x = pos.x
points[drag_point].y = pos.y
redraw() // ... and redraw canvas
}
});
$("#canvas").mouseup(function(e){
drag_point = -1
});
function getPointAt(x,y){
for(var i=0;i<points.length;i++){
if(Math.abs(points[i].x-x)<pointSize && Math.abs(points[i].y-y)<pointSize) // check if x,y is inside points bounding box. replace with pythagoras theorem if you like.
return i
}
return -1 // no point at x,y
}
function redraw(){
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height); // clear canvas
for(var i=0;i<points.length;i++){ // draw all points again
drawCoordinates(points[i].x,points[i].y)
}
}
function getPosition(event){
var rect = canvas.getBoundingClientRect();
var x = event.clientX - rect.left;
var y = event.clientY - rect.top;
return {x:x,y:y}
}
function drawCoordinates(x,y){
var ctx = document.getElementById("canvas").getContext("2d");
ctx.fillStyle = "#ff2626"; // Red color
ctx.beginPath();
ctx.arc(x, y, pointSize, 0, Math.PI * 2, true);
ctx.fill();
}
import
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
and use jquery to drag your div..Example:
$('#divname').draggable();

Resize and move rectangles drawn on canvas

I am allowing the user to draw rectangles on an image. At the same time , the user should be able to resize or move any of the rectangles at any point of time.
With some help, i have been able to draw the rectangles but i am unable to come up with resizing and moving part of it.
The rectangles that are being drawn do not overlap one another and the same has to be validated while resizing and moving too.
I am using javascript and jquery.
This is a demo of what i have done so far :
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var isDown = false;
ctx.strokeStyle = "lightgray";
ctx.lineWidth = 3;
function handleMouseDown(e) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// Put your mousedown stuff here
startX = mouseX;
startY = mouseY;
isDown = true;
}
function handleMouseUp(e) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
$("#uplog").html("Up: " + mouseX + " / " + mouseY);
// Put your mouseup stuff here
isDown = false;
}
function handleMouseMove(e) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// Put your mousemove stuff here
if (!isDown) {
return;
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawRectangle(mouseX, mouseY);
}
function drawRectangle(mouseX, mouseY) {
var width = mouseX - startX;
var height = mouseY - startY;
ctx.beginPath();
ctx.rect(startX, startY, width, height);
ctx.stroke();
}
$("#canvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function (e) {
handleMouseUp(e);
});
as i am running short of time and i am not able to figure out how this can be done.
AFAK, HTML canvas element is simply an array of pixels.
Then drawing/moving/resizing rectangles is, simply again, to keep redrawing canvas.
So first, drawn objects need to be stored (maybe in array).
Second, corresponding mouse events are necessary.
Last, canvas redrawing is required.
Like:
var boxes = [];
var tmpBox = null;
document.getElementById("canvas").onmousedown = function(e) {...};
document.getElementById("canvas").onmouseup = function(e) {...};
document.getElementById("canvas").onmouseout = function(e) {...};
document.getElementById("canvas").onmousemove = function(e) {...};
Here is JSFiddle for demo: https://jsfiddle.net/wiany11/p7hxjmsj/14/
These 2 tutorials explain what you want:
http://simonsarris.com/blog/510-making-html5-canvas-useful
http://simonsarris.com/blog/225-canvas-selecting-resizing-shape
In short you should store the borders of the rectangles yourself and detect when the user clicks in the rectangle or on the border.
First you create an array to store your rectangles in
var rectangles = [];
Then you make a method to call every time you want to draw all your rectangles
function drawRectangles() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for(var i = 0; i < rectangles.length; i++) {
var rect = rectangles[i];
ctx.beginPath();
ctx.rect(rect.startX, rect.startY, rect.endX, rect.endY);
ctx.stroke();
ctx.closePath();
}
}
In your mouseUp you then push the rectangles you have created to the array
function handleMouseUp() {
...
// store the rectangle as an object in your array
var rectangle = {startX: startX, endX: mouseX, startY: startY, endY: mouseY};
rectangles.push(rectangle);
drawRectangles();
}
In your other handlers you can then detect if you click in a rectangle of when your mouse will move in one
You can't just draw objects onto the canvas if you want to move them. You need to create instances of your shape objects and manage those (hit-testing and rendering as required). It is not very complex, but requires a lot more code than you have so far.
Try this tutorial: http://simonsarris.com/blog/510-making-html5-canvas-useful

how can I put multiple objects on the same canvas?

i'm creating a web page where you dynamically draw multiple rectangles. I can draw the single object, but once I tried to draw another one, the previous one is gone away. I tried to save the state using save() and restore(), and it seems that I can't put it here. Isn't it logical that save method is put in the mouseup and restore method is called in the mousedown event? Any help or advice will be appreciated.
const canvas = document.getElementById("circle"),
ctx = canvas.getContext("2d"),
circle = {},
drag = false,
circleMade = false,
mouseMoved = false;
function draw() {
ctx.beginPath();
ctx.arc(circle.X, circle.Y, circle.radius, 0, 2.0 * Math.PI);
ctx.stroke();
}
function mouseDown(e) {
ctx.restore();
circle.startX = e.pageX - this.offsetLeft;
circle.startY = e.pageY - this.offsetTop;
circle.X = circle.startX;
circle.Y = circle.startY;
if (!circleMade) {
circle.radius = 0;
}
drag = true;
}
function mouseUp() {
drag = false;
circleMade = true;
if (!mouseMoved) {
circle = {};
circleMade = false;
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
mouseMoved = false;
ctx.save();
}
function mouseMove(e) {
if (drag) {
mouseMoved = true;
circle.X = e.pageX - this.offsetLeft;
circle.Y = e.pageY - this.offsetTop;
if (!circleMade) {
circle.radius = Math.sqrt(Math.pow((circle.X - circle.startX), 2) + Math.pow((circle.Y - circle.startY), 2));
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
draw();
}
}
function init() {
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
}
init();
you need to save the information about what you are drawing in a separate object, every time you make a draw to the canvas you will wipe and redraw the new object.
so when you clearRect and then draw you are clearing and then drawing a fresh one but the old ones are being left behind. A good example:
var SavedCircles = [];
var circleInfo = function()
{
this.x = 0;
this.y = 0;
this.startX = 0;
this.startY = 0;
this.radius = 0;
}
circle = {};
function draw()
{
for(var x=0;x<SavedCircles.length;x++)
{
ctx.beginPath();
ctx.arc(SavedCircles[x].X, SavedCircles[x].Y, SavedCircles[x].radius, 0, 2.0 * Math.PI);
ctx.stroke();
}
}
function mouseDown()
{
circle = new circleInfo();
}
function mouseUp()
{
SavedCircles.push(circle);
}
function mouseMove()
{
draw();
}
so you can get rid of save and restore, also its much faster to clear a canvas simply by:
canvas.width = canvas.width;
this should help you keep all circles ever drawn. fill in the rest with your code.

Drawing on a canvas using Angular.js

I'm trying to draw a circle wherever the user clicks on the screen using angular on canvas. My code doesn't seem to be working.
Here's my plnk
http://plnkr.co/edit/rYVLgB14IutNh1F4MN6T?p=preview
var app = angular.module('plunker', []);
app.controller('MainController', function($scope) {
//alert("test");
$scope.doClick = function(event){
var x = event.clientX;
var y = event.clientY;
var offsetX = event.offsetX;
var offsetY = event.offsetY;
//alert(x, y, offsetX, offsetY);
//console.log(x, y, offsetX, offsetY);
var ctx = getContext("2d");
//draw a circle
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
};
$scope.test="test";
});
Any help appreciated.
So the problem here is not using canvas correctly.
You need to add an ID, Class or target all canvas elements, In this case I added an ID to your canvas element this way I can target it with document.getElementById
<canvas id="canvas" ng-click="doClick($event)" width="600" height= "600"></canvas>
And in your javascript you weren't targeting the canvas element and applying the context to it.
So this is what your new doubleCLick function will look like:
$scope.doClick = function(event){
var x = event.clientX;
var y = event.clientY;
var offsetX = event.offsetX;
var offsetY = event.offsetY;
alert(x, y, offsetX, offsetY);
/// These are the 2 new lines, see you target the canvas element then apply it to getContext
var canvasElement = document.getElementById("canvas");
var ctx = canvasElement.getContext("2d");
//draw a circle
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
};
I still recommend putting this code in a service.

Simple Button in HTML5 canvas

I am new to Javascript and i am in the process of making a project web based (HTML)
With my basic knowledge i have managed to create a form and drawn a rectangle on it.
I would now like to be able to click the rectangle , using it like a button but I cannot seem to find any tutorials or answers that can help me.
This is the code for my rectangle :
function Playbutton(top, left, width, height, lWidth, fillColor, lineColor) {
context.beginPath();
context.rect(250, 350, 200, 100);
context.fillStyle = '#FFFFFF';
context.fillStyle = 'rgba(225,225,225,0.5)';
context.fillRect(25,72,32,32);
context.fill();
context.lineWidth = 2;
context.strokeStyle = '#000000';
context.stroke();
context.closePath();
context.font = '40pt Kremlin Pro Web';
context.fillStyle = '#000000';
context.fillText('Start', 345, 415);
}
I am aware that you need to find the x,y coordinates and mouse position in order to click in the area of the rectangle. But i'm really stuck at this point.
It maybe really simple and logic, but we have all had to go past this stage.
You were thinking in the right direction.
You can solve this multiple ways like using html button suggested in the comments.
But if you do need to handle click events inside your canvas you can do something like this:
Add a click handler to the canvas and when the mouse pointer is inside your bounding rectangle you can fire your click function:
//Function to get the mouse position
function getMousePos(canvas, event) {
var rect = canvas.getBoundingClientRect();
return {
x: event.clientX - rect.left,
y: event.clientY - rect.top
};
}
//Function to check whether a point is inside a rectangle
function isInside(pos, rect){
return pos.x > rect.x && pos.x < rect.x+rect.width && pos.y < rect.y+rect.height && pos.y > rect.y
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
//The rectangle should have x,y,width,height properties
var rect = {
x:250,
y:350,
width:200,
height:100
};
//Binding the click event on the canvas
canvas.addEventListener('click', function(evt) {
var mousePos = getMousePos(canvas, evt);
if (isInside(mousePos,rect)) {
alert('clicked inside rect');
}else{
alert('clicked outside rect');
}
}, false);
jsFiddle
Path2d may be of interest, though it's experimental:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/isPointInPath
Basically, you'd do all of your drawing into a Path, and use the .isPointInPath method to do the checking. For a rectangle like you're describing, you can do that math pretty simply, but the glory of this is you can have a complex path set up, and it will do the collision detection for you:
//get canvas/context
const canvas = document.getElementById("myCanvas")
const context = canvas.getContext("2d")
//create your shape data in a Path2D object
const path = new Path2D()
path.rect(250, 350, 200, 100)
path.rect(25,72,32,32)
path.closePath()
//draw your shape data to the context
context.fillStyle = "#FFFFFF"
context.fillStyle = "rgba(225,225,225,0.5)"
context.fill(path)
context.lineWidth = 2
context.strokeStyle = "#000000"
context.stroke(path)
function getXY(canvas, event){ //adjust mouse click to canvas coordinates
const rect = canvas.getBoundingClientRect()
const y = event.clientY - rect.top
const x = event.clientX - rect.left
return {x:x, y:y}
}
document.addEventListener("click", function (e) {
const XY = getXY(canvas, e)
//use the shape data to determine if there is a collision
if(context.isPointInPath(path, XY.x, XY.y)) {
// Do Something with the click
alert("clicked in rectangle")
}
}, false)
jsFiddle

Categories