Related
I am trying to achieve a tracing effect where the lines have a faded trail. The way I am trying to do it is simply by drawing the solid background once, and then on further frames draw a transparent background before drawing the new lines, so that you can still see a little of the image before it.
The issue is that I do want the lines to fade out completely after some time, but they seem to leave a permanent after image, even after drawing over them repeatedly.
I've tried setting different globalCompositeOperation(s) and it seemed like I was barking up the wrong tree there.
This code is called once
//initiate trace bg
traceBuffer.getContext("2d").fillStyle = "rgba(0, 30, 50, 1)";
traceBuffer.getContext("2d").fillRect(0, 0, traceBuffer.width, traceBuffer.height);
then inside the setInterval function it calls
//draw transparent background
ctx.fillStyle = "rgba(0, 30, 50, 0.04)";
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
//set drawing settings
ctx.strokeStyle = "#AAAAAA";
ctx.lineWidth = 4;
for (let i = 0; i < tracer.layer2.length; i++){
ctx.beginPath();
ctx.moveTo(newX, newY);
ctx.lineTo(oldX, oldY);
ctx.stroke();
}
Here's an example: https://i.imgur.com/QTkeIVf.png
On the left is what I am currently getting, and on the right is the edit of what I actually want to happen.
This is how I would do it. I would build a history of the particles moving on the track. The older the position the smaller the value of the alpha value for the fill. Also for a nicer effect I would reduce the size of the circle.
I hope this is what you need.
PS: I would have loved to have your curve. Since I don't have it I've drawn a different one.
const hypotrochoid = document.getElementById("hypotrochoid");
const ctx = hypotrochoid.getContext("2d");
const cw = (hypotrochoid.width = 300);
const ch = (hypotrochoid.height = 300);
const cx = cw / 2,
cy = ch / 2;
ctx.lineWidth = 1;
ctx.strokeStyle = "#d9d9d9";
// variables for the hypotrochoid
let a = 90;
let b = 15;
let h = 50;
// an array where to save the points used to draw the track
let track = [];
//add points to the track array. This will be used to draw the track for the particles
for (var t = 0; t < 2 * Math.PI; t += 0.01) {
let o = {};
o.x = cx + (a - b) * Math.cos(t) + h * Math.cos((a - b) / b * t);
o.y = cy + (a - b) * Math.sin(t) - h * Math.sin((a - b) / b * t);
track.push(o);
}
// a function to draw the track
function drawTrack(ry) {
ctx.beginPath();
ctx.moveTo(ry[0].x, ry[0].y);
for (let t = 1; t < ry.length; t++) {
ctx.lineTo(ry[t].x, ry[t].y);
}
ctx.closePath();
ctx.stroke();
}
// a class of points that are moving on the track
class Point {
constructor(pos) {
this.pos = pos;
this.r = 3;//the radius of the circle
this.history = [];
this.historyLength = 40;
}
update(newPos) {
let old_pos = {};
old_pos.x = this.pos.x;
old_pos.y = this.pos.y;
//save the old position in the history array
this.history.push(old_pos);
//if the length of the track is longer than the max length allowed remove the extra elements
if (this.history.length > this.historyLength) {
this.history.shift();
}
//gry the new position on the track
this.pos = newPos;
}
draw() {
for (let i = 0; i < this.history.length; i++) {
//calculate the alpha value for every element on the history array
let alp = i * 1 / this.history.length;
// set the fill style
ctx.fillStyle = `rgba(0,0,0,${alp})`;
//draw an arc
ctx.beginPath();
ctx.arc(
this.history[i].x,
this.history[i].y,
this.r * alp,
0,
2 * Math.PI
);
ctx.fill();
}
}
}
// 2 points on the track
let p = new Point(track[0]);
let p1 = new Point(track[~~(track.length / 2)]);
let frames = 0;
let n, n1;
function Draw() {
requestAnimationFrame(Draw);
ctx.clearRect(0, 0, cw, ch);
//indexes for the track position
n = frames % track.length;
n1 = (~~(track.length / 2) + frames) % track.length;
//draw the track
drawTrack(track);
// update and draw the first point
p.update(track[n]);
p.draw();
// update and draw the second point
p1.update(track[n1]);
p1.draw();
//increase the frames counter
frames++;
}
Draw();
canvas{border:1px solid}
<canvas id="hypotrochoid"></canvas>
I'm attempting to draw the rotating line in this canvas animation with trailing opacity but it's not working. I've seen this effect with rectangles and arcs but never with a line, so I'm not sure what I need to add.
function radians(degrees) {
return degrees * (Math.PI / 180);
}
var timer = 0;
function sonar() {
var canvas = document.getElementById('sonar');
if (canvas) {
var ctx = canvas.getContext('2d');
var cx = innerWidth / 2,
cy = innerHeight / 2;
canvas.width = innerWidth;
canvas.height = innerHeight;
//ctx.clearRect(0, 0, innerWidth, innerHeight);
ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
ctx.fillRect(0, 0, innerWidth, innerHeight);
var radii = [cy, cy - 30, innerHeight / 3.33, innerHeight / 6.67];
for (var a = 0; a < 4; a++) {
ctx.beginPath();
ctx.arc(cx, cy, radii[a], radians(0), radians(360), false);
ctx.strokeStyle = 'limegreen';
ctx.stroke();
ctx.closePath();
}
// draw grid lines
for (var i = 0; i < 12; i++) {
var x = cx + cy * Math.cos(radians(i * 30));
var y = cy + cy * Math.sin(radians(i * 30));
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.lineTo(x, y);
ctx.lineCap = 'round';
ctx.strokeStyle = 'rgba(50, 205, 50, 0.45)';
ctx.stroke();
ctx.closePath();
}
if (timer <= 360) {
timer++;
ctx.beginPath();
ctx.fillstyle = 'limegreen';
ctx.moveTo(cx, cy);
ctx.lineTo(cx + cy * Math.cos(radians(timer)), cy + cy * Math.sin(radians(timer)));
ctx.strokeStyle = 'limegreen';
ctx.stroke();
ctx.closePath();
} else {
timer = 0;
}
requestAnimationFrame(sonar);
}
}
sonar();
jsbin example
Here are two ways to do this: with a gradient and by adding translucent lines.
Sidenote, you should try and only redraw what you need to redraw. I separated the canvases and put one on top of the other so that we don't redraw the grid all the time.
function radians(degrees) {
return degrees * (Math.PI / 180);
}
var timer = 0;
function trail() {
var canvas = document.getElementById('trail');
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, innerWidth, innerHeight);
var cx = innerWidth / 2,
cy = innerHeight / 2;
canvas.width = innerWidth;
canvas.height = innerHeight;
if (timer <= 360) {
timer++;
ctx.beginPath();
ctx.fillstyle = 'limegreen';
ctx.moveTo(cx, cy);
ctx.arc(cx,cy,cy,radians(timer-30),radians(timer));
ctx.lineTo(cx + cy * Math.cos(radians(timer)), cy + cy * Math.sin(radians(timer)));
var gradient = ctx.createLinearGradient(
cx+cy*Math.cos(radians(timer)), cy+cy*Math.sin(radians(timer)),
cx+cy*0.9*Math.cos(radians(timer-30)), cy+cy*0.9*Math.sin(radians(timer-30)));
gradient.addColorStop(0,'limegreen');
gradient.addColorStop(1,'transparent');
ctx.strokeStyle='transparent';
ctx.fillStyle = gradient;
ctx.fill();
ctx.beginPath();
var fade = 10;
for(var i =0;i<fade;i++)
{
ctx.moveTo(cx, cy);
ctx.lineTo(cx+cy*Math.cos(radians(180+timer-i*1.3)),cy+cy*Math.sin(radians(180+timer-i*1.3)));
ctx.strokeStyle ="rgba(50,205,50,0.1)";
ctx.lineWidth=5;
ctx.closePath();
ctx.stroke();
}
} else {
timer = 0;
}
requestAnimationFrame(trail);
}
function sonar() {
var canvas = document.getElementById('sonar');
if (canvas) {
var ctx = canvas.getContext('2d');
var cx = innerWidth / 2,
cy = innerHeight / 2;
canvas.width = innerWidth;
canvas.height = innerHeight;
//ctx.clearRect(0, 0, innerWidth, innerHeight);
var radii = [cy, cy - 30, innerHeight / 3.33, innerHeight / 6.67];
for (var a = 0; a < 4; a++) {
ctx.beginPath();
ctx.arc(cx, cy, radii[a], radians(0), radians(360), false);
ctx.strokeStyle = 'limegreen';
ctx.stroke();
ctx.closePath();
}
// draw grid lines
for (var i = 0; i < 12; i++) {
var x = cx + cy * Math.cos(radians(i * 30));
var y = cy + cy * Math.sin(radians(i * 30));
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.lineTo(x, y);
ctx.lineCap = 'round';
ctx.strokeStyle = 'rgba(50, 205, 50, 0.45)';
ctx.stroke();
ctx.closePath();
}
}
}
sonar();
trail();
canvas{
position: absolute;
}
<canvas id=sonar></canvas>
<canvas id=trail></canvas>
The problem is that to get this effect, you need to draw a triangle with a gradient along an arc, and you can't do that in a canvas. Gradients must be linear or radial.
The other option is to have an inner loop run each time you want to draw the sweeper, and go backwards from your sweeper line, drawing with slightly less opacity each time. But lets say you want your sweep to cover 15 degrees--obviously, if you have a 100% opacity line at d and a 5% opacity line at d - 15, that doesn't do the trick. So start filling in more lines, and more lines...you will have to draw so many lines to make it seem filled your performance would probably suffer.
My suggestion--you shouldn't have to redraw that on every frame. I would just make a PNG that looks like you want it to, and then place it and just rotate it around the center on each frame. No need to redraw it all the time then. That will be much faster than drawing a bunch of lines.
Canvas stack trails.
Below is a quick demo of how to use a stack of canvases to create a trailing effect.
You have a normal on screen canvas (this FX will not effect it) and then a stack of canvases for the trail FX. Each frame you move to the next canvas in the stack, first slightly clearing it then drawing to it what you want to trail. Then you render that canvas and the one just above it to the canvas.
A point to keep in mind is that the trails can also have a hugh range of FX, like blurring (just render each frame stack on itself slightly offset each time you render to it), zoom in and out trails. Trails on top or trails under. You can change the trail distance and much more.
It is overkill but over kill is fun.
The slider above the demo controls the trail length. Also the code need babel because I dont have time to write it for ES5.
Top slider is trail amount.One under that is trail distance. Trail dist does not transition well. Sorry about that.
//==============================================================================
// helper function
function $(query,q1){
if(q1 !== undefined){
if(typeof query === "string"){
var e = document.createElement(query);
if(typeof q1 !== "string"){
for(var i in q1){
e[i] = q1[i];
}
}else{
e.id = q1;
}
return e;
}
return [...query.querySelectorAll(q1)];
}
return [...document.querySelectorAll(query)];
}
function $$(element,e1){
if(e1 !== undefined){
if(typeof element === "string"){
$(element)[0].appendChild(e1);
return e1;
}
element.appendChild(e1);
return e1;
}
document.body.appendChild(element);
return element;
}
function $E(element,types,listener){
if(typeof types === "string"){
types = types.split(",");
}
element = $(element)[0];
types.forEach(t=>{
element.addEventListener(t,listener)
});
return element;
}
function R(I){
if(I === undefined){
return Math.random();
}
return Math.floor(Math.random()*I);
}
//==============================================================================
//==============================================================================
// answer code
// canvas size
const size = 512;
const trailDist = 10; // There is this many canvases so be careful
var trailDistCurrent = 10; // distance between trails
var clearAll = false;
// create a range slider for trail fade
$$($("input",{type:"range",width : size, min:0, max:100, step:0.1, value:50, id:"trail-amount",title:"Trail amount"}));
$("#trail-amount")[0].style.width = size + "px";
$E("#trail-amount","change,mousemove",function(e){fadeAmount = Math.pow(this.value / 100,2);});
// create a range slider trail distance
$$($("input",{type:"range",width : size, min:2, max:trailDist , step:1, value:trailDist , id:"trail-dist",title:"Trail seperation"}));
$("#trail-dist")[0].style.width = size + "px";
$E("#trail-dist","change,mousemove", function(e){
if(this.value !== trailDistCurrent){
trailDistCurrent= this.value;
clearAll = true;
}
});
$$($("br","")) // put canvas under the slider
// Main canvas
var canvas;
$$(canvas = $("canvas",{width:size,height:size})); // Not jquery. Just creates a canvas
// and adds canvas to the document
var ctx = canvas.getContext("2d");
// Trailing canvas
var trailCanvases=[];
var i =0; // create trail canvas
while(i++ < trailDist){trailCanvases.push($("canvas",{width:size,height:size}));}
var ctxT = trailCanvases.map(c=>c.getContext("2d")); // get context
var topCanvas = 0;
var fadeAmount = 0.5;
// Draw a shape
function drawShape(ctx,shape){
ctx.lineWidth = shape.width;
ctx.lineJoin = "round";
ctx.strokeStyle = shape.color;
ctx.setTransform(shape.scale,0,0,shape.scale,shape.x,shape.y);
ctx.rotate(shape.rot);
ctx.beginPath();
var i = 0;
ctx.moveTo(shape.shape[i++],shape.shape[i++]);
while(i < shape.shape.length){
ctx.lineTo(shape.shape[i++],shape.shape[i++]);
}
ctx.stroke();
}
// Create some random shapes
var shapes = (function(){
function createRandomShape(){
var s = [];
var len = Math.floor(Math.random()*5 +4)*2;
while(len--){
s[s.length] = (R() + R()) * 20 * (R() < 0.5 ? -1 : 1);
}
return s;
}
var ss = [];
var i = 10;
while(i--){
ss[ss.length] = createRandomShape();
}
ss[ss.length] = [0,0,300,0]; // create single line
return ss;
})();
// Create some random poits to move the shapes
var points = (function(){
function point(){
return {
color : "hsl("+R(360)+",100%,50%)",
shape : shapes[R(shapes.length)],
width : R(4)+1,
x : R(size),
y : R(size),
scaleMax : R()*0.2 + 1,
scale : 1,
s : 0,
rot : R()*Math.PI * 2,
dr : R()*0.2 -0.1,
dx : R()*2 - 1,
dy : R()*2 - 1,
ds : R() *0.02 + 0.01,
}
}
var line = shapes.pop();
var ss = [];
var i = 5;
while(i--){
ss[ss.length] = point();
}
var s = ss.pop();
s.color = "#0F0";
s.x = s.y = size /2;
s.dx = s.dy = s.ds = 0;
s.scaleMax = 0.5;
s.dr = 0.02;
s.shape = line;
s.width = 6;
ss.push(s);
return ss;
})();
var frameCount = 0; // used to do increamental fades for long trails
function update(){
// to fix the trail distance problem when fade is low and distance high
if(clearAll){
ctxT.forEach(c=>{
c.setTransform(1,0,0,1,0,0);
c.clearRect(0,0,size,size);
});
clearAll = false;
}
frameCount += 1;
// get the next canvas that the shapes are drawn to.
topCanvas += 1;
topCanvas %= trailDistCurrent;
var ctxTop = ctxT[topCanvas];
// clear the main canvas
ctx.setTransform(1,0,0,1,0,0); // reset transforms
// Fade the trail canvas
ctxTop.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,size,size); // clear main canvas
// slowly blendout trailing layer
if(fadeAmount < 0.1){ // fading much less than this leaves perminant trails
// so at low levels just reduce how often the fade is done
if(((Math.floor(frameCount/trailDistCurrent)+topCanvas) % Math.ceil(1 / (fadeAmount * 10))) === 0 ){
ctxTop.globalAlpha = 0.1;
ctxTop.globalCompositeOperation = "destination-out";
ctxTop.fillRect(0,0,size,size);
}
}else{
ctxTop.globalAlpha = fadeAmount;
ctxTop.globalCompositeOperation = "destination-out";
ctxTop.fillRect(0,0,size,size);
}
ctxTop.globalCompositeOperation = "source-over";
ctxTop.globalAlpha = 1;
// draw shapes
for(var i = 0; i < points.length; i ++){
var p = points[i];
p.x += p.dx; // move the point
p.y += p.dy;
p.rot += p.dr;
p.s += p.ds;
p.dr += Math.sin(p.s) * 0.001;
p.scale = Math.sin(p.s) * p.scaleMax+1;
p.x = ((p.x % size) + size) % size;
p.y = ((p.y % size) + size) % size;
drawShape(ctxTop,p); // draw trailing layer (middle)
}
// draw the trail the most distance from the current position
ctx.drawImage(trailCanvases[(topCanvas + 1)%trailDistCurrent],0,0);
// do it all again.
requestAnimationFrame(update);
}
update();
I wrote a simple canvas with several bubbles that float around. They are supposed to be green when not colliding and red when any of them are. For some reason they are all green but one. And when the bubbles collide the only ones that turn red are the ones touching that original bubble that wont start off green. I know I am missing something really obvious to you guys, but I went over it a thousand times and just can't see it. If anyone can please let me know, I am ready to feel stupid... thanks.
Here is a link to the GitHub gist:
https://gist.github.com/anonymous/e172bb18c078a2e9a797b8a30fdafcc3
Here is a snippet from the collision detection to drawing the canvas:
// Draw to Canvas
var draw = function() {
ctx.clearRect(0,0,600,400);
for(var i = 0 ; i < spawnArr.length; i++){
// Collision Detect & Correct
for(var j = 0; j < spawnArr.length; j++) {
var dx = spawnArr[i].x - spawnArr[j].x;
var dy = spawnArr[i].y - spawnArr[j].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < spawnArr[i].rad + spawnArr[j].rad) {
ctx.strokeStyle = "#FF0000";
ctx.beginPath();
ctx.arc(spawnArr[i].x, spawnArr[i].y, spawnArr[i].rad, 0, 2*Math.PI);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.arc(spawnArr[j].x, spawnArr[j].y, spawnArr[j].rad, 0, 2*Math.PI);
ctx.closePath();
ctx.stroke();
// console.log('hit');
}
else {
ctx.strokeStyle = "#00FF00";
ctx.beginPath();
ctx.arc(spawnArr[i].x, spawnArr[i].y, spawnArr[i].rad, 0, 2*Math.PI);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.arc(spawnArr[j].x, spawnArr[j].y, spawnArr[j].rad, 0, 2*Math.PI);
ctx.closePath();
ctx.stroke();
//console.log('miss');
}
}
The problem is you are drawing over the circles many times. When a circle is touching another you draw it red, then if it does not hit the next circle you draw it green. Also you are checking if the circle hit itself, so you draw all the circles red twice It can only be green or red, and it should only be drawn once.
The following will solve you problems and make it run somewhat quicker. I have added a style to each circle that defines its colour. It test for a hit and if found set the colour to red.
The second for loop starts from the position of the first for loop plus one. There is no point in checking if B hit A when you already know A hit B
// Draw to Canvas
var draw = function () {
ctx.clearRect(0, 0, 600, 400);
function drawThing(thing) {
ctx.strokeStyle = thing.style;
ctx.beginPath();
ctx.arc(thing.x, thing.y, thing.rad, 0, 2 * Math.PI);
ctx.stroke();
}
for (var i = 0; i < spawnArr.length; i++) {
var t1 = spawnArr[i];
var t1.style = "#00FF00";
// Collision Detect & Correct
for (var j = i + 1; j < spawnArr.length; j++) {
var t2 = spawnArr[j];
var dx = t1.x - t2.x;
var dy = t1.y - t2.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < t1.rad + t2.rad) {
t1.style = "#FF0000";
}
}
drawThing(t1);
}
}
I'm working on a game to play in canvas, and was wanting to add some ambiance to a background layer using javascript. To start, here is the code...
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");
var x = canvas.width/2;
var y = canvas.height-150;
var dx = Math.random() * (-5 * 5) + 15;
var dy = -15;
function drawDot() {
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI*2);
ctx.fillStyle = "black";
ctx.fill();
ctx.closePath();
};
function move() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawDot();
x += dx;
y += dy;
};
setInterval(move, 50);
If you run that, you can see that what I have is a black ball that moves up and off the page inside a random conal space. What I need help with is figuring out the best way to:
A. Populate it with more balls (maybe like 2-3) that are on their own random trajectory, and
B. Make it so those 2-3 balls are constantly animating inside the random cone area off the page from the same starting area (kind of like a constant spurting fountain effect).
A problem I can already see is that by using the console log, the 1 working ball I have now just keeps going off into infinity outside the canvas, so when I try to add a new one it won't run the function. I'm very new to javascript and especially canvas so apologies if this is obvious!
Thank you for any help with this!
There is a good tutorial by Seb Lee-Delisle on this exact problem here:
https://vimeo.com/36278748
Basically you have to encapsulate each Dot so it knows about its own position and acceleration.
EDIT 1
Here is an example using you own code:
document.body.innerHTML = '<canvas height="600" width="600" id="myCanvas"></canvas>';
clearInterval(interval);
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var dotArray = [];
function Dot() {
var dot = {
y : canvas.height / 2,
x : canvas.width / 2,
speedX : Math.random() * ( - 5 * 5) + 15,
speedY : Math.random() * ( - 5 * 5) + 15,
age : 0,
draw : function () {
this.x += this.speedX;
this.y += this.speedY;
ctx.beginPath();
ctx.arc(this.x, this.y, 10, 0, Math.PI * 2);
ctx.fillStyle = 'black';
ctx.fill();
ctx.closePath();
}
};
return dot;
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < dotArray.length; i++) {
dotArray[i].draw();
dotArray[i].age++;
if (dotArray[i].age > 20) {
dotArray.splice(i, 1);
}
}
dotArray.push(new Dot());
}
draw();
var interval = setInterval(draw, 1000 / 60);
I'm trying to fill an ellipse that I've made, but although I can get it to draw the outline, I can't get it to fill it. I've looked at a bunch of resources, including http://www.html5canvastutorials.com/tutorials/html5-canvas-shape-fill/ and https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Drawing_shapes, but following the advice there didn't fix the problem. I've tried to account for other errors - like spelling mistakes, errors with passing parameters, or errors with my ellipse-drawing method, but they all work independently just fine. I can draw the outline of ellipse. I can pass the context to a function. I can fill a non-ellipse. But I can't get my ellipse to fill. Here is what the code looks like:
main();
function main(){
var canvas = document.getElementById('landscape');
var context = canvas.getContext('2d');
// var mySky = new sky(0, 0);
// mySky.render(context);
var myLake = new lake(400, 500, context);
myLake.render(context);
var ctx = context;
ctx.beginPath();
ctx.moveTo(75,50);
ctx.lineTo(100,75);
ctx.lineTo(100,25);
ctx.fill();
}
function lake(x, y, context){
this.context = context;
this.x = x;
this.y = y;
var width = this.context.canvas.width/2;
var height = this.context.canvas.height/4;
var a = width/2;
var b = height/2;
var phi = Math.PI/2;
this.render = function(context){
var inc = (2*Math.PI)/200;
var end = 200*inc;
var oldX = oldY = newX = newY = 0;
var x_0 = xcoord(0);
var y_0 = ycoord(0);
console.log("" + x_0 + ", " + y_0);
var i = 0;
context.beginPath();
context.moveTo(x_0, y_0);
while(i < end){
i += inc;
newX = xcoord(i);
newY = ycoord(i);
context.lineTo(newX, newY);
context.moveTo(newX, newY);
console.log("" + newX + ", " + newY);
}
context.lineTo(x_0, y_0); // close up the ellipse
context.moveTo(x_0, y_0);
context.closePath();
context.fillStyle = '#6EB1F5';
context.fill();
}
function xcoord(t){
return x + a*Math.cos(t)*Math.sin(phi) + b*Math.sin(t)*Math.cos(phi);
}
function ycoord(t){
return y + a*Math.cos(t)*Math.cos(phi) - b*Math.sin(t)*Math.sin(phi);
}
Am I using the fill() function correctly? Is it because my ellipse isn't closed up properly? Please don't give me too much information if possible - I'd like to do it on my own, I just can't figure out what's wrong and I've spent nearly 3 hours trying to figure this out now.
Try by removing the moveTo the following places:
context.beginPath();
context.moveTo(x_0, y_0); /// keep this
while(i < end){
i += inc;
newX = xcoord(i);
newY = ycoord(i);
context.lineTo(newX, newY);
///context.moveTo(newX, newY); /// remove this
console.log("" + newX + ", " + newY);
}
///context.lineTo(x_0, y_0); /// not needed as closePath will close it
///context.moveTo(x_0, y_0); /// remove this
context.closePath();
As you are using moveTo for each new coordinates you will create sub-paths consisting of only a single line which can't be filled. You want to create a continuous line which are closed at the end forming a closed polygon.
Besides from that, you are using fill() correctly.
Since you're asking, there are easier and cheaper ways of drawing an ellipse.
Something like the following:
function ellipse(context, x, y, a, b, theta) {
context.beginPath();
context.save();
/* translate to avoid having our x and y values scaled */
context.translate(x, y);
/* we can even do some rotation. (rotate before stretching!) */
context.rotate(theta);
/* now stretch the axes */
context.scale(a, b);
/* circle of radius 1, centred at the origin */
context.arc(0, 0, 1, 0, 2*Math.PI, false);
/* undo transformations */
context.restore();
context.closePath();
}
JSFiddle here.
function ellipse(context, x, y, a, b, theta) {
context.beginPath();
context.save();
/* translate to avoid having our x and y values scaled */
context.translate(x, y);
context.scale(Math.random() * 1 ,Math.random() * 1);
/* we can even do some rotation. (rotate before stretching!) */
context.rotate(theta);
/* now stretch the axes */
context.scale(a, b);
/* circle of radius 1, centred at the origin */
context.arc(0, 0, 1, 0, 2*Math.PI, false);
/* undo transformations */
context.restore();
context.closePath();};
setInterval(function(){abc()}, 100);
var c = document.getElementById("c");
var ctx = c.getContext("2d");
function abc()
{
c.width = c.width;
for (var i=0; i < 20; i++) {
ellipse(ctx, i*50+25, 100, 20, 30, Math.random() * 10 - 5);
if (i % 3)
ctx.fill();
else
ctx.stroke();
};
};