So I'm trying to draw 8 random circles (Or bubbles as I call them in this case) on the screen for a simple project I'm making. I want to make it so that I can show the bubbles, but there are lines connecting each bubble at its startAngle.
<!DOCTYPE html>
<html>
<head>
<title>Image</title>
</head>
<body>
<script src="https://code.jquery.com/jquery-2.1.0.js"></script>
<canvas id="canvas" width="400" height="400"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var height = canvas.height;
var width = canvas.width;
ctx.strokeRect(0, 0, width, height);
var bubbles = [];
var Bubble = function () {
this.x = Math.floor(Math.random() * width);
this.y = Math.floor(Math.random() * height);
this.xspeed = 5;
this.yspeed = 5;
};
for (var i = 0; i < 8; i++) {
bubbles[i] = new Bubble();
};
Bubble.prototype.draw = function () {
for (var i = 0; i < 8; i++) {
ctx.fillStyle = "Black";
ctx.arc(bubbles[i].x, bubbles[i].y, 10, 0, Math.PI * 2, false);
}
};
setInterval(function () {
for (var i = 0; i < bubbles.length; i++) {
ctx.strokeStyle = "Black";
bubbles[i].draw();
ctx.stroke();
}
}, 30);
</script>
</body>
</html>
Basically, I've made 8 Bubble objects, then I've drawn an arc at their x and y (random) position, but it shows lines connecting them like so:
Output of code
When you run the code, it randomly generates 8 different locations and draws 8 arcs at their location, but it shows the lines that connect them. Is there a way to hide or get rid of these lines? I've tried to clear the canvas after each draw, but that hides the entire thing including the circle. I've been searching for most of the day and I couldn't find an answer to my specific problem. The answer is probably obvious, but I couldn't seem to find the solution due to my inexperience.
Call ctx.beginPath() before arc() to draw separate entities?
ctx.arc() creates an ctx.lineTo() between the last coordinates of the current path, and the first position of the arc.
So to avoid it, you can simply manually call moveTo() to lift the drawing pen to the first position of the arc.
This way, you can draw multiple arcs in the same Path and in the same stroke call (which becomes interesting when you draw a lot of arcs)
const ctx = c.getContext('2d'),
w = c.width,
h = c.height;
ctx.beginPath(); // call it once
for(let i = 0; i<100; i++){
let rad = Math.random()*20 + 5
let posX = rad + Math.random() * (w - rad *2);
let posY = rad + Math.random() * (h - rad *2);
// our arc will start at 3 o'clock
ctx.moveTo(posX + rad, posY); // so simply add 'rad' to the centerX
ctx.arc(posX, posY, rad, 0, Math.PI*2);
}
ctx.stroke(); // call it once
<canvas id="c" width="500"></canvas>
Related
I have a simple script that adds a new canvas to a div container for each clock that needs to be drawn based on the number of minutes given. The script will draw the canvas elements without fail and will draw the clock face in the last canvas element however it will not draw a clock face on any preceding canvas elements. Upon review of the console, the output is identical for the canvas elements both with and without the clock face. Not sure what is happening with this. Below is a JSFiddle with my code.
https://jsfiddle.net/1oxfgwkb/
The HTML
<html>
<body>
<div id="clockHolder"></div>
</body>
</html>
The JavaScript
var time = 115;
var holder = document.getElementById("clockHolder");
var clockNum = Math.ceil((time / 60));
for(var q = 1; q <= clockNum; q++) {
var clockFace = 'sample-'+q;
holder.innerHTML += '<canvas id="'+clockFace+'" width="35" height="35"></canvas>';
drawClock(clockFace);
}
function drawClock(clockFace) {
var c = document.getElementById(clockFace);
var ctx = c.getContext("2d");
var radius = (c.height / 2) * 0.9;
var midpoint = c.height / 2;
for(var i=1; i<=12; i++) {
var angle = (i*30) * Math.PI / 180;
ctx.save();
ctx.strokeStyle = 'rgba(100,100,100,0.75)';
ctx.beginPath();
ctx.translate(midpoint, midpoint);
ctx.rotate(angle);
ctx.translate(0, -radius*0.9);
ctx.moveTo(0,0);
ctx.lineTo(0,4);
ctx.stroke();
ctx.closePath();
ctx.restore();
}
ctx.strokeStyle = '#555';
ctx.beginPath();
ctx.arc(midpoint, midpoint, radius*0.9, 0, 2 * Math.PI);
ctx.stroke();
}
Any help would be greatly appreciated.
It's drawing them both but setting the innerHTML of the parent is overwriting all but the last. Setting the innerHTML doesn't preserve existing elements, it makes new ones with identical attributes--but without whatever content you updated in the meantime.
Instead try:
for(var q = 1; q <= clockNum; q++) {
holder.innerHTML += '<canvas id="sample-'+q+'" width="35" height="35"></canvas>';
}
for(var q = 1; q <= clockNum; q++) {
drawClock('sample-'+q);
}
You could also use document.createElement and then holder.append.
I am having some trouble drawing lines in circle with html5 canvas.
I am trying to make the bars look something like this
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
var bars = 50;
var radius = 100;
for(var i = 0; i < bars; i++){
var x = radius*Math.cos(i);
var y = radius*Math.sin(i);
draw_rectangle(x+200,y+200,1,13,i, ctx );
}
function draw_rectangle(x,y,w,h,deg, ctx){
ctx.save();
ctx.translate(x, y);
ctx.rotate(degrees_to_radians(deg));
ctx.fillStyle = "yellow";
ctx.fillRect(-1*(w/2), -1*(h/2), w, h);
ctx.restore();
}
function degrees_to_radians(degrees){
return degrees * Math.PI / 180;
}
function radians_to_degrees(radians){
return radians * 180 / Math.PI;
};
for some reason my lines are all crooked and unaligned. I really need help on this one. https://codepen.io/anon/pen/PRBdYV
The easiest way to deal with such a visualization is to play with the transformation matrix of your context.
You need to understand it as if you were holding a sheet of paper in your hands.
Instead of trying to draw the lines at the correct angle, rotate the sheet of paper, and always draw your lines in the same direction.
This way all you need in your drawing method is the angle, and the height of each bar.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
// the position of the whole thing
var circleX = canvas.width / 2;
var circleY = canvas.height / 2;
//
var bars = 50;
var barWidth = 5;
// inner radius
var radius = 50;
ctx.fillStyle = "yellow";
// no need to use degrees, a full circle is just 2π
for(var i = 0; i < Math.PI*2; i+= (Math.PI*2 / bars)){
draw_rectangle(i, (Math.random()*30) + 10);
}
function draw_rectangle(rad, barHeight){
// reset and move to the center of our circle
ctx.setTransform(1,0,0,1, circleX, circleY);
// rotate the context so we face the correct angle
ctx.rotate(rad);
// move along y axis to reach the inner radius
ctx.translate(0, radius);
// draw the bar
ctx.fillRect(
-barWidth/2, // centered on x
0, // from the inner radius
barWidth,
barHeight // until its own height
);
}
canvas#canvas{
background:black;
}
<html>
<body>
<canvas id="canvas" width="400" height="400"></canvas>
</body>
</html>
https://codepen.io/anon/pen/YajONR
Problems fixed: Math.cos wants radians, not degrees
We need to go from 0 to 360, so I adjusted the number of bars to make that a bit easier, and multiplied i by 6 (so the max value is 60*6==360)
If we don't add +90 when drawing the bars, we just get a circle
Check your codepen and figured out the problem lies in the degrees_to_radians
Here is the update link of you code.Link
PS I only looked at the shape of the circle not alignments of the bar :D
I want to write a simple scrolling right to left starfield. I have printed out the stars randomly. Now, how do I target each star and randomly give it a speed (say 1-10) and begin moving it? I also need to put each star back on the right edge after it reaches the left edge.
Following is my code written so far:
<!DOCTYPE html>
<html>
<head>
<script>
function stars()
{
canvas = document.getElementById("can");
if(canvas.getContext)
{
ctx = canvas.getContext("2d");
ctx.fillStyle = "black";
ctx.rect (0, 0, 400, 400);
ctx.fill();
starfield();
}
}
//print random stars
function starfield()
{
for (i=0; i<10; i++)
{
var x = Math.floor(Math.random()*399);
var y = Math.floor(Math.random()*399);
var tempx = x;
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(x, y, 3, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
}
}
</script>
</head>
<body onload="stars()">
<h1>Stars</h1>
<canvas id="can" width="400" height="400"style="border:2px solid #000100" ></canvas>
</body >
</html>
Here's a quick demo on Codepen. After saving the stars in an array, I'm using requestAnimationFrame to run the drawing code and update the position on every frame.
function stars() {
canvas = document.getElementById("can");
console.log(canvas);
if (canvas.getContext) {
ctx = canvas.getContext("2d");
ctx.fillStyle = "black";
ctx.rect(0, 0, 400, 400);
ctx.fill();
starfield();
}
}
// Create random stars with random velocity.
var starList = []
function starfield() {
for (i = 0; i < 20; i++) {
var star = {
x: Math.floor(Math.random() * 399),
y: Math.floor(Math.random() * 399),
vx: Math.ceil(Math.random() * 10)
};
starList.push(star);
}
}
function run() {
// Register for the next frame
window.requestAnimationFrame(run);
// Reset the canvas
ctx.fillStyle = "black";
ctx.rect(0, 0, 400, 400);
ctx.fill();
// Update position and draw each star.
var star;
for(var i=0, j=starList.length; i<j; i++) {
star = starList[i];
star.x = (star.x - star.vx + 400) % 400;
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(star.x, star.y, 3, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
}
stars();
run();
Put your x,y coordinates in an array, and then make a function that draws the array.
var stars = [
{x:110, y:80},
{x:120, y:20},
{x:130, y:60},
{x:140, y:40}
]
Then make a function to alter the x,y coordinates (for example increment y=y+1) each time before using the draw function.
Bonus:
This array solution allows you to have each star move at its own speed, you could store a delta (say 1 upto 3) in that array, and do y=y+delta instead. This looks 3D.
You could even go further and have a seperate x and y delta, and have stars fly out from the middle, which is even more 3D!
Or even simpler/faster could be to have the render function accept an x,y offset. It could then even wrap around, so that what falls off the screen on one side comes back on the other. It looks like you are rotating in space.
I simple way to imitate star movement towards a point(like a center) is simply divide both X and Y by Z coordinate.
nx = x / z
ny = y / z
And simply decrease z value as you iterate. As z is big, your points will be around a point and as z decreases the result will be bigger and bigger which imitates "moving" of a stars.
Just providing a solution which uses jQuery because using it you can get the output with lesser lines of code compared to complete canvas solution.It uses two canvas divs to get the desired output:
Check this fiddle
Little updated code from the code posted in the question
<script>
function stars(){
canvas = document.getElementById("can1");
canvasCopy = document.getElementById("can2");
if(canvas.getContext){
ctx = canvas.getContext("2d");
ctx.fillStyle = "black";
ctx.rect (0, 0, 400, 400);
ctx.fill();
starfield();
var destCtx = canvasCopy.getContext('2d');
destCtx.drawImage(canvas, 0, 0);
}
}
//print random stars
function starfield(){
for (i=0;i<10;i++){
var x = Math.floor(Math.random()*399);
var y = Math.floor(Math.random()*399);
var tempx = x;
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(x, y, 3, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
}
}
</script>
<body onload="stars()">
<h1>Stars</h1>
<div id="starBlocks">
<canvas id="can1" width="400" height="400"style="border:2px solid #000100" ></canvas>
<canvas id="can2" width="400" height="400"style="border:2px solid #000100" ></canvas>
</div>
</body >
jQuery
function playStars()
{
$('#starBlocks').animate({
scrollLeft : 400
},10000,'linear',function(){
$('#starBlocks').scrollLeft(0);
playStars();
});
}
playStars();
CSS
#starBlocks{
white-space:nowrap;
font-size:0px;
width:400px;
overflow:hidden;
}
I've been learning how to use html5 recently and one aspect that really interests me is the canvas's ability to create animations. I have followed some online tutorials to some success but recently I found "thecodeplayer" where there are some awesome tutorials (if your in to it, check it out). I've got to the point where I've gone through it various times but still with no luck. The canvas does not show in my browser window when I load it up in chrome. Ive even turned off extensions like adblocker as suggested from some answers on this site. Its probably something obvious but I cant find where I seem to have gone wrong. Anyone who can point me in the right direction, thanks
Heres the code.
<html>
<head>
<script type="text/javascript">
//Initializing the canvas
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
//Canvas dimensions
var W = 500; var H = 500;
//create an array of particles
var particles = [];
for(var i = 0; i < 50; i++)
{
//This will add 50 particles to the array with random positions
particles.push(new create_particle());
}
//function to create multiple particles
function create_particle()
{
//Random position on the canvas
this.x = Math.random()*W;
this.y = Math.random()*H;
//add random velocity to each particle
this.vx = Math.random()*20-10;
this.vy = Math.random()*20-10;
//Random colors
var r = Math.random()*255>>0;
var g = Math.random()*255>>0;
var b = Math.random()*255>>0;
this.color = "rgba("+r+", "+g+", "+b+", 0.5)";
//Random size
this.radius = Math.random()*20+20;
}
var x = 100; var y = 100;
//animate the particle
function draw()
{
//paint canvas black, remove particle trails
ctx.globalCompositeOperation = "source-over";
//reduce the opacity of the BG paint to give the final touch
ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
ctx.fillRect(0, 0, W, H);
//blend the particle with the BG
ctx.globalCompositeOperation = "lighter";
//draw particles from the array now
for(var t = 0; t < particles.length; t++)
{
var p = particles[t];
ctx.beginPath();
//colors
var gradient = ctx.createRadialGradient(p.x, p.y, 0, p.x, p.y, p.radius);
gradient.addColorStop(0, "white");
gradient.addColorStop(0.4, "white");
gradient.addColorStop(0.4, p.color);
gradient.addColorStop(1, "black");
ctx.fillStyle = gradient;
ctx.arc(p.x, p.y, p.radius, Math.PI*2, false);
ctx.fill();
//velocity
p.x += p.vx;
p.y += p.vy;
//Stops balls moving out of canvas
if(p.x < -50) p.x = W+50;
if(p.y < -50) p.y = H+50;
if(p.x > W+50) p.x = -50;
if(p.y > H+50) p.y = -50;
}
}
setInterval(draw, 33);
</script>
</head>
<body>
<canvas id="canvas"width="500"height="500"></canvas>
</body>
</html>
Place the code in a function, and add a script tag below the body HTML, calling the canvas drawing function. The canvas element is not yet created when you want to use it for drawing on.
Result:
<html>
<head>
<script type="text/javascript">
function doCanvasStuff () {
//Initializing the canvas
var canvas = document.getElementById("canvas");
...
setInterval(draw, 33);
}
</script>
</head>
<body>
<canvas id="canvas" width="500" height="500"></canvas>
</body>
<script>
doCanvasStuff();
</script>
</html>
I'm writing a program that will draw the sine curve with canvas.
HTML:
<canvas id="mycanvas" width="1000" height="100">
Your browser is not supported.
</canvas>
JavaScript:
var canvas = document.getElementById("mycanvas");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.lineWidth = 3;
var x = 0,
y = 0;
var timeout = setInterval(function() {
ctx.beginPath();
ctx.moveTo(x, y);
x += 1;
y = 50 * Math.sin(0.1 * x) + 50;
ctx.lineTo(x, y);
ctx.stroke();
if (x > 1000) {
clearInterval(timeout);
}
}, 10);
}
This works really nice: http://jsfiddle.net/HhGnb/
However, now I can only offer say 100px for the canvas width, so only the leftest 100px of the curve could be seen. http://jsfiddle.net/veEyM/1/
I want to archive this effect: when the right point of the curve is bigger than the width of canvas, the whole curve could move left, so I can see the rightest point of the curve, it's a bit like the curve is flowing to left. Can I do that?
One of the basic ideas of the <canvas> element is that the computer 'forgets' the drawing commands and only saves the pixels, like a bitmap. So to move everything to the left, you need to clear the canvas and draw everything again.
There is also one thing I'd like to advise you - you always start with x = 0 and y = 0, but obviously at x = 0 then y is not necessarily equal to 0 as well. EDIT: implemented this.
Anyway, I ended up with this code: http://jsfiddle.net/veEyM/5/
var canvas = document.getElementById("mycanvas");
var points = {}; // Keep track of the points in an object with key = x, value = y
var counter = 0; // Keep track when the moving code should start
function f(x) {
return 50 * Math.sin(0.1 * x) + 50;
}
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.lineWidth = 3;
var x = 0,
y = f(0);
var timeout = setInterval(function() {
if(counter < 100) { // If it doesn't need to move, draw like you already do
ctx.beginPath();
ctx.moveTo(x, y);
points[x] = y;
x += 1;
y = f(x);
ctx.lineTo(x, y);
ctx.stroke();
if (x > 1000) {
clearInterval(timeout);
}
} else { // The moving part...
ctx.clearRect(0, 0, 100, 100); // Clear the canvas
ctx.beginPath();
points[x] = y;
x += 1;
y = f(x);
for(var i = 0; i < 100; i++) {
// Draw all lines through points, starting at x = i + ( counter - 100 )
// to x = counter. Note that the x in the canvas is just i here, ranging
// from 0 to 100
ctx.lineTo(i, points[i + counter - 100]);
}
ctx.stroke();
}
counter++;
}, 10);
}