I'm still new to javascript.
I'm working on an javascript tutorial from here https://developer.mozilla.org/en-US/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls
One of the more challenging exercise is to make the ball change color when it bounce off from a wall. So far i manage to do this:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = canvas.width/2;
var y = canvas.height-30;
var dx = 2;
var dy = -2;
var ballRadius = 10;
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
function ballColor(){
var newColor = getRandomColor();
return newColor;
}
function drawBall(){
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle=ballColor();
ctx.fill();
ctx.closePath();}
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
drawBall();
x += dx;
y += dy;
if(y+dy>canvas.height-ballRadius||y+dy<ballRadius){
dy = -dy;
}
if(x+dx>canvas.width-ballRadius||x+dx<ballRadius){
dx = -dx;}
};
setInterval(draw,30);
If i run the function draw(), the ball will change color for every frame, making it very "flashing".
How do i get a fix color from getRandomColor() and store it in a variable (let say fixedColorOnly), so that the ball will only display fixedColorOnly until it hit another wall? By then the fixedColorOnly will store another color from getRandomNumber() and bounce and so on.
Thanks in advance.
Just create another global variable for the color. Here's a quick refactor:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<canvas id="myCanvas" style="border: 1px solid black"></canvas>
<script>
var canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d"),
x = canvas.width / 2,
y = canvas.height - 30,
dx = 2,
dy = -2,
ballRadius = 10,
color = getRandomColor();
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = color;
ctx.fill();
ctx.closePath();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBall();
x += dx;
y += dy;
if (y + dy > canvas.height - ballRadius || y + dy < ballRadius) {
dy = -dy;
color = getRandomColor();
}
if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
dx = -dx;
color = getRandomColor();
}
};
setInterval(draw, 30);
</script>
</body>
</html>
Related
I am trying to get this snowflake design to be "drawn out" using a "timer" on javascript. In one of the examples, this is how a circle is drawn:
http://jsfiddle.net/avanhout13/9opengv7/1/
var t = 0;
var c = document.getElementById("myCanvas");
var R = c.width/2;
var ctx = c.getContext("2d");
function doDrawing() {
t = 0;
// Clear the Canvas
ctx.clear();
// Create a random color
var timesRun = 0;
var color = '#'+Math.floor(Math.random()*16777215).toString(16);
// Initial x and y
var x = R+R*Math.cos(0);
var y = R+R*Math.sin(0);
// Start the Drawing
ctx.beginPath();
ctx.strokeStyle = color;
ctx.moveTo(x,y);
//Use the timer to create drawing
var interval = setInterval(function(){
timesRun += 1;
if(timesRun === 65){
clearInterval(interval); }
drawCircle();}, 20);
}
function drawCircle()
{
t += 0.1;
x = Math.floor(R+R*Math.cos(t));
y = Math.floor(R+R*Math.sin(t));
ctx.lineTo(x,y);
ctx.stroke();
}
CanvasRenderingContext2D.prototype.clear =
CanvasRenderingContext2D.prototype.clear || function (preserveTransform) {
if (preserveTransform) {
this.save();
this.setTransform(1, 0, 0, 1, 0, 0);
}
this.clearRect(0, 0, this.canvas.width, this.canvas.height);
if (preserveTransform) {
this.restore();
}
};
This is the snowflake design. I want to do a similar drawing technique but cannot seem to figure out how to get it to actively be drawn when the "draw" button is clicked.
https://jsfiddle.net/avanhout13/g8xs9Ljf/
let canvas = document.getElementById('snowflake'),
ctx = canvas.getContext('2d'),
maxLevel = 2,
branches = 7;
canvas.width = 1000;
canvas.height = 1000;
ctx.translate(canvas.width / 2, canvas.height / 2);
let angle = Math.PI * 2 + Math.random();
for (let i = 0; i < 6; i++) {
drawLine(0);
ctx.rotate(Math.PI * 2 / 6);
}
function drawLine(level) {
if (level > maxLevel) return;
ctx.strokeStyle = "black";
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(200, 0);
ctx.stroke();
for (let i = 1; i < branches + 1; i++) {
ctx.save();
ctx.translate(200 * i / (branches + 1), 0);
ctx.save();
ctx.rotate(angle);
drawLine(level + 1);
ctx.restore();
ctx.save();
ctx.rotate(-angle);
drawLine(level + 1);
ctx.restore();
ctx.restore();
}
}
Any idea of how to get this to draw? Thank you.
Make sure that your js code isn't loaded in file type, otherwise you can not use the function by input it's name in the html tag directly.
In JSFiddle, it could be change by the select label on the top left corner of your js window.
Hope this could be help.
<html lane='en'>
<head>
<meta charset='utf-8'>
<title> Snowflake Spirograph</title>
</head>
<body>
<button onclick="draw()">Start Drawing</button>
<canvas id="snowflake" width="1000" height="1000"></canvas>
</body>
</html>
const canvas = document.getElementById('snowflake');
const ctx = canvas.getContext('2d');
const maxLevel = 2;
const branches = 7;
ctx.translate(canvas.width / 2, canvas.height / 2);
let angle = Math.PI * 2 + Math.random();
function draw() {
for (let i = 0; i < 6; i++) {
drawLine(1);
ctx.rotate(Math.PI * 2 / 6);
}
}
function drawLine(level) {
if (level > maxLevel) return;
ctx.strokeStyle = "black";
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(200, 0);
ctx.stroke();
for (let i = 1; i < branches + 1; i++) {
ctx.save();
ctx.translate(200 * i / (branches + 1), 0);
ctx.save();
ctx.rotate(angle);
drawLine(level + 1);
ctx.restore();
ctx.save();
ctx.rotate(-angle);
drawLine(level + 1);
ctx.restore();
ctx.restore();
}
}
I have been trying to play around with the idea of a Ball class within Javascript that is within an HTML file. Check out my code to see what my hang up is. I have seen people use both a function and a class to accomplish this but I can't seem to get this to work. I feel like I am doing more of a C++ style rather than Javascript. Any suggestions?
class Ball {
constructor(x, y, radius, dx, dy) {
this.x = x;
this.y = y;
this.radius = radius;
this.dx = dx;
this.dy = dy;
}
get X() {
return this.x;
}
get Y() {
return this.y;
}
get Radius() {
return this.radius;
}
get Dx() {
return this.dx;
}
get Dy() {
return this.dy;
}
drawBall() {
ctx.beginPath();
ctx.arc(get X(), get Y(), get Radius(), 0, Math.PI*2);
ctx.fillStyle() = "black";
ctx.fill();
ctx.closePath();
}
};
var Ball1 = new Ball(canvas.width/2, canvas.height-30, 10, 2, -2);
function drawBall() {
ctx.beginPath();
ctx.arc(get X(), get Y(), get Radius(), 0, Math.PI*2);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBall();
drawBall2();
if((Ball1.get X() + Ball1.get Dx()) > canvas.width-Ball1.get Radius() || (Ball1.get X() + Ball1.get Dx()) < Ball1.get Radius()) {
Ball1.set Dx(-(Ball1.get Dx()));
}
if(Ball1.get Y() + Ball1.get Dy() > canvas.height-Ball1.get Radius() || y + dy < ballRadius) {
dy = -dy;
}
if(x2 + dx2 > canvas.width-ballRadius || x2 + dx2 < ballRadius) {
dx2 = -dx2;
}
if(y2 + dy2 > canvas.height-ballRadius || y2 + dy2 < ballRadius) {
dy2 = -dy2;
}
x += dx;
y += dy;
x2 += dx2;
y2 += dy2;
}
I know there are discrepancies in my code like things not matching but I don't think I am on the right track. Thanks ahead of time!
EDIT!
Here is the code that I started with that works so far:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>My Game</title>
<style>
* { padding: 0; margin: 0; }
canvas { background: #eee; display: block; margin: 0 auto; }
</style>
</head>
<body>
<canvas id="myCanvas" width="600" height="580"></canvas>
<script>
//Javascript goes here
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 10;
//ball 1
var x = canvas.width/2;
var y = canvas.height-30;
var dx = 2;
var dy = -2;
//ball 2
var x2 = canvas.width/3;
var y2 = canvas.height-30;
var dy2 = -4;
var dx2 = 4;
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
}
function drawBall2() {
ctx.beginPath();
ctx.arc(x2, y2, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "red";
ctx.fill();
ctx.closePath();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBall();
drawBall2();
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if(y + dy > canvas.width-ballRadius || y + dy < ballRadius) {
dy = -dy;
}
if(x2 + dx2 > canvas.width-ballRadius || x2 + dx2 < ballRadius) {
dx2 = -dx2;
}
if(y2 + dy2 > canvas.height-ballRadius || y2 + dy2 < ballRadius) {
dy2 = -dy2;
}
x += dx;
y += dy;
x2 += dx2;
y2 += dy2;
}
setInterval(draw, 10);
</script>
</body>
</html>
I fixed your code a little bit just to give you an Idea. This is still not a very good code design. The example will only work in modern Browsers because you use es6 features like class. I think you should start with some javascript fundamentals first.
"use strict";
class Ball {
constructor(x, y, radius, dx, dy) {
this.x = x;
this.y = y;
this.radius = radius;
this.dx = dx;
this.dy = dy;
}
get X() {
return this.x;
}
get Y() {
return this.y;
}
get Radius() {
return this.radius;
}
get Dx() {
return this.dx;
}
get Dy() {
return this.dy;
}
draw(ctx) {
ctx.beginPath();
ctx.arc(this.X, this.Y, this.Radius, 0, Math.PI * 2);
ctx.fillStyle = "black";
ctx.stroke();
}
};
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var Ball1 = new Ball(canvas.width / 2, canvas.height - 30, 10, 2, -2);
Ball1.draw(ctx);
<canvas id="myCanvas" width="200" height="200"></canvas>
Simple Javascript
var canvas = document.getElementById("my-canvas");
var ctx = canvas.getContext("2d");
function drawBall(ctx, x, y, r) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.fillStyle = "black";
ctx.stroke();
}
drawBall(ctx, canvas.width / 2, canvas.height - 30, 10, 2, -2);
I just saw this question ball bounce while searching for some JavaScript code. Its easy code but what to do if we want to change the color randomly of the ball every time it bounces off the wall.
My thoughts:
Have a random color generator and use it. Something like this
function get_random_color() {
var letters = 'ABCDE'.split('');
var color = '#';
for (var i=0; i<3; i++ ) {
color += letters[Math.floor(Math.random() * letters.length)];
}
return color;
}
But how to change the color of the ball. I tried context.fill() but no help
Should be as straight forward as calling the function when the ball hits a wall, like this
function myFunction() {
var context;
var dx = 4;
var dy = 4;
var y = 150;
var x = 10;
var color = get_random_color();
function draw() {
context = myCanvas.getContext('2d');
context.clearRect(0, 0, 400, 400);
context.beginPath();
context.fillStyle = color;
context.arc(x, y, 10, 0, Math.PI * 2, true);
context.closePath();
context.fill();
if (x < 0 || x > 400) {
dx = -dx;
color = get_random_color();
}
if (y < 0 || y > 300) {
dy = -dy;
color = get_random_color();
}
x += dx;
y += dy;
}
setInterval(draw, 10);
}
FIDDLE
On an HTML5 canvas I can't find a method to make colored circles. I've been consulting this as a reference.
Here is my current attempt
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillRect(20, 20, 100, 100);
ctx.lineJoin = "round";
ctx.lineWidth = "cornerRadius";
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
(Also on jsFiddle: http://jsfiddle.net/kvnm21r1/1/)
I've tried using the canvas arc method, which creates a circle, but doesn't color it.
I can't use the border-radius property, because ctx is not an element.
Is there any way, I can transform my squares into circles?
Thanks in advance.
You can use quadratic curves to "round-out" the straight lines of your square until they form a circle.
// change sideCount to the # of poly sides desired
//
var sideCount = 4;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.lineWidth = 2;
ctx.fillStyle = randomColor();
var PI2 = Math.PI * 2;
var cx = 150;
var cy = 150;
var radius = 100;
var xx = function (a) {
return (cx + radius * Math.cos(a));
}
var yy = function (a) {
return (cy + radius * Math.sin(a));
}
var lerp = function (a, b, x) {
return (a + x * (b - a));
}
var sides = [];
for (var i = 0; i < sideCount; i++) {
sides.push(makeSide(i, sideCount));
}
var percent = 0;
var percentDirection = 0.50;
$("#toShape").click(function () {
percentDirection = -0.50;
})
$("#toCircle").click(function () {
percentDirection = 0.50;
})
animate();
// functions
function animate() {
requestAnimationFrame(animate);
drawSides(percent);
percent += percentDirection;
if (percent > 100) {
percent = 100;
}
if (percent < 0) {
percent = 0;
}
}
function drawSides(pct, color) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (pct == 100) {
ctx.beginPath();
ctx.arc(cx, cy, radius, 0, PI2);
ctx.closePath();
ctx.fill();
} else {
ctx.beginPath();
ctx.moveTo(sides[0].x0, sides[0].y0);
for (var i = 0; i < sideCount; i++) {
var side = sides[i];
var cpx = lerp(side.midX, side.cpX, pct / 100);
var cpy = lerp(side.midY, side.cpY, pct / 100);
ctx.quadraticCurveTo(cpx, cpy, side.x2, side.y2);
}
ctx.fill();
}
}
function makeSide(n, sideCount) {
var sweep = PI2 / sideCount;
var sAngle = sweep * (n - 1);
var eAngle = sweep * n;
var x0 = xx(sAngle);
var y0 = yy(sAngle);
var x1 = xx((eAngle + sAngle) / 2);
var y1 = yy((eAngle + sAngle) / 2);
var x2 = xx(eAngle);
var y2 = yy(eAngle);
var dx = x2 - x1;
var dy = y2 - y1;
var a = Math.atan2(dy, dx);
var midX = lerp(x0, x2, 0.50);
var midY = lerp(y0, y2, 0.50);
var cpX = 2 * x1 - x0 / 2 - x2 / 2;
var cpY = 2 * y1 - y0 / 2 - y2 / 2;
return ({
x0: x0,
y0: y0,
x2: x2,
y2: y2,
midX: midX,
midY: midY,
cpX: cpX,
cpY: cpY,
color: randomColor()
});
}
function randomColor() {
return ('#' + Math.floor(Math.random() * 16777215).toString(16));
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id="toShape">Animate to Shape</button>
<button id="toCircle">Animate to Circle</button><br>
<canvas id="canvas" width=300 height=300></canvas>
JSfiddle with a circle
To draw a circle you'll need to draw an arc and have a starting angle and an ending angle. So you'll have to use Pi and define a radius.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var radius = 70;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#003300';
context.stroke();
Avoid w3schools.com whenever possible. Refer to sites like MDN instead.
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");
ctx.beginPath();
var radius = 50; // Arc radius
var startAngle = 0; // Starting point on circle
var endAngle = Math.PI*2; // End point on circle
ctx.arc(150, 75, radius, startAngle, endAngle, true);
ctx.fill();
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
I'm trying to plot a pie chart using HTML5 and Canvas.
Here below is my working example in jsfiddle.
http://jsfiddle.net/2mf8gt2c/
I need to show the values inside of the pie chart.
i.e
var myColor = ["Green","Red","Blue"];
var myData = [30,60,10];
The value should be displayed inside the pie chart. How can I achieve that?
The full code is available below.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>My Title</title>
</head>
<body>
<section>
<div>
<table width="80%" cellpadding=1 cellspacing=1 border=0>
<tr>
<td width=50%><canvas id="canvas" align="center" width="400" height="250"> This text is displayed if your browser does not support HTML5 Canvas. </canvas>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var myColor = ["Green","Red","Blue"];
var myData = [30,60,10];
function degreesToRadians(degrees) {
return (degrees * Math.PI)/180;
}
function sumTo(a, i) {
var sum = 0;
for (var j = 0; j < i; j++) {
sum += a[j];
}
return sum;
}
function getTotal(){
var myTotal = 0;
for (var j = 0; j < myData.length; j++) {
myTotal += (typeof myData[j] == 'number') ? myData[j] : 0;
}
return myTotal;
}
var drawSegmentLabel = function(canvas, context, i)
{
context.save();
var x = Math.floor(250 / 2);
var y = Math.floor(100 / 2);
var angle;
var angleD = sumTo(myData, i);
var flip = (angleD < 90 || angleD > 270) ? false : true;
context.translate(x, y);
if (flip) {
angleD = angleD-180;
context.textAlign = "left";
angle = degreesToRadians(angleD);
context.rotate(angle);
context.translate(-(x + (canvas.width * 0.5))+15, -(canvas.height * 0.05)-10);
}
else {
context.textAlign = "right";
angle = degreesToRadians(angleD);
context.rotate(angle);
}
var fontSize = Math.floor(canvas.height / 25);
context.font = fontSize + "pt Helvetica";
context.fillStyle = "black";
var dx = Math.floor(250 * 0.5) - 10;
var dy = Math.floor(100 * 0.05);
context.fillText(myData[i], dx, dy);
context.restore();
}
function plotData()
{
var canvas;
var ctx;
var lastend = 0;
var myTotal = getTotal();
var pRadius = 100;
var xPie=250;
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
ctx.imageSmoothingEnabled = true;
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < myData.length; i++)
{
ctx.fillStyle = myColor[i];
ctx.beginPath();
ctx.moveTo(xPie,pRadius+10);
ctx.arc(xPie,pRadius+10,pRadius,lastend,lastend +
(Math.PI*2*(myData[i]/myTotal)),false);
ctx.lineTo(xPie,pRadius+10);
ctx.fill();
lastend += Math.PI*2*(myData[i]/myTotal);
ctx.lineWidth = 2;
ctx.strokeStyle = '#000000';
ctx.stroke();
}
}
plotData();
</script>
</section>
</body>
</html>
Can someone help me to get this done?
Thanks,
Kimz
Here's an alternate way to draw a wedge with a specified starting & ending angle:
ctx.beginPath();
ctx.moveTo(cx,cy);
ctx.arc(cx,cy,radius,startAngle,endAngle,false);
ctx.closePath();
ctx.fillStyle=fill;
ctx.strokeStyle='black';
ctx.fill();
ctx.stroke();
I suggest this alternate method because you can easily calculate the angle exactly between the starting & ending angle like this:
var midAngle=startAngle+(endAngle-startAngle)/2;
And given the midAngle, you can use some trigonometry to calculate where to draw your values inside the wedge:
// draw the value labels 75% of the way from centerpoint to
// the outside of the wedge
var labelRadius=radius*.75;
// calculate the x,y at midAngle
var x=cx+(labelRadius)*Math.cos(midAngle);
var y=cy+(labelRadius)*Math.sin(midAngle);
Here's example code and a Demo:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
ctx.lineWidth = 2;
ctx.font = '12px verdana';
var PI2 = Math.PI * 2;
var myColor = ["Green", "Red", "Blue"];
var myData = [30, 60, 10];
var cx = 150;
var cy = 150;
var radius = 100;
pieChart(myData, myColor);
function pieChart(data, colors) {
var total = 0;
for (var i = 0; i < data.length; i++) {
total += data[i];
}
var sweeps = []
for (var i = 0; i < data.length; i++) {
sweeps.push(data[i] / total * PI2);
}
var accumAngle = 0;
for (var i = 0; i < sweeps.length; i++) {
drawWedge(accumAngle, accumAngle + sweeps[i], colors[i], data[i]);
accumAngle += sweeps[i];
}
}
function drawWedge(startAngle, endAngle, fill, label) {
// draw the wedge
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.arc(cx, cy, radius, startAngle, endAngle, false);
ctx.closePath();
ctx.fillStyle = fill;
ctx.strokeStyle = 'black';
ctx.fill();
ctx.stroke();
// draw the label
var midAngle = startAngle + (endAngle - startAngle) / 2;
var labelRadius = radius * .75;
var x = cx + (labelRadius) * Math.cos(midAngle);
var y = cy + (labelRadius) * Math.sin(midAngle);
ctx.fillStyle = 'white';
ctx.fillText(label, x, y);
}
body {
background-color: ivory;
padding: 10px;
}
#canvas {
border: 1px solid red;
}
<canvas id="canvas" width=400 height=300></canvas>