Line not clearing from HTML5 Canvas - javascript

I'm trying to solve an odd artifact that is occurring in my HTML5 Canvas animation. I'm trying to surround the text with lines that follow each other. When I get to clearing the third line, there is a line still there as if clearRect() didn't work correctly.
I've already googled and my draw functions do indeed use beginPath() and closePath() respectively, so you can imagine my frustration when this thing doesn't clear.
I'm hoping someone can help me see where I've gone wrong with this animation.
Here's an example of the draw code (because stack overflow is forcing me to put code in here if I link to JSFiddle)
function drawArc(xPos, yPos,
radius,
startAngle, endAngle,
anticlockwise,
lineColor, fillColor) {
var startAngle = startAngle * (Math.PI / 180);
var endAngle = endAngle * (Math.PI / 180);
var radius = radius;
context.strokeStyle = lineColor;
context.fillStyle = fillColor;
context.lineWidth = 1;
context.beginPath();
context.arc(xPos, yPos,
radius,
startAngle, endAngle,
anticlockwise);
context.fill();
context.closePath();
}
function drawLine(xStartPos, yStartPos, xEndPos, yEndPos, width, color) {
context.stokeStyle = color;
context.lineWidth = width;
context.beginPath();
context.moveTo(xStartPos, yStartPos);
context.lineTo(xEndPos, yEndPos);
context.stroke();
context.closePath();
}
JSFiddle: https://jsfiddle.net/xtkbnxx5/9/
With this version, it looks like the animation is stopping in the wrong place. However, If you comment out line 126 in the javascript and run it again, you will see that the line is just there and never gets cleared...
Any help would be greatly appreciated.

Your context.clearRect(...) statements are not clearing the entire canvas.
When I change you clearRect statements to
context.clearRect(0,0, canvas.width, canvas.height);
Then the second line eventually disappears.
https://jsfiddle.net/xtkbnxx5/10/

Related

Rotate triangle around circle (2D)

I'm trying to rotate a triangle around a circle, the triangle should always face outwards, meaning it should rotate around the circle, AND around its center I'm guessing.
I found this question, which is something like what I need, but just in reverse.
Another thing I need is to have the triangle pointed at the user's mouse coords. aka the triangle is something like an arrow.
I just edited the code you linked and replaced the rectangle with a triangle, and animate() with a mouse move listener, of course:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cx = 100;
var cy = 100;
var radious = 10;
var gap = 5;
var triangleHeight = 25;
var triangleBase = 10;
redraw(cx + 1, cy);
function redraw(mx, my)
{
mox = mx-cx;
moy = my-cy;
rotation = Math.atan2(moy, mox);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(cx, cy, radious, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(rotation);
ctx.beginPath();
ctx.moveTo(radious+gap, -triangleBase/2);
ctx.lineTo(radious+gap, triangleBase/2);
ctx.lineTo(radious+gap+triangleHeight, 0);
ctx.lineTo(radious+gap, -triangleBase/2)
ctx.stroke();
ctx.restore();
}
canvas.addEventListener("mousemove", function (e) {
redraw(e.pageX, e.pageY);
}, false);
<canvas id="canvas"></canvas>
BTW, it's my very first piece of code in JS, so, feel free to correct my code if something is funny.

How to draw in canvas 2D this shape and fill it with color?

This should be without this diagonal. I want to draw two arcs one with x2 smaller radius, join them and fill(). I know how to calculate the end and beginning of an arc, problem is arcs are always drawn clockwise, so to draw second arc within same ctx.beginPath() I have to use something like ctx.moveTo() but problem with moveTo is I get two different paths as proof closePath() cause this diagonal.
So I want to know how to draw arc in other direction than clockwise or how to use moveTo() but still beeing able to fill this shape. Filling now cause following issue:
White diagonal visible.
Arcs are not always drawn clockwise. The sixth parameter to .arc is a boolean which when true will make the arc be drawn anti-clockwise.
However you will also need to reverse the start and end angles, otherwise the arc will attempt to go the long way around:
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(20, 20, 40, 30 * Math.PI / 180, 80 * Math.PI / 180);
ctx.arc(20, 20, 150, 80 * Math.PI / 180, 30 * Math.PI / 180, true);
ctx.closePath();
ctx.lineWidth = 3;
ctx.stroke();
ctx.fillStyle = '#e0e0ff';
ctx.fill();
<canvas id="c" width="200" height="200" />
Why not use the lineWidth property to make the arc thicker. In this case you'll only need one call to arc:
let canvas = document.getElementById("canvas"),
context = canvas.getContext("2d");
context.beginPath();
context.arc(20, 20, 40, 0, Math.PI / 4);
context.lineWidth = 15;
context.stroke();
<canvas id="canvas"></canvas>

Prevent canvas element from manipulating others depending on order

I have been experimenting with canvas and things were going pretty well. However when it came time to rotate an object I had the hardest time getting it to rotate. When I finally did I found that depending on the order the objects being initiated it. The object with the rotation attributes would get passed on to objects being called after it.
All my objects were put into their own functions, and then called by a draw function. I am curious if this is always true and I have to be conscious of my objects order of initiation or if there is something I am missing.
Below if you move Obj1 and Obj2 before or after each other you will see the results are different. My goal is to have Obj1 before Obj2 and only have Obj1 rotated.
window.onload = function(){
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
x = 470,
y = 260;
canvas.width = 500;
canvas.height = 500;
function Obj1(){
ctx.beginPath();
ctx.translate(100,0);
ctx.rotate(20 * Math.PI / 180);
ctx.fillRect(x, y + 10, 20, 45);
ctx.fillStyle = 'blue';
ctx.fill();
ctx.closePath();
}
function Obj2(){
ctx.beginPath();
ctx.rect(0,300,100, 200);
ctx.fillStyle = "black";
ctx.fill();
ctx.closePath();
}
function draw(){
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
Obj1();
Obj2();
}
draw();
}
<canvas id="canvas"></canvas>
You need to reset the rotation matrix after rotating the object
Whats happening is that the transforms are cascading .
Rendering happens as a stack not a per element basis .
The order of operations is
TRANSFORM
DRAW
RESET
DRAW
This is also a recursive process .
You can say rotate the world scene / view port and also individual object .
TRANSFORM
TRANSFORM
DRAW
RESET
TRANSFORM
DRAW
RESET
RESET
If you post a simple code example I can review it for you
Have a look at
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Transformations
function Obj1(){
ctx.save();
ctx.beginPath();
ctx.translate(100,0);
ctx.rotate(20 * Math.PI / 180);
ctx.fillRect(x, y + 10, 20, 45);
ctx.fillStyle = 'blue';
ctx.fill();
ctx.closePath();
ctx.restore();
}
I believe off the top of my head .

Canvas animation pixelated

I want to animate an Arc on Canvas, and it works (with a really basic animation, interval), but the outcome is very pixelated/edgy. On the left side I draw an arc (animated), on the right side without animation (smooth).
JsFiddle: http://jsfiddle.net/C8CXz/2/
function degreesToRadians (degrees) {
return degrees * (Math.PI/180);
}
function radiansToDegrees (radians) {
return radians * (180/Math.PI);
}
var canvas = document.getElementById('circle');
var ctx = canvas.getContext('2d');
var start = 0, end = 0;
var int = setInterval(function(){
end++;
ctx.beginPath();
ctx.arc(80, 80, 50, degreesToRadians(0)-Math.PI/2, degreesToRadians(end)-Math.PI/2, false);
ctx.lineWidth = 10;
ctx.stroke();
if(end >= 360) {
clearInterval(int);
}
}, 10);
ctx.beginPath();
ctx.arc(220, 80, 50, degreesToRadians(0)-Math.PI/2, degreesToRadians(360)-Math.PI/2, false);
ctx.lineWidth = 10;
ctx.stroke();
(raw simple code, dont mind the sloppiness)
You need a:
ctx.clearRect(0, 0, w, h);
In each draw loop.
Basically, you are drawing the same arc over itself hundreds of times. The edge pixels that are only partially black are bing darkened over and over until they are completely black.
Things like this are way nearly all canvas animations clear the canvas and draw fresh for each iteration.
Try clearing the drawing rectangle on every frame
ctx.clearRect(x,y,width,height);
http://jsfiddle.net/C8CXz/3/
I found that I first need the clear the canvas.
ctx.clearRect(0, 0, canvas.width, canvas.height);

Make the half circle more elliptic

This is my jsfiddle:
http://jsfiddle.net/c4upM/103/
I have the gray arc and the blue/green arc.
I am trying to make them more Elliptic, like:
and I didn't succeed.
I read this one: http://jsbin.com/ovuret/2/edit and tried to make it on my jsfiddle but I didn't succeed because the arc-s are painted in the function of: DrawCircle and DrawEllipseForProjection.
There are two functions: blueArc and grayarc. by the radian angle, there is a calculation in function circleInArc that places the small lightblue circle and the small gray circle (when you mouse over the canvas) in the arc-s.
I want these functions to work after the change but I didn't succeed.
these are the blue and gray arc-s:
function grayArc(strokeColor, cx, cy, radius, ctx, linewidth) {
ctx.beginPath();
ctx.arc(cx, cy, radius, Math.PI, Math.PI * 2);
ctx.lineWidth = linewidth;
ctx.strokeStyle = strokeColor;
ctx.stroke();
}
function blueArc(strokeColor, radianStart, radianEnd, cx, cy, radius, ctx, linewidth) {
ctx.beginPath();
ctx.arc(cx, cy, radius, radianStart, radianEnd);
ctx.lineWidth = linewidth;
ctx.strokeStyle = strokeColor;
ctx.stroke();
}
and this is the circleInArc function:
function circleInArc(fillColor, radianAngle, cx, cy, radius, ctx, linewidth) {
var x = cx + radius * Math.cos(radianAngle);
var y = cy + radius * Math.sin(radianAngle);
ctx.beginPath();
ctx.arc(x, y, linewidth / 2, 0, Math.PI * 2);
ctx.closePath();
ctx.fillStyle = fillColor;
ctx.fill();
return ({
x: x,
y: y,
radius: linewidth / 2
});
}
Any help appreciated!
You can try draw arc with bigger radius and not from Math.PI to 2*Math.PI but this one
ctx.arc(cx, cy, radius, Math.PI*5/4, Math.PI * 7/4);
and don't forget move the arc down for radius size
grayArc("rgb(177,177,177)", cx, cy+radius, radius*2, ctx, linewidth);
hope it will help
I've fiddled around a bit, and you'll propably have to adjust some of the values, but here's an example: Fiddle (Only the gray arc was adjusted)
The basic strategy is to save the state of the context, then scale it to your liking. If you only scale one axis.. voilá, ellipsis.
Also, I translated the origin of the canvas to the center of the arc before scaling, because they get scewed with the scaling. The center of the arc is then 0, 0.
After that the context can be restored like nothing ever happened, an you can stroke your transformed arc.
ctx.save();
ctx.translate(cx,cy);
ctx.scale(1.3, 1);
ctx.arc(0, 0, radius, 1.2*Math.PI, 1.8*Math.PI);
ctx.restore();
You'll propably want to play around with the radius, the ratio of scaling and maybe the range in which the arc gets drawn to fit your needs.
Edit: I cut down on the range of the arc which gets drawn, to prevent the stubby ends of the ellipsis showing. From 1.2*PI to 1.8*PI instead of 1*PI to 2*PI seems to look alright in the current case. :)
For future questions, please try to extract the a more basic example of your problem, to make it easier for those who want to help out. :)

Categories

Resources