My canvas draw pixelated line - javascript

I'm trying to draw a little chart using some JavaScript and the canvas.
I'm doing a stuff like that :
RadarChart.prototype.fillRadar = function () {
var nbLabel = this.data.labels.length;
this.context.save();
this.context.lineWidth = 0.5;
this.context.lineJoin = "round";
this.context.translate(this.canvas.width / 2, this.canvas.height / 2);
this.context.strokeStyle = this.data.lineColor;
for (var i = 0; i < nbLabel; i++) {
this.context.moveTo(0, 0);
this.context.lineTo(0, -((this.canvas.height / 2) - 30))
this.context.stroke();
this.context.rotate((Math.PI / 180) * (360 / nbLabel));
}
this.context.restore();
}
the problem is that my lines are so pixelated and are not perfect. their width seems to change. It's like it's fading out over time...
Why is it doing that? How can I fix it?
Thanks for help.

Don't set the width / height of the canvas using css
use
canvas.width = 500;
canvas.height = 500;
make a function that find out how much 20% of the screen represent in pixel and then set the width/height in the code.

Related

Javascript - rotating canvas causes stretching [duplicate]

This question already has answers here:
Canvas is stretched when using CSS but normal with "width" / "height" properties
(10 answers)
Closed 1 year ago.
For some reason, if you set the canvas aspect ratio to 2:1, everything appears normal; any other aspect ratio will make it stretch.
const canvas = document.getElementById('canvas');
canvas.style.width = '400px';
canvas.style.height = '400px';
canvas.style.border = '2px solid black';
const ctx = canvas.getContext('2d');
const w = canvas.width/4;
const h = canvas.height/4;
var relativeAngle = 0;
//(Target is the position I want it; in this case, right in the middle)
const targetX = canvas.width/2;
const targetY = canvas.height/2;
const targetDist = Math.sqrt(targetX ** 2 + targetY ** 2);
const targetAngle = Math.atan(targetY / targetX) * 180 / Math.PI;
ctx.fillStyle = 'red'
function draw(){
relativeAngle += 3;
let targetRelativeAngle = targetAngle - relativeAngle;
let targetRelativeX = targetDist * Math.cos(targetRelativeAngle * Math.PI / 180);
let targetRelativeY = targetDist * Math.sin(targetRelativeAngle * Math.PI / 180);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
ctx.rotate(relativeAngle * Math.PI / 180);
ctx.translate(targetRelativeX,targetRelativeY);
ctx.fillRect(-w/2,-h/2,w,h);
ctx.restore();
window.requestAnimationFrame(draw);
}
draw();
What is the problem here and/or what is the better way to do this?
https://jsfiddle.net/1gx7bv3m/
My experience not a good idea to mix styles with canvas...
We can set the aspect ratio directly on the canvas like this:
const canvas = document.getElementById('canvas');
canvas.width = canvas.height = 400
const ctx = canvas.getContext('2d');
const w = canvas.width / 4;
const h = canvas.height / 4;
ctx.fillStyle = 'red'
function refresh() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.translate(w, h)
ctx.rotate(0.02);
ctx.fillRect(-w / 2, -h / 2, w, h);
ctx.translate(-w, -h)
window.requestAnimationFrame(refresh);
}
refresh();
<canvas id="canvas"></canvas>
You can see that I also remove a lot of the calculations you had and I hope that I accomplish the same result you are looking for, a lot less code and much more readable.

Fabric JS scaling multiple objects and center it on the canvas without scaling the canvas

Is it possible to scale down every object in a canvas (my image example contain about 10 objects) and center them without scaling the canvas? (The size of the canvas is the same in both the first and second image)
See image example the first image represent the original version, and the second image represent the desired version. Given some number, all objects are shrunk but their positioning are also tweaked so that their relative distances to each other are not disrupted, while maintaining centerism. The two images seem to be of different sizes, but they are the same size.
Yes, you can select every object and scale them to whatever dimension you need (if I understand your question).
var selection = new fabric.ActiveSelection(canvas.getObjects(), { canvas:canvas });
var sizeObj = resizer(
{ width: canvas.getWidth(), height: canvas.getHeight() },
{ width: selection.width, height: selection.height });
selection.scaleToHeight(sizeObj.height)
selection.center();
// routine from a stackoverflow contributer
resizer(canvas, imageObj) {
var imageAspectRatio = imageObj.width / imageObj.height;
var canvasAspectRatio = canvas.width / canvas.height;
var renderableHeight, renderableWidth, xStart, yStart;
// If image's aspect ratio is less than canvas's we fit on height
// and place the image centrally along width
if (imageAspectRatio < canvasAspectRatio) {
renderableHeight = canvas.height;
renderableWidth = imageObj.width * (renderableHeight / imageObj.height);
xStart = (canvas.width - renderableWidth) / 2;
yStart = 0;
}
// If image's aspect ratio is greater than canvas's we fit on width
// and place the image centrally along height
else if (imageAspectRatio > canvasAspectRatio) {
renderableWidth = canvas.width
renderableHeight = imageObj.height * (renderableWidth / imageObj.width);
xStart = 0;
yStart = (canvas.height - renderableHeight) / 2;
}
// Happy path - keep aspect ratio
else {
renderableHeight = canvas.height;
renderableWidth = canvas.width;
xStart = 0;
yStart = 0;
}
return { x: xStart, y: yStart, width: renderableWidth, height: renderableHeight }
}

Drawing audio as sound bars on a canvas does not overwrite last drawing when canvas.height not set

I have the following in which I get an audioBuffer audio clip and then I draw a circle of sound bars to visualize it:
const { audioContext, analyser } = this.getAudioContext();
const source = audioContext.createBufferSource();
source.buffer = this.props.audioBuffer;
analyser.fftSize = 256;
source.connect(analyser).connect(audioContext.destination);
source.start();
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext("2d");
// find the center of the window
let center_x = canvas.width / 2;
let center_y = canvas.height / 2;
let radius = 150;
const frequency_array = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(frequency_array);
const bars = analyser.frequencyBinCount;
const bar_width = 2;
animationLooper();
function animationLooper(){
//canvas.height = window.innerHeight;
// find the center of the window
center_x = canvas.width / 2;
center_y = canvas.height / 2;
radius = 50;
analyser.getByteFrequencyData(frequency_array);
for(let i = 0; i < bars; i++){
//divide a circle into equal parts
let rads = Math.PI * 2 / bars;
const bar_height = frequency_array[i] / 2;
// set coordinates
let x = center_x + Math.cos(rads * i) * (radius);
let y = center_y + Math.sin(rads * i) * (radius);
const x_end = center_x + Math.cos(rads * i)*(radius + bar_height);
const y_end = center_y + Math.sin(rads * i)*(radius + bar_height);
//draw a bar
drawBar(x, y, x_end, y_end, bar_width);
}
window.requestAnimationFrame(animationLooper);
}
function drawBar(x1, y1, x2, y2, width){
ctx.strokeStyle = "#1890ff";
ctx.lineWidth = width;
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
}
HTML:
<canvas id="canvas" width="400" height="400" />
This results in this after audio finished playing and the drawing completes. It should return back to no blue lines.
However if I comment in the line
canvas.height = window.innerHeight;
Then it correctly visualizes the audio and at the end the blue lines disappear. But I want a fixed height and width for my canvas. The end result should be lines/sound bars coming out from a center circle.
Does anyone know why the blue lines dont disappear when audio finished playing when I dont have that line commented in?
Yes, clearRect works well if you don't have other elements to draw on the same canvas for each frame. However, it will not work if you only want to remove one of the elements on the canvas.
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
The other issue is that you may need some kinds of transaction effects (such as audio bar fade out) through frames for a certain element.
If you keep drawing the effects for one element, it can clear all other elements during those frames.
The solution I came up with is to keep all elements in an array.
Then draw the array with a boolean tag that decides whether to draw or not for a certain element.

Canvas - Animating rotated text

What do I need to do to this animation to make the text animate along with the background image?
Fiddle here
I have seen a couple of different examples online but either they don't have the text rotated like I do (which is causing the problem) or they don't explain the maths behind the solution.
This is quite good - http://tech.pro/tutorial/1008/creating-a-roulette-wheel-using-html5-canvas
but it doesn't offer a great insight into the use of any of the Math functions.
I obviously need to affect the line:
context.rotate(i * arc);
in the loop that writes the text but I am unsure of the maths involved.
var cvs = document.getElementById("cvs");
var context = cvs.getContext("2d");
var height = 400,
width = 400,
spinning = false,
angle = 0,
awards = [100,200,300,400,500,600,700,800,900,1000,1100,1200],
segmentCount = 12,
angleAmount = 30,
arc = Math.PI / 6,
image = new Image();
image.src = 'http://placehold.it/400x400';
function draw() {
// clear
context.clearRect(0,0,width,height);
// rotate whole wheel here?
context.save();
context.translate(height/2, width/2);
context.rotate(angle * (Math.PI / 180));
context.drawImage(image,-width/2,-height/2);
context.restore();
// draw the prize amount text
for(var i = 0; i < segmentCount; i++){
context.save();
context.translate(height/2, width/2);
context.font = "bold 18px sans-serif";
context.textAlign = "end";
context.rotate(i * arc);
context.fillStyle = "#000000";
context.textBaseline = 'middle';
context.fillText(awards[i],145,0);
context.restore();
angle += angleAmount;
}
}
function update(){
draw();
angle += 5;
setTimeout(update,1000/30);
}
image.onload = update;
I think you got confused by the way you are using the 'angle' var : it is in fact the var that holds the current rotation, and you also use it in the for loop that draws the amounts (angle+=angleAmount)... just to increase it. Luckily enough you add 360° to it so it did not create a bug.
So first thing is to stop increasing this var in the text drawing for loop, second thing is to add the current rotation angle to each text draw (with a degree-> rad conversion) :
context.rotate(( i * angleAmount + angle ) * (Math.PI / 180));
http://jsfiddle.net/gamealchemist/fwter56k/4/
(or with a bit of optimisation : http://jsfiddle.net/gamealchemist/fwter56k/5/ )

Increase drawing canvas?

I have this code here: http://jsfiddle.net/m1erickson/98Bgq/
And I need to Increase drawing canvas for 550px of width and 400px height, and something tells me that this line:
var arcCount = colors.length;
var arcAngle = Math.PI * 2 / arcCount;
var cx = 150;
var cy = 150;
var radius = 75;
var lineWidth = 25;
And I don't know how to do that, someone can help me?
Just get the canvas DOM element and change its width and height properties.
var canvas = document.getElementById('canvas');
canvas.width = 550;
canvas.height = 400;

Categories