Clear Canvas Recursively after translating it - javascript

I am trying to translate and save my canvas each time I press right key, so that it moves horizontally each time I press right key. This is the function I am using to move the canvas horizontally each time which is working for the first time and but not later.
function clearRight(){
var canvas1=document.getElementById('plot');
ctx=canvas1.getContext("2d");
ctx.restore();
ctx.translate(-1000,0);
ctx.save();
ctx.clearRect(0,0,canvas1.width,canvas1.height);
}
rightKey(){
clearRight();
draw();
}
Can anyone please point where am I going wrong in trying to move the canvas?
UPDATE
I have solved the issue I was facing.
To move the canvas horizontally
var translated=0;
function clear()
{
var canvas1=document.getElementById('plot');
var ctx=canvas1.getContext("2d");
ctx.restore();
ctx.save();
ctx.clearRect(0,0,canvas1.width,canvas1.height);
}
function rightKey()
{
clear();
ctx.clearRect(0,0,canvas1.width,canvas1.height);
translated += 10;
ctx.translate(-translated,300);
draw(ctx);
}

I'm assuming there's a reason why you're not just drawing an oversized canvas contained in a smaller div-wrapper with scrollbars enabled...so here's an alternative.
You could draw your entire plotted graph to a separate canvas.
Then to pan left/right you can draw that temporary canvas to your main canvas with an offset.
A Demo: http://jsfiddle.net/m1erickson/GfRLq/
Before panning right:
After panning right:
About dynamically changing plots:
If your plots are dynamic, then you can still use this panning technique.
Just update the tempCanvas with each new plot.
Example code:
<!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 offset=0;
// create some test data
var points=[];
for(var i=0;i<50;i++){
points.push({x:i*40,y:100+Math.random()*100-50});
}
// create a temporary canvas
var tempCanvas=document.createElement("canvas");
var tempCtx=tempCanvas.getContext("2d");
tempCanvas.width=40*points.length;
tempCanvas.height=300;
// draw your complete plot on the tempCanvas
// draw the line
tempCtx.beginPath();
tempCtx.moveTo(points[0].x,points[0].y);
for(var i=0;i<points.length;i++){
var point=points[i];
tempCtx.lineTo(point.x,point.y);
}
tempCtx.lineWidth=5;
tempCtx.strokeStyle="blue";
tempCtx.stroke();
// draw the markers
for(var i=0;i<points.length;i++){
var point=points[i];
tempCtx.beginPath();
tempCtx.arc(point.x,point.y,10,0,Math.PI*2);
tempCtx.closePath();
tempCtx.fillStyle="black";
tempCtx.fill();
tempCtx.fillStyle="white";
tempCtx.fillText(i,point.x-3,point.y+3);
}
ctx.drawImage(tempCanvas,0,0)
// function to draw the canvas with your specified offset
function drawPlotWithOffset(offset){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.drawImage(tempCanvas,offset,0,canvas.width,canvas.height,0,0,canvas.width,canvas.height)
}
$("#left").click(function(){
offset-=20;
if(offset<0){offset=0;}
drawPlotWithOffset(offset);
});
$("#right").click(function(){
offset+=20;
if(offset>tempCanvas.width-canvas.width){
offset=tempCanvas.width-canvas.width;
}
drawPlotWithOffset(offset);
});
}); // end $(function(){});
</script>
</head>
<body>
<button id="left">Pan Left</button><br>
<button id="right">Pan Right</button><br>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

Related

How to create your own interactive panoramic website

I want to make a website that will be a room, and I want users to be able to look at that room in limited panoramic view, e.g. up/down 30 degrees, left/right 45 degrees, and I want to put objects in that panoramic view that user could interact with.
I have found that google street view could give the panoramic effect, but I'm not quite sure if it would suit my needs as I would want to put objects in it.
Are there any alternative panoramic libraries that are good and could give me tools to support what I want to achieve?
You are basically talking about panning around a view.
You can do that by drawing the view with horizontal & vertical offsets.
Here's annotated code and a Demo: http://jsfiddle.net/m1erickson/32Y5A/
<!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 ctx=canvas.getContext("2d");
ctx.strokeStyle="red";
ctx.lineWidth=5;
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var lastX=0;
var lastY=0;
var panX=0;
var panY=0;
var dragging=[];
var isDown=false;
// create "draggable" rects
var images=[];
images.push({x:200,y:150,width:25,height:25,color:"green"});
images.push({x:80,y:235,width:25,height:25,color:"gold"});
// load the tiger image
var tiger=new Image();
tiger.onload=function(){
draw();
}
tiger.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/tiger.png";
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
// draw tiger
ctx.globalAlpha=0.25;
ctx.drawImage(tiger,panX,panY,tiger.width,tiger.height);
// draw color images
ctx.globalAlpha=1.00;
for(var i=0;i<images.length;i++){
var img=images[i];
ctx.beginPath();
ctx.rect(img.x+panX,img.y+panY,img.width,img.height);
ctx.fillStyle=img.color;
ctx.fill();
ctx.stroke();
}
}
// create an array of any "hit" colored-images
function imagesHitTests(x,y){
// adjust for panning
x-=panX;
y-=panY;
// create var to hold any hits
var hits=[];
// hit-test each image
// add hits to hits[]
for(var i=0;i<images.length;i++){
var img=images[i];
if(x>img.x && x<img.x+img.width && y>img.y && y<img.y+img.height){
hits.push(i);
}
}
return(hits);
}
function handleMouseDown(e){
// get mouse coordinates
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// set the starting drag position
lastX=mouseX;
lastY=mouseY;
// test if we're over any of the images
dragging=imagesHitTests(mouseX,mouseY);
// set the dragging flag
isDown=true;
}
function handleMouseUp(e){
// clear the dragging flag
isDown=false;
}
function handleMouseMove(e){
// if we're not dragging, exit
if(!isDown){return;}
//get mouse coordinates
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// calc how much the mouse has moved since we were last here
var dx=mouseX-lastX;
var dy=mouseY-lastY;
// set the lastXY for next time we're here
lastX=mouseX;
lastY=mouseY;
// handle drags/pans
if(dragging.length>0){
// we're dragging images
// move all affected images by how much the mouse has moved
for(var i=0;i<dragging.length;i++){
img=images[dragging[i]];
img.x+=dx;
img.y+=dy;
}
}else{
// we're panning the tiger
// set the panXY by how much the mouse has moved
panX+=dx;
panY+=dy;
}
draw();
}
// use jQuery to handle mouse events
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
}); // end $(function(){});
</script>
</head>
<body>
<h4>Drag the tiger and<br>independently drag the rectangles.</h4>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

How to hide an element after drawing on canvas with setTimeout Javascript

I have used JavaScript to draw circles at specific points onto the canvas after set times using SetTimeout after I have pressed a button.
How do i make the circles then disappear after a set time or before the next one appears?
JavaScript
//button
function MButton() {
drawOnCanvas();
Circle();
Circle2();
}
function drawOnCanvas() {
var canvas = document.getElementById("canvas_1");
if (canvas.getContext) {
canvas_context = canvas.getContext("2d");
//alert("alert draw");
setTimeout();
}
}
function Circle() {
setTimeout(function () {
canvas_context.fillStyle = "red";
canvas_context.beginPath();
canvas_context.arc(195, 180, 10, 0, Math.PI * 2, true);
canvas_context.closePath();
canvas_context.fill();
}, 300);
}
function Circle2() {
setTimeout(function () {
canvas_context.fillStyle = "red";
canvas_context.beginPath();
canvas_context.arc(285, 180, 10, 0, Math.PI * 2, true);
canvas_context.closePath();
canvas_context.fill();
}, 1500);
}
HTML
<CANVAS WIDTH="360" HEIGHT="300" ID="canvas_1">
Canvas tag not supported
</CANVAS>
<INPUT TYPE ="Button" VALUE=" Play " onClick="MButton()">
I am new to this and I would really appreciate the help!
Here are the general steps to creating canvas circles that disappear after a specified time
Create javascript objects for each circle containing info about that circle.
The object holds info on how to draw the circle: x,y,radius,color
The object also holds info on how long the object will appear after being drawn. That's visibleDuration in the example below. visibleDuration:750 indicates this circle should remain visible for 750ms and then disappear
The object also hold info on how much longer it should display before it disappears. That's visibleCountdown in the example below. When the user clicks the "Display Red Circle" button, visibleCountdown will be set to 750. visibleCountdown is decremented in the animation frame.
circles.red=({
x:100,
y:100,
radius:25,
color:"red",
visibleDuration:750, // this circle disappears after 750ms
visibleCountdown:0 // this is used as a display countdown timer for this circle
});
Create an animation loop with the efficient requestAnimationFrame method.
requestAnimationFrame is preferred to setTimeout for performance reasons (check out why on Google!)
// begin the animation loop
animate();
// This is an animation loop using the highly-efficient requestAnimationFrame method
// It will run about 60 x per second
function animate(){
requestAnimationFrame(animate);
}
Inside the animation loop, draw each circle if their visibleCountdown has not expired
// reduce visibleCountdown by the elapsed time
visibleCountdown -= elapsedTimeSinceLastTimeInLoop
if(visibleCountdown>0){
// draw this circle since it's countdown is still above zero
}
Here is example code and a Demo: http://jsfiddle.net/m1erickson/utdG8/
<!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 circles={};
circles.red=({
x:100,
y:100,
radius:25,
color:"red",
visibleDuration:750,
visibleCountdown:0
});
circles.blue=({
x:175,
y:150,
radius:20,
color:"blue",
visibleDuration:1500,
visibleCountdown:0
});
var startTime=lastTime=performance.now();
animate();
function animate(currentTime){
requestAnimationFrame(animate);
ctx.clearRect(0,0,canvas.width,canvas.height);
var elapsed=currentTime-lastTime;
lastTime=currentTime;
for(var i in circles){
var circle=circles[i];
circle.visibleCountdown-=elapsed;
if(circle.visibleCountdown>0){
drawCircle(circle);
}
}
}
function drawCircle(circle){
ctx.globalAlpha=circle.visibleCountdown/circle.visibleDuration;
ctx.beginPath();
ctx.arc(circle.x,circle.y,circle.radius,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle=circle.color;
ctx.fill();
ctx.globalAlpha=1.00;
}
function showCircle(circle){
circle.visibleCountdown=circle.visibleDuration
}
$("#red").click(function(){
showCircle(circles["red"]);
});
$("#blue").click(function(){
showCircle(circles["blue"]);
});
}); // end $(function(){});
</script>
</head>
<body>
<button id="red">Show Red for 0.75 seconds</button><br>
<button id="blue">Show Blue for 1.50 seconds</button><br>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
You have to use the clearRect command
context.clearRect ( x , y , w , h );
This will wipe out the area for you!

One pixel fill, with canvas

This might be a somewhat stupid question, but...is it possible to fill an HTML canvas element, pixel by pixel, depending on where a user clicks?
I want to have a blank canvas, that users will click one pixel at a time, which will fill a color, and enter that user/pixel into a database.
How would this be done?
How can I know what pixel, what user clicked?
Thanks
Yes, you can set each canvas pixel individually based on mouse-clicks.
Here's how you set an individual pixel using context.getImageData and context.putImageData:
function setPixel(x, y, red, green, blue) {
pixPos=( (~~x) + (~~y)) * 4;
var pxData = ctx.getImageData(x,y,1,1);
pxData.data[0]=red;
pxData.data[1]=green;
pxData.data[2]=blue;
pxData.data[3]=255;
ctx.putImageData(pxData,x,y);
}
And you get the X/Y position of the mouse click by adding an event listener like this:
// get the position of the canvas relative to the web page
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
// tell the browser to send you mouse down events
// Here I use jquery -- be sure to add jquery or just do addEventListener instead
$("#canvas").mousedown(function(e){handleMouseDown(e);});
// handle the mousedown events that the browser sends you
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
setPixel(mouseX,mouseY,red,green,blue);
}
Here's code and a fiddle: http://jsfiddle.net/m1erickson/wtStf/
<!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 canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var red=255;
var green=0;
var blue=0;
function setPixel(x, y, red, green, blue) {
pixPos=( (~~x) + (~~y)) * 4;
var pxData = ctx.getImageData(x,y,1,1);
pxData.data[0]=red;
pxData.data[1]=green;
pxData.data[2]=blue;
pxData.data[3]=255;
ctx.putImageData(pxData,x,y);
}
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
setPixel(mouseX,mouseY,red,green,blue);
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
[Edited for additional question]
You can easily modify the code to set blocks of pixels like this:
var blockWidth=25;
var blockHeight=25;
function setPixel(x, y, red, green, blue) {
pixPos=( (~~x) + (~~y)) * 4;
var pxData = ctx.getImageData(x,y,blockWidth,blockHeight);
for(var n=0;n<blockWidth*blockHeight;n++){
pxData.data[n*4+0]=red;
pxData.data[n*4+1]=green;
pxData.data[n*4+2]=blue;
pxData.data[n*4+3]=255;
}
ctx.putImageData(pxData,x,y);
}

Drag a canvas element on a circle path

I would like to achieve jQuery Knob-like effect using HTML5 Canvas, but with a circle knob/cursor, instead of the stroke cursor effect that jQuery Knob does.
Based on jQuery Knob code, I was managed to connect the onMouseMove event with my circle knob/cursor so the circle knob moves according to the X and Y coordinates of where the mouse is. However I cannot "restrict" the knob to move only on/along the circle path just like this example, so if I click/mousedown inside the circle path, the circle knob moves to inside the path.
Is there any way to achieve this only using Canavas and jQuery, not Raphael like the example above?
One of my thoughts was to move the circle knob back on track (on the path) whenever mousemove event occurs outside the path (like this). However no luck in succeeding the calculation for this. Is there any math/geometry formula I can use to achieve this?
Just a little bit of trigonometry will answer your question!
This code will find the point on a circle closest to a mouseclick.
var rads = Math.atan2(mouseY - knobCenterY, mouseX - knobCenterX);
var indicatorX=knobRadius*Math.cos(rads)+knobCenterX;
var indicatorY=knobRadius*Math.sin(rads)+knobCenterY;
This code will put an indicator on the knob closest to where the user clicks
And here is a Fiddle --- http://jsfiddle.net/m1erickson/pL5jP/
<!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>
<!--[if lt IE 9]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var circleArc=Math.PI*2;
// drawing design properties
var knobCenterX=100;
var knobCenterY=100;
var knobRadius=50;
var knobColor="green";
var indicatorRadius=5;
var indicatorColor="yellow";
Draw(canvas.width/2,1); // just to get started
function Draw(mouseX,mouseY){
// given mousePosition, what is the nearest point on the knob
var rads = Math.atan2(mouseY - knobCenterY, mouseX - knobCenterX);
var indicatorX=knobRadius*Math.cos(rads)+knobCenterX;
var indicatorY=knobRadius*Math.sin(rads)+knobCenterY;
// start drawing
ctx.clearRect(0,0,canvas.width,canvas.height);
// draw knob
ctx.beginPath();
ctx.arc(knobCenterX,knobCenterY,knobRadius,0,circleArc,false);
ctx.fillStyle="ivory";
ctx.fill();
ctx.lineWidth=2;
ctx.strokeStyle=knobColor;
ctx.stroke();
// draw indicator
ctx.beginPath();
ctx.arc(indicatorX, indicatorY, indicatorRadius, 0, circleArc, false);
ctx.fillStyle = indicatorColor;
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
ctx.stroke();
}
function handleMouseDown(e){
MouseX=parseInt(e.clientX-offsetX);
MouseY=parseInt(e.clientY-offsetY);
Draw(MouseX,MouseY);
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
}); // end $(function(){});
</script>
</head>
<body>
<br/><p>Click anywhere in the canvas to set the knob indicator</p><br/>
<canvas id="canvas" width=200 height=200></canvas>
</body>
</html>

HTML5 Canvas moving alpha mask

I have a background, let's say it's green grass. On top of the background I have a black overlay. What I want now is to make a movable hole in the overlay so that you can see the background like in the image below.
I am pretty new to canvas so I'm not sure what I'm supposed to look for. Alpha mask?
So my question is how can I achieve the effect demonstrated in the image above?
If it were HTML I would have two images of the grass, one as the background and one above the overlay in a div with a border radius that can move and just calculate positions.
Thanks.
Are you looking for a moving "flashlight" kind of effect?
If so, you can do that by drawing a circular path and then using it as a clipping region with: context.clip();
Anything drawn after the .clip() will be viewed through the clipping path.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/pRzxt/
<!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");
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
var radius=50;
var x=100;
var dx=10;
var y=100;
var dy=10;
var delay=10;
var img=new Image();
img.onload=function(){
var canvas1=document.getElementById("image");
var ctxImg=canvas1.getContext("2d");
ctxImg.drawImage(img,0,0,img.width,img.height,0,0,canvas.width,canvas.height);
animate();
}
img.src="http://lh3.ggpht.com/_Z-i7eF_ACGI/TRxpFywLCxI/AAAAAAAAAD8/ACsxiuO_C1g/house%20vector.png";
function animate() {
if(--delay<0){
// update
x+=dx;
if(x-radius<0 || x+radius>=canvas.width){dx=-dx;}
y+=dy;
if(y-radius<0 || y+radius>=canvas.height){dy=-dy;}
delay=10;
// draw stuff
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.beginPath();
ctx.arc(x,y, radius, 0, 2 * Math.PI, false);
ctx.clip();
ctx.drawImage(img,0,0,img.width,img.height,0,0,canvas.width,canvas.height);
ctx.restore();
}
// request new frame
requestAnimFrame(function() {
animate();
});
}
}); // end $(function(){});
</script>
</head>
<body>
<p>Image clipped by moving circle</p>
<canvas id="canvas" width=300 height=200></canvas>
<br/><p>Unclipped image</p>
<canvas id="image" width=300 height=200></canvas>
</body>
</html>
I did something similar for a little canvas test I was working on a while back. What you can do is create a div with a canvas element on top of the bottom layer and draw a radial gradient with transparency on that top layer canvas. I have a fiddle here: http://jsfiddle.net/CnEBQ/14/
In particular look at this bit of code for the radial gradient. The context is attached to the top div canvas:
var gradient = tCTX.createRadialGradient(CANVAS_SIZE.x/2, CANVAS_SIZE.y/2, 250, CANVAS_SIZE.x/2, CANVAS_SIZE.y/2, 0);
gradient.addColorStop(0, "#000");
gradient.addColorStop(1, "transparent");
tCTX.fillStyle = gradient;
tCTX.fillRect(0, 0, CANVAS_SIZE.x, CANVAS_SIZE.y);
There may be a little bad code in there, but it should give you an idea of whether this is where you want to go. You could redraw the top layer "hole" as needed on a timer or some event to get it moving. And you can play with the gradient setting to get more or less "darkness".
I'm having quite a time trying to find a good reference to the functions I'm using here, but a decent place to look for more explanation of these functions is
the Mozilla Canvas API
where the parameters to the gradient functions are explained. Especially useful since they're not immediately obvious.

Categories