Reputation: 160
I am currently creating some artsy background for my website with a bunch of randomly generated curve plots.
So far, I am using Html5 Canvas and I recreate the whole every time the window is resized to fit the new width of the canvas. The data all lies in x,y ~ [0,1],[0,1] and is then scaled to fit the window. This is how I set up the canvas transformation:
ctx.resetTransform();
ctx.scale(c.width, c.height);
Since the basic data does not change, I was hoping I could just adjust the canvas size (which deletes all data) and the transformation to update the plots (although I guess I might run into trouble concerning the stroke width, when stroking the lines in the [0,1] space). Is there any more efficient way for me to redraw all these plots (for example storing all the line-paths somehow) or do I really have to loop through everything again and recreate the whole scene?
Upvotes: 0
Views: 470
Reputation: 54099
Path2D
Use Path2D
to create the content once then render to the scale as needed.
For example
const pathStroke = new Path2D(), pathFill = new Path2D();
var i;
for (i = 0; i <= 1; i += 1 / 100) {
pathStroke.lineTo(i, Math.sin(i * Math.PI * 8) * 0.1 + 0.2);
pathFill.lineTo(i, Math.sin(i * Math.PI * 16) * 0.1 + 0.4);
}
for (i = 0; i <= 1; i += 1 / 100) {
pathFill.lineTo((1-i), Math.cos((i-i) * Math.PI * 13) * 0.1 + 0.5);
}
Then to render the content
ctx = canvas.getContext("2d");
ctx.setTransform(canvas.width, 0, 0, canvas.height, 0, 0);
ctx.stroke(pathStroke);
ctx.fill(pathFill);
Switch to full page to see content re-rendered and scaled.
createPaths
adds content to the two paths pathStroke
and pathFill
renderContent
renders the content in the paths scaled to fit the canvas.
The resize event just calls this function again.const ctx = canvas.getContext("2d");
const pathStroke = new Path2D(), pathFill = new Path2D();
createPaths();
renderContent();
addEventListener("resize", renderContent);
function createPaths() {
var i;
for (i = 0; i <= 1; i += 1 / 1000) {
pathStroke.lineTo(i * i, Math.sin(i * Math.PI * 8) * 0.05 + 0.1);
pathFill.lineTo(i, Math.sin(i * Math.PI * 11) * 0.4 * i ** 0.5 + 0.6);
}
for (i = 0; i <= 1; i += 1 / 1000) {
if (i === 0) {
pathStroke.moveTo((1-i), Math.sin(i * i * Math.PI * 8) * (i * 0.1) + 0.2);
} else {
pathStroke.lineTo((1-i), Math.sin(i * i * Math.PI * 9) * (i * 0.1) + 0.2);
}
pathFill.lineTo((1-i), Math.cos((1-i) * Math.PI * 13) * 0.3 * i * i + 0.7);
}
}
function renderContent() {
canvas.width = innerWidth;
canvas.height= innerHeight;
// scale line width 2 pixels
ctx.lineWidth = 2 / Math.max(canvas.width, canvas.height);
ctx.setTransform(canvas.width, 0, 0, canvas.height, 0, 0);
ctx.stroke(pathStroke);
ctx.fill(pathFill);
}
body { padding: 0px }
canvas {
position: absolute;
top: 0px;
left: 0px;
}
<canvas id="canvas"></canvas>
Upvotes: 1
Reputation: 476
Since the data is not going to change why not use svg instead of having all the data first being saved in some place and having whole lot of logic being written to draw that on canvas.
There are sites available to convert you image to svg. All you have to do is make some changes which you seem most fit to your needs and you are done.
some examples: Trajan column
Upvotes: 0