is mouse in user drawn area on canvas - html

Basically, a user uploads a picture and then can paint on it, and save the result. Another user can then view the photo and if they click in the same area as painted, something happens.
So user 1 can make an area click-able for user 2 by drawing on the photo.
now the upload bit is fine, and painting with help from a tutorial and example I've got sussed out. But defining what area is click-able is a bit harder. For something like a rectangle its easy enough, I made an example.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var button = new Object();
button.x = 50;
button.y = 50;
button.width = 50;
button.height = 50;
button.rgb = "rgb(0, 0, 255)";
function drawbutton(buttonobject)
{
context.fillStyle = buttonobject.rgb;
context.fillRect (buttonobject.x, buttonobject.y, buttonobject.width, buttonobject.height);
context.strokeRect(buttonobject.x, buttonobject.y, buttonobject.width, buttonobject.height);
}
drawbutton(button);
function checkIfInsideButtonCoordinates(buttonObj, mouseX, mouseY)
{
if(((mouseX > buttonObj.x) && (mouseX < (buttonObj.x + buttonObj.width))) && ((mouseY > buttonObj.y) && (mouseY < (buttonObj.y + buttonObj.height))))
return true;
else
return false;
}
$("#myCanvas").click(function(eventObject) {
mouseX = eventObject.pageX - this.offsetLeft;
mouseY = eventObject.pageY - this.offsetTop;
if(checkIfInsideButtonCoordinates(button, mouseX, mouseY))
{
button.rgb = "rgb(0, 255, 0)";
drawbutton(button);
} else {
button.rgb = "rgb(255, 0, 0)";
drawbutton(button);
}
});
but when it comes to other shapes like circles, or just someone smothering the page, how would you go about detecting that ?
one thought I had was using the edited layer, making it hidden, and detecting a pixel color of say blue, from here but that limits the color use of the photo and im not entirely sure how to implement it. any other ideas ?
EDIT:
I figured out circles after some tinkering, using Pythagoras theorem to see if mouse coordinates are smaller than the radius, but this assumes circle center of 0,0, so then offset mouse by circles actual center. example
function checkIfInsideButtonCoordinates(buttonObj, mouseX, mouseY) {
actualX = mouseX - buttonObj.x
actualY = mouseY - buttonObj.y
mousesqX = actualX * actualX
mousesqY = actualY * actualY
sqR = buttonObj.r * buttonObj.r
sqC = mousesqX + mousesqY
if (sqC < sqR) return true;
else return false;
}

Here’s how to test whether user#2 is inside user#1’s paintings
Create a second canvas used to hit-test whether user#2 is inside of user#1’s paintings.
The hit-test canvas is the same size as the drawing canvas, but it only contains user#1’s paintings…not the image.
When user#1 is painting, also draw their paintings on the hit canvas.
When user#1 is done painting, save all their paintings from the hit canvas.
You have at least 2 ways to save user#1’s paintings from the hit canvas:
Serialize all the canvas commands needed to recreate the shapes/paths that user#1 paints.
Save the hit canvas as an image using canvas.toDataURL.
When user#2 clicks, check if the corresponding pixel on the hit canvas is filled or is transparent (alpha>0).
// getImageData for the hit-test canvas (this canvas just contains user#1's paintings)
imageDataData=hitCtx.getImageData(0,0,hit.width,hit.height).data;
// look at the pixel under user#2's mouse
// return true if that pixel is filled (not transparent)
function isHit(x,y){
var pixPos=(x+y*hitWidth)*4+3;
return( imageDataData[pixPos]>10)
}
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/etA5a/
<!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; padding:15px; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var hit=document.getElementById("hit");
var hitCtx=hit.getContext("2d");
var user2=document.getElementById("user2");
var ctx2=user2.getContext("2d");
var canvasOffset=$("#user2").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var imageDataData;
var hitWidth=hit.width;
var img=document.createElement("img");
img.onload=function(){
// left canvas: image+user#1 paintings
ctx.globalAlpha=.25;
ctx.drawImage(img,0,0);
ctx.globalAlpha=1.00;
scribble(ctx,"black");
// mid canvas: just user#1 paintings (used for hittests)
scribble(hitCtx,"black");
// right canvas: user#2
ctx2.drawImage(img,0,0);
imageDataData=hitCtx.getImageData(0,0,hit.width,hit.height).data;
}
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/colorhouse.png";
function scribble(context,color){
context.beginPath();
context.moveTo(70,2);
context.lineTo(139,41);
context.lineTo(70,41);
context.closePath();
context.rect(39,54,22,30);
context.arc(73,115,3,0,Math.PI*2,false);
context.fillStyle=color;
context.fill();
}
function handleMouseMove(e){
var mouseX=parseInt(e.clientX-offsetX);
var mouseY=parseInt(e.clientY-offsetY);
// If user#2 has a hit on user#1's painting, mid-canvas turns red
var color="black";
if(isHit(mouseX,mouseY)){ color="red"; }
scribble(hitCtx,color);
}
function isHit(x,y){
var pixPos=(x+y*hitWidth)*4+3;
return( imageDataData[pixPos]>10)
}
$("#user2").mousemove(function(e){handleMouseMove(e);});
}); // end $(function(){});
</script>
</head>
<body>
<p>Left: original image with user#1 painting</p>
<p>Mid: user#1 painting only (used for hit-testing)</p>
<p>Right: user#2 (move mouse over hit areas)</p>
<canvas id="canvas" width=140 height=140></canvas>
<canvas id="hit" width=140 height=140></canvas>
<canvas id="user2" width=140 height=140></canvas><br>
</body>
</html>

Related

HTML Canvas, How do you create a circle at the position of the mouse when clicked and then for the circle to increase in radius?

So, I have tried attempting this myself and have searched heavily online and I can't seem to solve this particular issue. I am attempting to make a very simple effect that looks like a very basic water ripple. I intend for the user to be able to click somewhere on the canvas, and for an empty circle (with a black stroke) to appear where the mouse has clicked (starting at a radius of zero), and continuously expand the radius as an animation.
I currently have this code:
<!DOCTYPE html>
<html>
<head>
<!-- Search Engine Optimisation (SEO) -->
<title> Ripple </title>
<meta description="Codelab assignment 3">
<meta keywords="Uni, assignment, ripple, interactive, discovery">
<!-- End of Metadata -->
<!-- Links -->
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<canvas id="myCanvas" width="1024" height="768" style="border: 1px solid"></canvas>
</body>
<script type="text/javascript">
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var radius = 0;
//Have a rectangle fill the canvas and add a hit region
//Call the ripple function from the rectangle function
//Track mouse position in rectangle
function ripple(e) {
// ctx.clearRect(0, 0, canvasWidth, canvasHeight);
ctx.beginPath();
ctx.arc(e.clientX,e.clientY,radius,0,2*Math.PI);
//ctx.closePath();
ctx.stokeStyle = "black";
ctx.stroke();
radius++;
requestAnimationFrame(ripple);
}
canvas.addEventListener('mousedown', ripple);
</script>
</html>
This is what it currently does:
Screenshot
I really appreciate any help!
You'd have to pass the mouse event when calling the ripple function through requestAnimationFrame.
also, you'll need to set the radius to 0 and clear running animation frame (if any) on mouse click
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var radius = 0;
var rAF;
function ripple(e) {
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
ctx.beginPath();
ctx.arc(e.offsetX, e.offsetY, radius, 0, 2 * Math.PI);
ctx.stokeStyle = "black";
ctx.stroke();
radius++;
rAF = requestAnimationFrame(function() {
ripple(e);
});
}
canvas.addEventListener('mousedown', function(e) {
if (rAF) cancelAnimationFrame(rAF);
radius = 0;
ripple(e);
});
body{margin:10px 0 0 0;overflow:hidden}canvas{border:1px solid #ccc}
<canvas id="canvas" width="635" height="208"></canvas>
note: use e.offsetX and e.offsetY to get proper mouse coordinates relative to canvas.

Canvas animation using png file

I am trying to make a racing game using canvas, and a png file with transparent background for the car.
I have a problem when I hold down on one of the arrows. In the opposite way of the movement it appears like a white shadow the old position of the car.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
var canvas;
var ctx;
var car = new Image();
var x = 0;
var y = 0;
function startUp(){
canvas = document.getElementById('myCanvas');
ctx = canvas.getContext('2d');
loadImages();
startGameLoop();
}
function startGameLoop() {
setInterval(function() {
drawScreen();
drawCar();
}, 16);
window.addEventListener('keydown', whatKey, true);
}
function drawScreen(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#aaaaaa';
ctx.rect(0, 0, canvas.width, canvas.height);
ctx.fill();
}
function drawCar(){
ctx.drawImage(car, x ,y, 200, 103);
}
function whatKey(evt) {
switch (evt.keyCode) {
// Left arrow.
case 37: {
x -= 15;
}
break;
// Right arrow.
case 39:{
x += 15;
}
break;
// Down arrow
case 40:{
y += 15;
}
break;
// Up arrow
case 38: {
y -= 15;
}
break;
}
}
function loadImages() {
car.src = 'http://sammywasem.com/images/f3-top.png';
}
</script>
</head>
<body onload="startUp()">
<canvas id="myCanvas" width="1050" height="620">
</canvas>
</body>
</html>
The car move is in fact the right way.
Say you press the right key : the event is sent to the window, and trapped by your code : the car goes right. But the event is also handled by the whole window, where it is understood as : move the window to the right.
So what you see in the end, since the window move more than the car, is a move to the left of the car.
What you need to do is to prevent the key event from bubbling further once you handled it : it is done with
event.preventDefault();
and
event.stopPropagation();
look mdn to see the specifications of preventDefault or stopPropagation .
i've done a fiddle out of your code, and updated it :
http://jsbin.com/joboxuvu/1/edit?js,output

How set a identification to Canvas Path?

Good morning everyone.
I'm building a graph for the enterprise system where I work, but I came across a problem where I need to insert some kind of identification, that I may be rescued by JavaScript (name, id, label, ...).
Someone could tell me how I could do to identify each element of the graph separately? To be more exact, what I'm wondering identifies each element arc is created.
If someone wanted to see the code to understand it better, I'll put the link here:
- JS Bin
Nothing you draw on the canvas is automatically remembered or labeled with an id.
All canvas drawings become forgotten and inaccessible pixels. However there are ways of keeping track of your various drawings.
Instead of keeping your posX,posY and color info in separate parallel arrays, how about creating an object for each node.
Then you could add the id property to each node object:
var nodes=[];
nodes.push({id:"sun", x:100, y:100, color:"yellow"});
nodes.push({id:"earth", x:50, y:50, color:"blue"});
nodes.push({id:"moon", x:50, y:60, color:"gray"});
And, of course, pull the graphing info from each node...
You can draw your graph inside a function and apply a scaleFactor when needed.
function drawGraph(){
context.clearRect(0,0,canvas.width,canvas.height);
context.save();
context.scale(scaleFactor,scaleFactor);
for(var i=0; i<nodes.length;i++){
var node=nodes[i];
context.beginPath();
context.moveTo(centerCanvasX,centerCanvasY);
context.lineTo(node.x,node.y);
context.stroke();
context.beginPath();
context.arc(node.x,node.y,node.radius,0,Math.PI*2,false);
context.closePath();
context.stroke();
context.fillStyle=node.color;
context.fill();
}
context.restore();
}
For dragging/clicking/etc, You could hit test each node array element until you found a match.
function hit(x,y){
for(var i=0;i<nodes.length;i++){
var node=nodes[i];
var dx=node.x-x;
var dy=node.y-y;
var rr=node.radius;
if(dx*dx+dy*dy<rr*rr){
return(i);
}
}
return(-1);
}
The matching element would have the id you need.
If your graph is scaled and you're using mouse coordinates to drag, you must adjust the coordinates that the browser gives you by the current scaleFactor of your graph:
mouseX=parseInt(event.clientX-offsetX)/scaleFactor;
mouseY=parseInt(event.clientY-offsetY)/scaleFactor;
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/c4hsW/
<!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; padding:20px; }
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var context=canvas.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var centerCanvasX=canvas.width/2;
var centerCanvasY=canvas.height/2;
var startX;
var startY;
var isDown=false;
var nodes=[];
var dragNode;
var scaleFactor=1.00;
nodes.push({id:"sun", x:centerCanvasX, y:centerCanvasY, radius:20, color:"yellow"});
nodes.push({id:"earth", x:50, y:50, radius:5, color:"blue"});
nodes.push({id:"moon", x:50, y:65, radius:3, color:"gray"});
drawGraph();
function drawGraph(){
context.clearRect(0,0,canvas.width,canvas.height);
context.save();
context.scale(scaleFactor,scaleFactor);
for(var i=0; i<nodes.length;i++){
var node=nodes[i];
context.beginPath();
context.moveTo(centerCanvasX,centerCanvasY);
context.lineTo(node.x,node.y);
context.stroke();
context.beginPath();
context.arc(node.x,node.y,node.radius,0,Math.PI*2,false);
context.closePath();
context.stroke();
context.fillStyle=node.color;
context.fill();
}
context.restore();
}
function hit(x,y){
for(var i=0;i<nodes.length;i++){
var node=nodes[i];
var dx=node.x-x;
var dy=node.y-y;
var rr=node.radius;
if(dx*dx+dy*dy<rr*rr){
return(i);
}
}
return(-1);
}
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX)/scaleFactor;
mouseY=parseInt(e.clientY-offsetY)/scaleFactor;
var i=hit(mouseX,mouseY);
if(i>=0){
startX=mouseX;
startY=mouseY;
isDown=true;
dragNode=nodes[i];
}
}
function handleMouseUp(e){
isDown=false;
}
function handleMouseOut(e){
isDown=false;
}
function handleMouseMove(e){
if(!isDown){return;}
// get the current mouse position
mouseX=parseInt(e.clientX-offsetX)/scaleFactor;
mouseY=parseInt(e.clientY-offsetY)/scaleFactor;
// reposition the dragged node
dragNode.x+=(mouseX-startX);
dragNode.y+=(mouseY-startY);
startX=mouseX;
startY=mouseY;
// redraw the graph
drawGraph();
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
$("#bigger").click(function(){
scaleFactor+=0.20;
drawGraph();
});
$("#smaller").click(function(){
scaleFactor-=0.20;
drawGraph();
});
}); // end $(function(){});
</script>
</head>
<body>
<button id="bigger">Scale Up</button>
<button id="smaller">Scale Down</button><br>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

move, delete and retrieve added rectangles positions in a HTML5 canvas

I have this code below to add a rectangle to a canvas, I have some questions regarding this.
Is it possible to move the added rectangle after it has been created?
Is it possible to delete a rectangle that has been added?
Can I retrieve all added rectangles positions (x, y, width and height) after I have added a bunch of rectangles and lets say by click of a button?
<script>
function rect()
{
var canvas = document.getElementById('drawing'),
ctx = canvas.getContext('2d'),
rect = {},
drag = false;
function init() {
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
}
function mouseDown(e) {
rect.startX = e.pageX - this.offsetLeft;
rect.startY = e.pageY - this.offsetTop;
drag = true;
}
function mouseUp() {
drag = false;
}
function mouseMove(e) {
if (drag) {
rect.w = (e.pageX - this.offsetLeft) - rect.startX;
rect.h = (e.pageY - this.offsetTop) - rect.startY ;
//ctx.clearRect(0,0,canvas.width,canvas.height);
draw();
}
}
function draw() {
ctx.globalAlpha=0.5; // Half opacity
ctx.fillStyle= "#b0c2f7";
//ctx.fillStyle = "rgba(255, 255, 255, 0.05)";
ctx.fillRect(rect.startX, rect.startY, rect.w, rect.h);
}
init();
}
</script>
<div id="canvasDiv">
<canvas id="drawing" width="580px" height="788px" style="border:2px solid #000; background: #FFF;"></canvas>
</div>
<script>
var canvas = document.getElementById('drawing');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 69, 50);
};
imageObj.src = 'http://localhost/test/Images/DSC0273446.jpg';
</script>
<div id="rect">
<p><button onclick="rect();">Rectangle</button></p>
</div>
Really appreciate all help I can get in this matter, thanks!
Is it possible to move the added rectangle after it has been created?
No, once drawn it is just pixels, there is no 'rectangle object' in the canvas. The usual approach to 'moving' a shape in canvas is to clearRect() (or the whole canvas) and then fillRect() in a slightly different position in a requestAnimationFrame controlled loop.
Is it possible to delete a rectangle that has been added?
As long as you've stored the location where you drew it, you can clearRect(). Note that this clears an area of pixels, not an object - the results of previous drawing operations will not automatically reappear.
Can I retrieve all added rectangles positions (x, y, width and height) after I have added a bunch of rectangles and lets say by click of a button?
No. The canvas does not store drawn objects, only pixel image data. If you want to keep track of the objects that have been drawn then you have to do that yourself. If you want to manipulate shapes instead of pixels then there are libraries like fabric.js which add an object manipulation layer on top of canvas, or you can use an svg element instead which will let you create graphics with normal DOM methods.

Mouse Coordinates in HTML5 Canvas

I have tried many different ways of trying to get mouse coordinates in HTML5 canvas in compliment with video and none have seemed too work very well in either Chrome or Safari.
At the moment I am using:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test</title>
<script src="modernizr-1.6.min.js"></script>
<script type="text/javascript">
window.addEventListener('load', eventWindowLoaded,false);
var videoElement;
var VideoDiv;
var Object1;
var Mouse = {
x:0
x:y}
function eventWindowLoaded(){
videoElement = document.createElement("video");
videoDiv = document.createElement('div');
document.body.appendChild(videoDiv);
videoDiv.appendChild(videoElement);
videoDiv.setAttribute("style", "display:none;");
var videoType = supportedVideoFormat(videoElement);
if (videoType == ""){
alert("no video support");
return;
}
videoElement.setAttribute("src", "different_movement>" + videoType);
videoElement.addEventListener("canplaythrough", videoLoaded, false);
}
function supportedVideoFormat(video){
var returnExtension= "";
if(video.canPlayType("video/webm") =="probably" || video.canPlayType("video/webm") == "maybe"){
returnExtension = "webm";
} else if (video.canPlayType("video/mp4") == "probably" || video.canPlayType("video/mp4") == "maybe"){
returnExtension = "mp4";
}else if(video.canPlayType("video/ogg") == "probably" || video.canPlayType("video/ogg") == "maybe"){
returnExtension = "ogv";
}
return returnExtension;
}
function videoLoaded(event){
canvasApp();
}
canvasOne.onmousemove = function (event){
Mouse={
x: event.offsetX,
y: event.offsetY}
}
}
function canvasApp(){
function drawScreen(){
context.drawImage(videoElement, 0, 0);
context.fillStyle = '#ffffff';
context.fillText(Mouse.x, 280, 280);
context.fillText(Mouse.y, 280, 300);
}
var theCanvas = document.getElementByID('canvasOne');
var context = theCanvas.getContext('2d');
videoElement.play();
setinterval(drawScreen, 33);
}
</script>
</head>
<body>
<canvas id="canvasOne" width="640" height="480">
Your browser does not support HTML5 Canvas.
</canvas>
</div>
</body>
</html>
The result of this is the 0,0 will be shown on the video from the initial variable set at 0,0 but then instead of changing as the mouse is moved around the screen, it stays 0,0. This leads me to believe that it is the part of the code that is finding the mouse coordinates that is not working.
I have tried various other attempts at finding mouse coordinates including:
Mouse={
x: event.pageX,
y: event.pageX}
,
if (e.pageY) {
posy = e.pageY;
} else if (e.clientY) {
posy = e.clientY + document.body.scrollTop
+ document.documentElement.scrollTop;
}
,
var mouseX;
var mouseY;
var pieceX;
var pieceY;
if (e.pageX || e.pageY) {
mouseX = e.pageX;
mouseX = e.pageY;
} else {
mouseX = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
mouseY = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
My end product is supposed to be a video that has mouse interactions that will play sounds when certain parts on the video are clicked (thus the part of video). I have tried not using canvas at all for this, and instead positioning a image on top of the canvas which has image mapping on it, but it doesn't seem to work.
Another issue I am going to run into when I figure out mouse coordinates is what I will test collisions with the mouse coordinates to initiate it to play the sounds.
EDIT:
Completely rewrote the code using e.offset, seems to work.
I used <iframe> to set an html page with a canvas element positioned top left of document. Then when I get clientX-Y it's origin is the top left of the canvas document, that's in the iframe, that you can have positioned anywhere on the canvas-containing document. It's easy as pie.
<iframe scrolling="no" height="100%" width="100%" src="canvas.html"></iframe>
also, I got the canvas to scale when it is scaled by style sheet. I added this to my canvas program.
c = canvas element, ctx = canvas context;
ctx.scale(c.width/630,c.height/800); // I originally intended it to be 630x800
(note: I am not sure if this answers your problem, but it is how I find coordinates without having to offset.)