I am creating a gradient on a canvas, generating a PNG file, and then downloading it. I want a radial gradient which is an ellipse. Since canvas gradients must be circles, I am generating the gradient as a circle and then resizing the canvas element to create the ellipse. This works fine and the visually generated image is the ellipse I want.
When I go to download the generated canvas, it is using the full size of the canvas, not the css styled size and so I get the original full sized circle. Is there a way to actually alter the dimensions of the canvas image and NOT keep the aspect ratio? All the SO posts that show up on the topic want to keep the aspect ratio.
makeCanvas();
scaled();
var input = document.createElement("input");
input.type = "button";
input.style.display = "block";
input.value = "Download Canvas to PNG";
input.onclick = function() {
var canvas = document.getElementById("canvas");
downloadURI(canvas.toDataURL("image/png"), "gradient.png");
}
document.body.appendChild(input);
var input = document.createElement("input");
input.type = "button";
input.style.display = "block";
input.value = "Download Scaled";
input.onclick = function() {
var canvas = document.getElementById("scaled");
downloadURI(canvas.toDataURL("image/png"), "gradient.png");
}
document.body.appendChild(input);
function makeCanvas() {
var canvasGradient;
var ctx;
width = 200;
height = 200;
var canvas = document.createElement("canvas");
canvas.id = "canvas";
canvas.style.width = width + "px";
canvas.style.height = height + "px";
canvas.width = width;
canvas.height = height;
ctx = canvas.getContext('2d');
var gradient;
// both circles have to share the center of the canvas
var coords = {
x1: 0,
y1: 0,
x2: 0,
y2: 0
};
coords.x1 = (width / 2);
coords.x2 = coords.x1;
coords.y1 = (height / 2);
coords.y2 = coords.y1;
// inner circle is just the center - a point
coords.r1 = 0;
// outer circle is the edge
coords.r2 = Math.min(height, width);
gradient = ctx.createRadialGradient(coords.x1, coords.y1, coords.r1, coords.x2, coords.y2, coords.r2);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width, height);
canvas.style.width = width / 2 + "px";
document.body.append(canvas);
can = alter(canvas, ctx);
//document.body.append(can);
}
function downloadURI(uri, name) {
var link = document.createElement("a");
link.download = name;
link.href = uri;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
}
function alter(canvas, ctx) {
var can = document.createElement("canvas");
can.id = "can";
can.width = Math.floor(canvas.width / 2);
can.height = canvas.height;
can.ctx = can.getContext("2d");
can.ctx.drawImage(canvas, 0, 0, can.width, can.height);
canvas.width = can.width;
canvas.height = can.height;
ctx.drawImage(can, 0, 0);
return can;
}
function scaled() {
var canvas = document.createElement("canvas");
canvas.id = "scaled";
canvas.style.width = "200px";
canvas.style.height = "200px";
canvas.width = 200;
canvas.height = 200;
ctx = canvas.getContext('2d');
var gradient;
var g = ctx.createRadialGradient(100, 100, 0, 100, 100, 100);
g.addColorStop(0, "white")
g.addColorStop(1, "red")
ctx.fillStyle = g
ctx.scale(0.5, 1) // scale x axis 0.5
ctx.fillRect(0, 0, 200, 200) // gradient circle squashed along x
document.body.append(canvas);
}
For your info gradient circles can be transformed to a ellipse.
var g = ctx.createRadialGradient(200,200,0,200,200,200)
g.addColorStop(0,"red")
g.addColorStop(1,"white")
ctx.fillStyle = g
ctx.scale(0.5,1) // scale x axis 0.5
ctx.fillRect(0,0,400,400) // gradient circle squashed along x
Create a second canvas
// assuming canvas , ctx is the original canvas and context
var can = document.createElement("canvas");
Set the resolution
can.width = Math.floor(canvas.width / 2);
can.height = canvas.height;
Get context and draw original on new canvas
can.ctx = can.getContext("2d");
can.ctx.drawImage(canvas,0,0,can.width,can.height);
Set the original canvas to the new size
canvas.width = can.width;
canvas.height = can.height;
Draw on the scaled can onto the original canvas
ctx.drawImage(can,0,0);
can = undefined; // reference to dump temp canvas
You now have the canvas scale yet keeping the content. You could also just replace the old canvas with the new one