HTML Canvas: How Do I Set Border Restrictions? - html

I have created a program that can move a rectangular block up, down, right, and left within a canvas using the w, a, s and d keys. I am having difficulty figuring out how to have the block not go beyond the borders of the canvas and be restricted only to stay within it.
Here is the part of my code for the canvas:
<html>
<head>
<script>
var positionX=0;
var positionY=0;
window.addEventListener("keydown", onKeyPress, true);
function draw(){
var canvas=document.getElementById("canvas_c");
var context=canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle="green";
context.fillRect(positionX, positionY, 100, 100);
context.strokeStyle = 'black';
context.stroke();
}
function onKeyPress(e){
if (e.keyCode==87){
positionY-=15;
}
if (e.keyCode==83){
positionY+=15;
}
if (e.keyCode==68){
positionX+=50;
}
if (e.keyCode==65){
positionX-=50;
}
draw();
}
</script>
</head>
<body>
<div id="firstDiv">
<canvas id="canvas_c" width="1000" height="500" style="border: 1px solid black;"> </canvas>
</div>
</body>

Here is pseudo-code for the basic boundary respecting movement functions:
// assuming this block object: var block={x:10,y:10,width:20,y:20};
function goLeft(){ if(block.x>0){block.x--;} }
function goUp(){ if(block.y>0){block.y--;} }
function goRight(){ if(block.x<(canvas.width-block.width)){block.x++;} }
function goDown(){ if(block.y<(canvas.height-block.height)){block.y++;} }
[Addition: Here's code based on the code you've added to your question]
Warning: untested code ... may need tweaking! :-)
// save the canvas width & height at the top of the app
var canvas=document.getElementById("canvas1");
var cw=canvas.width;
var ch=canvas.height;
function onKeyPress(e){
if (e.keyCode==87){
positionY=Math.max(0,positionY-15);
}
if (e.keyCode==83){
positionY=Math.min(cw-100,positionY+15);
}
if (e.keyCode==68){
positionX=Math.min(ch-100,positionX+50);
}
if (e.keyCode==65){
positionX=Math.max(0,positionX-50);
}
draw();
}

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.

HTML5 Canvas Drag and Drop Item

Been struggling to get this work work. Here's my code:
<canvas id="graphCanvas" ondrop="drop(event)" ondragover="allowDrop(event)" height=600 width=1000 style="border:1px solid #000000;"></canvas>
<img id="img1" src="./images/arrow_up.svg" draggable="true" onmousedown="get_pos(event)" ondragstart="drag(event)"/>
<script type="text/javascript">
function init() {
var canvas = document.getElementById("graphCanvas");
var context = canvas.getContext("2d");
context.lineWidth = 2;
}
var pos;
function allowDrop(ev) {
ev.preventDefault();
}
function get_pos(ev){
pos = [ev.pageX, ev.pageY];
}
function drag(ev) {
ev.dataTransfer.setData("Text",ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var offset = ev.dataTransfer.getData("text/plain").split(',');
var data=ev.dataTransfer.getData("Text");
var img = canvas = document.getElementById("img1");
var dx = pos[0] - img.offsetLeft;
var dy = pos[1] - img.offsetTop;
document.getElementById("graphCanvas").getContext("2d").drawImage(document.getElementById(data), ev.pageX - dx, ev.pageY - dy);
}
</script>
It's suppose to be a draggable image that I can drop into a canvas. Once the image is in the canvas, the user can then move that image around. Unfortunately I can not seem to get it work. The image should appear if you drop it in near the top left, but the image appears near the bottom right.
How can I fix this problem?
You can use html5 draggable to drop an image element on canvas.
Then you can drawImage a copy of that image on the canvas.
You need this info to draw a copy of the draggable image on the canvas:
The mouse position relative to the draggable image (see mousedown below)
The canvas position relative to the document (canvasElement.offsetLeft & canvasElement.offsetTop).
The mouse position relative to the document at the drop ( dropEvent.clientX & dropEvent.clientY )
The Id of the draggable element (stored and retrieved in dragEvent.dataTransfer)
With this info you can drawImage a copy of the draggable element like this:
function drop(ev) {
ev.preventDefault();
var dropX=ev.clientX-canvasLeft-startOffsetX;
var dropY=ev.clientY-canvasTop-startOffsetY;
var id=ev.dataTransfer.getData("Text");
var dropElement=document.getElementById(id);
// draw the drag image at the drop coordinates
ctx.drawImage(dropElement,dropX,dropY);
}
Here's example code and a Demo: http://jsfiddle.net/m1erickson/WyEPh/
<!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; }
#graphCanvas{border:1px solid #000000;}
</style>
<script>
$(function(){
var canvas=document.getElementById("graphCanvas");
var ctx=canvas.getContext("2d");
var canvasLeft=canvas.offsetLeft;
var canvasTop=canvas.offsetTop;
canvas.ondrop=drop;
canvas.ondragover=allowDrop;
//
var img=document.getElementById("img1");
img.onmousedown=mousedown;
img.ondragstart=dragstart;
// this is the mouse position within the drag element
var startOffsetX,startOffsetY;
function allowDrop(ev) {
ev.preventDefault();
}
function mousedown(ev){
startOffsetX=ev.offsetX;
startOffsetY=ev.offsetY;
}
function dragstart(ev) {
ev.dataTransfer.setData("Text",ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var dropX=ev.clientX-canvasLeft-startOffsetX;
var dropY=ev.clientY-canvasTop-startOffsetY;
var id=ev.dataTransfer.getData("Text");
var dropElement=document.getElementById(id);
// draw the drag image at the drop coordinates
ctx.drawImage(dropElement,dropX,dropY);
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="graphCanvas" height=300 width=300></canvas>
<img id="img1" src="house32x32.png" draggable="true" />
</body>
</html>
However...images drawn on the canvas are just painted pixels and therefore not draggable
You can use a canvas library like KineticJS to create "retained" images that can be dragged after they are drawn on the canvas.
Here's a Demo using KineticJS to allow dropped images to later be dragged around the canvas:
http://jsfiddle.net/m1erickson/LuZbV/

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>

What can I do to create Jquery reel effect using canvas/div instead of images?

I am working on a web app and I want to have effect like "http://jquery.vostrel.cz/reel.
I want to create this effect using a canvas/div instead of images, Has anyone tried this before?
Edit
The code I have tried is as follows.
<body>
<canvas width="1280" height="720" id="pageCanvas">
You do not have a canvas enabled browser
</canvas>
<script>
var context = document.getElementById('pageCanvas').getContext('2d');
var angle = 0;
function convertToRadians(degree) {
return degree*(Math.PI/180);
}
function incrementAngle() {
angle++;
if(angle > 360) {
angle = 0;
}
}
function drawRandomlyColoredRectangle() {
<!-- clear the drawing surface -->
context.clearRect(0,0,1280,720);
<!-- you can also stroke a rect, the operations need to happen in order -->
incrementAngle();
context.save();
context.lineWidth = 10;
context.translate(200,200);
context.rotate(convertToRadians(angle));
<!-- set the fill style -->
context.fillStyle = '#'+Math.floor(Math.random()*16777215).toString(16);
context.fillRect(-25,-25,50,50);
context.strokeRect(-25,-25,50,50);
context.restore();
}
setInterval(drawRandomlyColoredRectangle, 20);
</script>
</body>
This I have tried using one Canvas but I want to use multiple Canvas.
Please guide me to solve this problem....
try this:
<body>
<canvas width="1280" height="720" id="pageCanvas1">
You do not have a canvas enabled browser
</canvas>
<canvas width="1280" height="720" id="pageCanvas2">
You do not have a canvas enabled browser
</canvas>
<script>
var draw = function (canvasid){
var context = document.getElementById(canvasid).getContext('2d');
var angle = 0;
var convertToRadians = function(degree) {
return degree*(Math.PI/180);
}
var incrementAngle = function() {
angle++;
if(angle > 360) {
angle = 0;
}
}
var drawRandomlyColoredRectangle = function(){
<!-- clear the drawing surface -->
context.clearRect(0,0,1280,720);
<!-- you can also stroke a rect, the operations need to happen in order -->
incrementAngle(angle);
context.save();
context.lineWidth = 10;
context.translate(200,200);
context.rotate(convertToRadians(angle));
<!-- set the fill style -->
context.fillStyle = '#'+Math.floor(Math.random()*16777215).toString(16);
context.fillRect(-25,-25,50,50);
context.strokeRect(-25,-25,50,50);
context.restore();
}
return {
'start' : function(){
setInterval(drawRandomlyColoredRectangle, 20);
},
'getContext' :function(){
return context;
}
};
}
draw("pageCanvas1").start();
draw("pageCanvas2").start();
</script>

Canvas: Click event on line

Please take a look at this little example. The clickhandler only works if you click in the middle of the line. It seems that the method isPointInPath does not consider the width of the line. Is there a way to solve this problem?
Yes, you are correct.
The new isPointInPath() works only on the centerline of a "fat" line--not the full width of the line.
It's more user friendly on closed shapes that are more than 1 pixel wide ;)
A Workaround for your exact question: Instead of drawing a fat line, draw a 20px wide rectangle.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/QyWDY/
This code uses basic trigonometry to create a rectangle around a line. In the mousedown event handler, it redraws the rectangle transparently and then tests isPointInPath().
If you need to test a poly-line, you can use these same principles to make rectangle-lines for each segment of your poly-line.
<!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");
// get canvas's relative position
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
// line specifications
var x1=50;
var y1=50;
var x2=300;
var y2=100;
// draw the lineRectangle
var lineRect=defineLineAsRect(x1,y1,x2,y2,20);
drawLineAsRect(lineRect,"black");
// overlay the line (just as visual proof)
drawLine(x1,y1,x2,y2,3,"red");
function drawLine(x1,y1,x2,y2,lineWidth,color){
ctx.fillStyle=color;
ctx.strokeStyle=color;
ctx.lineWidth=lineWidth;
ctx.save();
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
ctx.restore();
}
function drawLineAsRect(lineAsRect,color){
var r=lineAsRect;
ctx.save();
ctx.beginPath();
ctx.translate(r.translateX,r.translateY);
ctx.rotate(r.rotation);
ctx.rect(r.rectX,r.rectY,r.rectWidth,r.rectHeight);
ctx.translate(-r.translateX,-r.translateY);
ctx.rotate(-r.rotation);
ctx.fillStyle=color;
ctx.strokeStyle=color;
ctx.fill();
ctx.stroke();
ctx.restore();
}
function defineLineAsRect(x1,y1,x2,y2,lineWidth){
var dx=x2-x1; // deltaX used in length and angle calculations
var dy=y2-y1; // deltaY used in length and angle calculations
var lineLength= Math.sqrt(dx*dx+dy*dy);
var lineRadianAngle=Math.atan2(dy,dx);
return({
translateX:x1,
translateY:y1,
rotation:lineRadianAngle,
rectX:0,
rectY:-lineWidth/2,
rectWidth:lineLength,
rectHeight:lineWidth
});
}
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// draw our lineRect
drawLineAsRect(lineRect,"transparent");
// test if hit in the lineRect
if(ctx.isPointInPath(mouseX,mouseY)){
alert('Yes');
}
}
canvas.addEventListener("mousedown", handleMouseDown, false);
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=310 height=115></canvas>
</body>
</html>