How do I put the canvas on top of my website, with position: absolute, so that my animation happens on top of my regular website. Now when I animate, the canvas background becomes white so I can't see my website. BUT I want to see both my website and the animation that is lying on top of it.?
My end goal is to have tiny circles follow my fingers when I touch the screen on a mobile phone, but before I can achieve that, I have to know that I can animate on top of other elements first. At least, that is what I think at the moment.
Please help :)
Use ctx.clearRect() for your animation. I also added background-color:transparent just in case, but it works without it.
var ctx = canvas.getContext('2d');
canvas.height = innerHeight;
canvas.width = innerWidth;
function rad(deg){
return deg*Math.PI/180;
}
var t = 360;
function loop(){
requestAnimationFrame(loop);
ctx.clearRect(0,0,innerHeight,innerWidth);
ctx.beginPath();
ctx.arc(100+50*Math.sin(rad(t)),100+50*Math.cos(rad(t)),40+20*Math.sin(rad(t)),0,Math.PI*2);
ctx.fillStyle='rgba(255,255,20,0.8)';
ctx.strokeStyle='red';
ctx.lineWidth = 5;
ctx.fill();
ctx.stroke();
t=t>0?t-5:360;
}
loop();
canvas{
position:absolute;
background-color:transparent;
}
<canvas id=canvas></canvas>
<h1>
Your website.
</h1>
<h2>
Words words words.
</h2>
words words words words
Related
I would like to add 2d text annotations to a 3d object similar to this.
I haven't found any tutorials on overlaying a 3d object with HTML elements that can be turned off and on with click. I did find this but wasn't sure if there was another way other than rendering to the canvas.
Display text over Canvas only onmouseover
Seems like I should be able to toggle display styles of absolute-positioned elements, but I can't figure it out. Any pointers are greatly appreciated
There are a lot tutorials to determine the object when clicking on the canvas (using raycaster and projection). Basically, you want it the other way round: having a 3D coordinate and want to get the 2D coordinate above the canvas where you can postion a html element.
I would do it the following way:
Html structure
<div style="position: relative">
<canvas></canvas>
<div id="tip" style="position: absolute; display: none">Some text</div>
</div>
Determine the clicked object
var selectedObject;
// using jquery
$('canvas').on('click', function(event) {
// get 2D viewport coordinates
var mouse = new THREE.Vector2();
mouse.x = (event.offsetX / SCREEN_WIDTH) * 2 - 1;
mouse.y = - (event.offsetY / SCREEN_HEIGHT) * 2 + 1;
// raycast
var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5).unproject(camera);
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects(arrayOfObjects, true);
if(intersects.length > 0 ) {
selectedObject = intersects[0].object;
// toggle html element
$('#tip').css('display', 'block');
$('#tip').text(selectedObject.userData.note);
// assuming that the actual position is at the center of the mesh, otherwise the text will display somewhere else
// alternatively you could store and pass the point of click: intersects[0].point
positionTip(selectedObject.position);
}
});
position the html element (if you manipulate the camera, then you need to call this each time, so the element's position will update too)
function positionTip(pos3D) {
var v = pos3D.project(camera);
var left = SCREEN_WIDTH * (v.x + 1) / 2;
var top = SCREEN_HEIGHT * (-v.y + 1) / 2;
$('#tip').css({ left: left, top: top });
}
DISCLAIMER: I cannot guarantee that these code snippets work out of the box. I just copied some pieces of code from my project and made some additions/modifications for generalisation.
i'm looking for a way to erase drawing lines in canvas without erasing my background image.
when i tried using white color i get white line on the image.
i thought about making transparent line but i don't think that's possible.
on saving the canvas with toDataURL() i want to save the drawing with the background.
this is how i set background image:
var background = new Image();
background.src = "pizza.png";
background.onload = function(){
context.drawImage(background,0,0);
}
You can "erase" with Compositing, but it's not recommended for lines
You can use compositing to "erase" a previously drawn line by redrawing it with globalCompositeOperation='destination-out'. This causes the previous line to become transparent pixels. Then you can reapply the background image over just the transparent pixels using globalCompositeOperation='destination-over'.
But there's a problem with lines. The problem with "erasing" lines is that canvas will automatically apply anti-aliasing to every line. That added anti-aliasing is difficult to remove.
The better (more typical) way of erasing canvas lines drawn over a background is to redraw everything:
Save all line definitions in an array (eg lines[]),
To remove line(s), remove their definitions from the lines[] array,
Erase the whole canvas,
Redraw the background,
Redraw all lines still in the lines[] array.
Here's annotated code and a demo:
// canvas vars
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
// save line definitions
var lines=[
{x0:75,y0:50,x1:200,y1:100,color:'red'},
{x0:75,y0:75,x1:200,y1:100,color:'green'},
{x0:75,y0:100,x1:200,y1:100,color:'blue'},
{x0:65,y0:50,x1:65,y1:200,color:'green'},
]
// load the background
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/bk.png";
function start(){
// draw the first time
draw();
// remove green lines on button click
$('#go').click(function(){ remove('green'); });
}
function draw(){
// clear canvas
ctx.clearRect(0,0,cw,ch);
// redraw background
ctx.drawImage(img,0,0);
// redraw all lines still in lines[]
ctx.lineWidth=3;
for(var i=0;i<lines.length;i++){
var l=lines[i];
ctx.beginPath();
ctx.moveTo(l.x0,l.y0);
ctx.lineTo(l.x1,l.y1);
ctx.strokeStyle=l.color;
ctx.stroke();
}
}
function remove(color){
for(var i=lines.length-1;i>=0;i--){
if(lines[i].color==color){lines.splice(i,1);}
}
draw();
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id=go>Remove green lines</button>
<br>
<canvas id="canvas" width=300 height=300></canvas>
I have this fiddle where I have text arranged in a circle, I would like now to animate it and rotate the text in a clockwise/counter clockwise motion.
Every animation demo I have seen uses a container as the starting point however all the examples i could find about manipulating text in a circular arrangement have all started with the element. I have tried 100's of variations trying to get this working but I am either missing something or it's not possible with the construction i have used thus far.
Here is the fiddle for the circular text I have so far:
http://jsfiddle.net/jamesburt/Sa2G8/
<canvas id="canvas1" width="500" height="500"></canvas>
var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');
Where as the animation examples start off with:
<div id="container"></div>
var stage = new Kinetic.Stage({container: 'container'});
I'm open to any ideas / rewrites needed as ultimately my goal is an animated text circle.
Also if this is easily accomplished in an alternative to KineticJS I'd be interested in trying that out.
Here is a demo I made using KineticJS: http://jsfiddle.net/Moonseeker/Xf7hp/
var stage = new Kinetic.Stage({
container: 'container',
width: 500,
height: 500
});
var layer = new Kinetic.Layer();
var myText = "My text in a circle. ";
var centerCoords = {x:250, y:250};
for(var i=0;i<myText.length;i++){
var rotation = i*360/myText.length;
var oneChar = new Kinetic.Text({
x: centerCoords.x,
y: centerCoords.y,
text: myText[i],
fontSize: 30,
fontFamily: 'Calibri',
fill: 'green',
offset: {x:0, y:100},
rotationDeg: rotation
});
layer.add(oneChar);
}
// add the layer to the stage
stage.add(layer);
var angularSpeed = Math.PI / 2;
var anim = new Kinetic.Animation(function(frame){
var angleDiff = frame.timeDiff * angularSpeed / 1000;
for(var i=0;i<layer.children.length;i++){
layer.children[i].rotate(angleDiff);
};
}, layer);
anim.start();
You can rotate at every direction or speed you wish, you can change the style of the circle.
You should be able to use layer.find('Text').each() instead of the for-loop for looping through the text to rotate but the KineticJS library at jsfiddle seems outdated as it doesn't know the find method.
One efficient way:
Render your text-around-a-circle on an offscreen canvas.
Save that offscreen canvas as an image using .toDataURL
Create a Kinetic.Image from that offscreen image.
You can then efficiently rotate/animate the Kinetic.Image as you need.
I am completely new to HTML5 and have been reading about it for the past few days mainly because I wanted to create a rotating image to put in a <div>. I found a code that does exactly what I want, but it throws the canvas on to the bottom left corner of my page (I'm not sure why, but I think it has something to do with the very first line of the code below). I'm not sure how to adapt the code to a element so that I can put it where I want. From looking at other people's scripts and trying to emulate them, I know you're supposed to do this sort of thing to hold the canvas "<canvas width="100" height="100" id="pageCanvas"></canvas>," but I don't know how to name the below code in order to do that. I greatly appreciate any help anyone can offer me - thank you so much for reading! :)
<script>
window.addEventListener("load", init);
var counter = 0,
logoImage = new Image(),
TO_RADIANS = Math.PI/180;
logoImage.src = 'IMG URL';
var canvas = document.createElement('canvas');
canvas.width = 100;
canvas.height = 100;
var context = canvas.getContext('2d');
document.body.appendChild(canvas);
function init(){
setInterval(loop, 1000/30);
}
function loop() {
context.clearRect(0,0,canvas.width, canvas.height);
drawRotatedImage(logoImage,100,100,counter);
drawRotatedImage(logoImage,300,100,counter+90);
drawRotatedImage(logoImage,500,100,counter+180);
counter+=2;
}
function drawRotatedImage(image, x, y, angle) {
// save the current co-ordinate system
// before we screw with it
context.save();
// move to the middle of where we want to draw our image
context.translate(x, y);
// rotate around that point, converting our
// angle from degrees to radians
context.rotate(angle * TO_RADIANS);
// draw it up and to the left by half the width
// and height of the image
context.drawImage(image, -(image.width/2), -(image.height/2));
// and restore the co-ords to how they were when we began
context.restore();
}
</script>
Create a canvas element in your HTML code so you can place it exactly where you want (with html + css) :
<canvas id='canvas' height='100' width='100'> Your browser does not support HTML5 canvas </canvas>
And replace this javascript code :
var canvas = document.createElement('canvas');
canvas.width = 100;
canvas.height = 100;
var context = canvas.getContext('2d');
document.body.appendChild(canvas);
by this one :
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
I am trying to draw circles on a canvas filled with portions from an image. Imagine clicking on a white canvas and where the user clicked reveal a portion of a photo.
I have found ways to draw 1 circle, but can not succeed using this to draw multiples. If I repeat the action with other coordinates the drawing is not happening.
function start_drawing(){
ctx.beginPath();
ctx.fillStyle = "rgb(255,255,255)";
ctx.fillRect(0,0,canvas.width,canvas.height);//fill the background. color is default black
ctx.arc(mouse.x,mouse.y,45,0,6.28,false);//draw the circle
ctx.arc(mouse.x+100,mouse.y+100,45,0,6.28,false);
ctx.clip();//call the clip method so the next render is clipped in last path
ctx.drawImage(img,0,0);
ctx.closePath();
}
Any idea on how this can be achieved ?
Thank you.
Later Edit (The entire exact code used)
<!DOCTYPE HTML>
<html>
<head>
<script>
window.onload=function(){
var canvas = document.getElementById('myCanvas');
var ctx=canvas.getContext('2d');
var mouse={x:0,y:0} //make an object to hold mouse position
canvas.onmousemove=function(e){mouse={x:e.pageX-this.offsetLeft,y:e.pageY-this.offsetTop};} //update the mouse when the canvas is moved over
var img=new Image();
img.src="bmw_gina.jpg";
setInterval( start_drawing ,100);// set the animation into motion
ctx.beginPath();
ctx.fillStyle = "rgb(255,255,255)";
ctx.fillRect(0,0,canvas.width,canvas.height);//fill the background. color is default black
ctx.closePath();
function start_drawing(){
//ctx.save();
ctx.beginPath();
ctx.arc(mouse.x,mouse.y,45,0,6.28,false);//draw the circle
ctx.clip();//call the clip method so the next render is clipped in last path
ctx.drawImage(img,0,0);
ctx.closePath();
//ctx.restore();
}
}
</script>
</head>
<body>
<canvas id="myCanvas" width="1003" height="914"></canvas>
</body>
</html>
There are two issues I can see with yor code:
The first is that start_drawing is clearing the canvas every execution. So for each mouse click (I assume that start_drawing is called on mouse click) the circle is drawn but the canvas is cleared before that.
the other is that You need to call BeginPath and closePath for each clipping region you want to create. so your code should look something like that:
function start_drawing(){
ctx.fillStyle = "rgb(255,255,255)";
ctx.fillRect(0,0,canvas.width,canvas.height);//fill the background. color is default black
ctx.beginPath();
ctx.arc(mouse.x,mouse.y,45,0,6.28,false);//draw the circle
ctx.clip();//call the clip method so the next render is clipped in last path
ctx.closePath();
ctx.drawImage(img,0,0);
ctx.beginPath();
ctx.arc(mouse.x+100,mouse.y+100,45,0,6.28,false);
ctx.clip();//call the clip method so the next render is clipped in last path
ctx.closePath();
ctx.drawImage(img2,0,0);
}
Update
Well apparently, the trick to reset the clipping region is to reset the canvas. This can be achieved by re setting it's width.
There you go: http://jsfiddle.net/qCg9N/5/