CSS canvas circle smoothness - javascript

I have a circle drawn in canvas, one of top of the other, the problem is that you can see the back one through the front one (red outline). Is there a way to improve this?
The only thing I can think of is the increase the size of the top one (lineWidth by pixel or 2) to completely cover the back one.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var canvas2 = document.getElementById('myCanvas2');
var context2 = canvas2.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var radius = 70;
for (var i = 0; i < 1; i++) {
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.lineWidth = 25;
context.strokeStyle = '#ff0000';
context.stroke();
}
for (var i = 0; i < 1; i++) {
context2.beginPath();
context2.arc(centerX, centerY, radius, 0, 2.5, false);
context2.lineWidth = 25;
context2.strokeStyle = '#fff';
context2.stroke();
}
#myCanvas,
#myCanvas2{
position:absolute;
}
<canvas id="myCanvas" width="578" height="200"></canvas>
<canvas id="myCanvas2" width="578" height="200"></canvas>
https://jsfiddle.net/0zs2gqxk/3/

I guess this is due to what is called anti-aliasing effect that is a direct result of the rendering in the browser.
As a fix you can specify the start angle for the red arc so that the issue do not occur - see demo below (a background has been added to body for illustration):
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var canvas2 = document.getElementById('myCanvas2');
var context2 = canvas2.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var radius = 70;
for (var i = 0; i < 1; i++) {
context.beginPath();
context.arc(centerX, centerY, radius, 2.5, 2 * Math.PI, false); /* CHANGED HERE*/
context.lineWidth = 25;
context.strokeStyle = '#ff0000';
context.stroke();
}
for (var i = 0; i < 1; i++) {
context2.beginPath();
context2.arc(centerX, centerY, radius, 0, 2.5, false);
context2.lineWidth = 25;
context2.strokeStyle = '#fff';
context2.stroke();
}
body {
background: #ddd;
}
#myCanvas,
#myCanvas2 {
position: absolute;
}
<canvas id="myCanvas" width="578" height="200"></canvas>
<canvas id="myCanvas2" width="578" height="200"></canvas>

Related

set grid made by js on the background of canvas

I try to make paint app in javascript. I need to make square grid and by pushing button. I made such grid but it is not on the background. How should I pass grid made by js on the background?
function print_grid()
{
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillRect(0, 0, 5100, 5100);
ctx.clearRect(0, 0, 5100, 5100);
ctx.beginPath();
for (let i = 0; i < 39; i++)
{
ctx.lineWidth = 1;
ctx.moveTo(50*i, 0);
ctx.lineTo(50*i, 5100);
ctx.moveTo(0, 50*i);
ctx.lineTo(5100, 50*i);
}
ctx.stroke();
}
<!DOCTYPE html>
<html>
<body>
<h1>Board</h1>
<button onclick="print_grid()">square</button>
<p >draw!!!</p>
<canvas id="myCanvas" width="1000" height="1000" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
</body>
</html>
One easy solution is using two canvases layered on top of each other. This way you can draw the grid onto the background layer independent from the canvas in the foreground.
Here's an example:
const canvas = document.getElementById('canvas2');
const ctx = canvas.getContext('2d');
let coordinates = {
x: 0,
y: 0
};
let painting = false;
function getPosition(event) {
coordinates.x = event.clientX - canvas.offsetLeft;
coordinates.y = event.clientY - canvas.offsetTop;
}
function startPainting(event) {
painting = true;
getPosition(event);
}
function stopPainting() {
painting = false;
}
function draw(event) {
if (!painting) return;
ctx.beginPath();
ctx.lineWidth = 5;
ctx.lineCap = 'round';
ctx.strokeStyle = 'red';
ctx.moveTo(coordinates.x, coordinates.y);
getPosition(event);
ctx.lineTo(coordinates.x, coordinates.y);
ctx.stroke();
}
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function printGrid() {
let backgroundCanvas = document.getElementById('canvas');
let context = backgroundCanvas.getContext("2d");
context.beginPath();
for (let a = 0; a < 10; a++) {
context.moveTo(0, parseInt(a * (backgroundCanvas.height / 9)));
context.lineTo(backgroundCanvas.width, parseInt(a * (backgroundCanvas.height / 9)));
context.moveTo(parseInt(a * (backgroundCanvas.width / 9)), 0);
context.lineTo(parseInt(a * (backgroundCanvas.width / 9)), backgroundCanvas.height);
}
context.stroke();
context.closePath();
}
printGrid();
document.addEventListener('mousedown', startPainting);
document.addEventListener('mouseup', stopPainting);
document.addEventListener('mousemove', draw);
<button onclick='clearCanvas();'>Clear</button>
<div>
<canvas id='canvas' style='position: absolute'></canvas>
<canvas id='canvas2' style='position: absolute'></canvas>
</div>

Is clearing canvas [ 2D Context ] in HTML5 necessary for good performance?

I have a 2D canvas and drawing circle indefinitely one above the other.
Take this example : http://jsfiddle.net/umaar/fnMvf/
<html>
<head>
</head>
<body>
<canvas id="canvas1" width="500" height="500"></canvas>
</body>
</html>
JavaScript :
var currentEndAngle = 0
var currentStartAngle = 0;
var currentColor = 'black';
var lineRadius = 75;
var lineWidth = 15;
setInterval(draw, 50);
function draw() {
var can = document.getElementById('canvas1'); // GET LE CANVAS
var canvas = document.getElementById("canvas1");
var context = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius;
var width;
var startAngle = currentStartAngle * Math.PI;
var endAngle = (currentEndAngle) * Math.PI;
currentStartAngle = currentEndAngle - 0.01;
currentEndAngle = currentEndAngle + 0.01;
if (Math.floor(currentStartAngle / 2) % 2) {
currentColor = "white";
radius = lineRadius - 1;
width = lineWidth + 3;
} else {
currentColor = "black";
radius = lineRadius;
width = lineWidth;
}
var counterClockwise = false;
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, counterClockwise);
context.lineWidth = width;
context.lineCap = "round";
// line color
context.strokeStyle = currentColor;
context.stroke();
}
Do I really need to clear canvas at some specific interval ?
How does canvas work in that case ? As it is '2D' context, does it still store previous data ? If yes, What should be approach to achieve smoothness for drawing circle keeping performance in mind ?
Canvas is a drawing surface. When you draw an element (e.g. call fill method), you are just changing the color of some pixels on the drawing surface. The canvas does not store any information about the element being drawn. In your example, there is no need to clear the canvas.

Drawing Shadow of an object in Canvas

I want to draw one circle and a character with shadow on a canvas in a HTML page while loading the page and recreate the image on a button click. I am using this code:
window.onload = function() {
draw();
};
function draw(){
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
ctx.clearRect(0, 0, c.width, c.height);
var width = c.width;
var height = c.height;
//DRAW A CIRCLE
var centerX = Math.floor((Math.random() * width));
var centerY = Math.floor((Math.random() * height));
var radius = Math.floor(Math.random() * 50);
var color = '#f11';
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2, false);
ctx.closePath();
ctx.fill();
//DRAW A CHARACTER WITH SHADOW
var c = "S";
ctx.font = "300% Verdana";
ctx.shadowBlur = 20;
ctx.shadowColor = "black";
ctx.shadowOffsetX = 20;
ctx.shadowOffsetY = 20;
ctx.fillStyle = "#111";
ctx.fillText(c, 10, 90);
}
In HTML I am calling draw function onclick() event of a button named Refresh.
For the first time it is giving desired output by drawing one circle and a character with shadow. As I click on the Refresh button it is drawing both the objects with shadow. I dont want to draw shadow of the circle. Can anyone please tell me the mistake I'm doing here.
You may want to use the CanvasRenderingContext2D.save() method :
window.onload = function() {
draw();
};
document.getElementById("canvas").addEventListener('click', draw);
function draw(){
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
ctx.clearRect(0, 0, c.width, c.height);
var width = c.width;
var height = c.height;
//DRAW A CIRCLE
var centerX = Math.floor((Math.random() * width));
var centerY = Math.floor((Math.random() * height));
var radius = Math.floor(Math.random() * 50);
var color = '#f11';
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2, false);
ctx.closePath();
ctx.fill();
//DRAW A CHARACTER WITH SHADOW
//save the actual context
ctx.save();
var c = "S";
ctx.font = "300% Verdana";
ctx.shadowBlur = 20;
ctx.shadowColor = "black";
ctx.shadowOffsetX = 20;
ctx.shadowOffsetY = 20;
ctx.fillStyle = "#111";
ctx.fillText(c, 10, 90);
//restore it
ctx.restore();
}
canvas{border:1px solid;}
<canvas id="canvas" width="400" height="200"></canvas>

Canvas: Multiple Radial Progress bar

i have a little problem, i have made 3 radial progress bars with canvas and js (following more or less the guide on thecodeplayer.com).
The result is almost good, and it's working, the problem is that if i have multiple bars the last one takes the percentage from the first. In my example the first is 65% and the last should be 88% but it take the data-attribute from the first.
Here is the code
Javascript:
window.onload = function(){
var canvas = document.getElementsByTagName('canvas');
for (var i = 0; i < canvas.length; i++) {
progressBar(canvas[i].id);
}
// load the canvas
function progressBar(canvasId) {
var canvas = document.getElementById(canvasId);
var ctx = canvas.getContext('2d');
// declare some variables
var cWidth = canvas.width;
var cHeight = canvas.height;
var progressColor = 'lightblue';
var circleColor = '#333';
var rawPerc = canvas.getAttribute('data-perc');
var definition = canvas.getAttribute('data-text');
var perc = parseInt(rawPerc);
var degrees = 0;
var endDegrees = (360*perc)/100;
var lineWidth = 10; // The 'brush' size
console.log(canvasId+' '+perc);
function getDegrees() {
if(degrees < endDegrees) {
degrees++;
}
else {
clearInterval(degreesCall);
}
drawProgressBar();
}
function drawProgressBar() {
//clear the canvas after every instance
ctx.clearRect(0,0,cWidth,cHeight);
// let's draw the background circle
ctx.beginPath();
ctx.strokeStyle = circleColor;
ctx.lineWidth = lineWidth -1;
ctx.arc(cHeight/2, cWidth/2, cWidth/3, 0, Math.PI*2, false);
ctx.stroke();
var radians = 0; // We need to convert the degrees to radians
radians = degrees * Math.PI/180;
// let's draw the actual progressBar
ctx.beginPath();
ctx.strokeStyle = progressColor;
ctx.lineWidth = lineWidth;
ctx.arc(cHeight/2, cWidth/2, cWidth/3, 0 - 90*Math.PI/180, radians - 90*Math.PI/180, false);
ctx.stroke();
// let's get the text
ctx.fillStyle = progressColor;
ctx.font = '20px Arial';
var outputTextPerc = Math.floor(degrees/360*100)+'%';
var outputTextPercWidth = ctx.measureText(outputTextPerc).width;
var outputTextDefinitionWidth = ctx.measureText(definition).width;
ctx.fillText(outputTextPerc, cWidth/2 - outputTextPercWidth/2, cHeight/2 - 10);
ctx.fillText(definition, cWidth/2 - outputTextDefinitionWidth/2, cHeight/2 + 15);
}
degreesCall = setInterval(getDegrees, 10/(degrees - endDegrees));
}
}
(sorry for the bad indend)
HTML:
<canvas id="canvas-3" width="300" height="300" data-text="Radial 1" data-perc="65"></canvas>
<canvas id="canvas-4" width="300" height="300" data-text="Radial 2" data-perc="90"></canvas>
<canvas id="canvas-1" width="450" height="450" data-text="Radial 3" data-perc="88"></canvas>
I have made a working jsfiddle at http://jsfiddle.net/ranqgnr8/.
Any idea why it's taking tha first percentage?
thanks to all who are reading.
EDIT:
the strange thing is that in the console log the percentage is right.
You forgot to define the degreesCall variable, so it ends up in the global space and you override the same interval
var canvas = document.getElementsByTagName('canvas');
for (var i = 0; i < canvas.length; i++) {
progressBar(canvas[i].id);
}
// load the canvas
function progressBar(canvasId) {
var degreesCall;
var canvas = document.getElementById(canvasId);
var ctx = canvas.getContext('2d');
// declare some variables
var cWidth = canvas.width;
var cHeight = canvas.height;
var progressColor = 'lightblue';
var circleColor = '#333';
var rawPerc = canvas.getAttribute('data-perc');
var definition = canvas.getAttribute('data-text');
var perc = parseInt(rawPerc);
var degrees = 0;
var endDegrees = (360*perc)/100;
var lineWidth = 10; // The 'brush' size
console.log(canvasId+' '+perc);
function getDegrees() {
if(degrees < endDegrees) {
degrees++;
}
else {
clearInterval(degreesCall);
}
drawProgressBar();
}
function drawProgressBar() {
//clear the canvas after every instance
ctx.clearRect(0,0,cWidth,cHeight);
// let's draw the background circle
ctx.beginPath();
ctx.strokeStyle = circleColor;
ctx.lineWidth = lineWidth -1;
ctx.arc(cHeight/2, cWidth/2, cWidth/3, 0, Math.PI*2, false);
ctx.stroke();
var radians = 0; // We need to convert the degrees to radians
radians = degrees * Math.PI/180;
// let's draw the actual progressBar
ctx.beginPath();
ctx.strokeStyle = progressColor;
ctx.lineWidth = lineWidth;
ctx.arc(cHeight/2, cWidth/2, cWidth/3, 0 - 90*Math.PI/180, radians - 90*Math.PI/180, false);
ctx.stroke();
// let's get the text
ctx.fillStyle = progressColor;
ctx.font = '20px Arial';
var outputTextPerc = Math.floor(degrees/360*100)+'%';
var outputTextPercWidth = ctx.measureText(outputTextPerc).width;
var outputTextDefinitionWidth = ctx.measureText(definition).width;
ctx.fillText(outputTextPerc, cWidth/2 - outputTextPercWidth/2, cHeight/2 - 10);
ctx.fillText(definition, cWidth/2 - outputTextDefinitionWidth/2, cHeight/2 + 15);
}
degreesCall = setInterval(getDegrees, 10/(degrees - endDegrees));
}
body {
padding-top: 100px;
background: #555;
}
canvas {
display: inline-block;
margin: auto;
}
<canvas id="canvas-3" width="300" height="300" data-text="Radial 1" data-perc="65"></canvas>
<canvas id="canvas-4" width="300" height="300" data-text="Radial 2" data-perc="90"></canvas>
<canvas id="canvas-1" width="450" height="450" data-text="Radial 3" data-perc="88"></canvas>

My Line Color is overlapping. What to do?

I'm following the JS tutorial in W3schools and make some improve for the code.
Now My code is as follows:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="600" height="600"></canvas>
<script>
function getAngle(x, y, angle, h) {
var radians = angle * (Math.PI / 180);
return { x: x + h * Math.cos(radians), y: y + h * Math.sin(radians) };
}
var canvas = document.getElementById('myCanvas');
var lineWidth = 250;
var centerx = canvas.width/2;
var centery = canvas.height/2;
var axisx = canvas.getContext('2d');
var axisy = canvas.getContext('2d');
var L1 = canvas.getContext('2d');
var L2 = canvas.getContext('2d');
var L3 = canvas.getContext('2d');
axisy.beginPath();
axisy.moveTo(centerx, 10);
axisy.lineTo(centerx, 590);
axisy.strokeStyle = '#000000';
axisy.stroke();
axisx.beginPath();
axisx.moveTo(10, centery);
axisx.lineTo(590, centery);
axisx.strokeStyle = '#000000';
axisx.stroke();
L1pos = getAngle(centerx, centery, 25, lineWidth);
L1.moveTo(centerx, centery);
L1.lineTo(L1pos.x, L1pos.y);
L1.strokeStyle = '#ff0000';
L1.stroke();
L2pos = getAngle(centerx, centery, 125, lineWidth);
L2.moveTo(centerx, centery);
L2.lineTo(L2pos.x, L2pos.y);
L2.strokeStyle = '#00ff00';
L2.stroke();
L3pos = getAngle(centerx, centery, 225, lineWidth);
L3.moveTo(centerx, centery);
L3.lineTo(L3pos.x, L3pos.y);
L3.strokeStyle = '#0000ff';
L3.stroke();
</script>
</body>
The result show that all 3 diagonals line (L1, L2, L3) were blue coloured (#0000ff). How to put different color on each line?
Before beginning to draw, you have to call beginPath, to flush the previous line. (see beginPath on w3schools)
L1.beginPath()
see the fiddle: http://jsfiddle.net/UX4gC/

Categories