13

I'm trying to make this raindrop canvas script take up 100% width and height, but nothing I seem to do works. I tried changing the CSS, and height/width in the Canvas area, but it either doesn't change anything, or it makes it not work at all. The one time I tried something that actually made it full size, it seemed to have a weird effect on the raindrops, they became all blurry and much larger, so it must have actually stretched the canvas instead of making it larger. Here's the code for the default 800x800 pixel canvas.

Style

<style>
  article, aside, figure, footer, header, hgroup, 
  menu, nav, section { display: block; }
</style>

Script for canvas

<script type="text/javascript">
var canvas = null;
var context = null;
var bufferCanvas = null;
var bufferCanvasCtx = null;
var flakeArray = [];
var flakeTimer = null;
var maxFlakes = 200; // Here you may set max flackes to be created 

function init() {
    canvas = document.getElementById('canvasRain');
    context = canvas.getContext("2d");

    bufferCanvas = document.createElement("canvas");
    bufferCanvasCtx = bufferCanvas.getContext("2d");
    bufferCanvasCtx.canvas.width = context.canvas.width;
    bufferCanvasCtx.canvas.height = context.canvas.height;


    flakeTimer = setInterval(addFlake, 200);

    Draw();

    setInterval(animate, 30);

}
function animate() {

    Update();
    Draw();

}
function addFlake() {

    flakeArray[flakeArray.length] = new Flake();
    if (flakeArray.length == maxFlakes)
        clearInterval(flakeTimer);
}
function blank() {
    bufferCanvasCtx.fillStyle = "rgba(0,0,0,0.8)";
    bufferCanvasCtx.fillRect(0, 0, bufferCanvasCtx.canvas.width, bufferCanvasCtx.canvas.height);

}
function Update() {
    for (var i = 0; i < flakeArray.length; i++) {
        if (flakeArray[i].y < context.canvas.height) {
            flakeArray[i].y += flakeArray[i].speed;
            if (flakeArray[i].y > context.canvas.height)
                flakeArray[i].y = -5;
            flakeArray[i].x += flakeArray[i].drift;
            if (flakeArray[i].x > context.canvas.width)
                flakeArray[i].x = 0;
        }
    }

}
function Flake() {
    this.x = Math.round(Math.random() * context.canvas.width);
    this.y = -10;
    this.drift = Math.random();
    this.speed = Math.round(Math.random() * 5) + 1;
    this.width = (Math.random() * 3) + 2;
    this.height = this.width;
}
function Draw() {
    context.save();

    blank();

    for (var i = 0; i < flakeArray.length; i++) {
        bufferCanvasCtx.fillStyle = "white";
        bufferCanvasCtx.fillRect(flakeArray[i].x, flakeArray[i].y, flakeArray[i].width, flakeArray[i].height);
    }


    context.drawImage(bufferCanvas, 0, 0, bufferCanvas.width, bufferCanvas.height);
    context.restore();
}

</script>

And finally here's the body

<body onload="init()">
  <canvas  id="canvasRain" width="800px" height="800px">Canvas Not Supported</canvas>
</body>
Steve Worth
  • 133
  • 1
  • 1
  • 5
  • Did you try setting the CSS height and width for the canvas element? – aet Oct 29 '13 at 18:55
  • @aet Yes, I tried 100% for both and it doesn't change it at all, actually I put the wrong code in too, I don't think this one even works let me put the working default code in – Steve Worth Oct 29 '13 at 18:58
  • Try to put the width and height of the body on 100% and than the canvas on 100%. Both with css. – MeiSign Oct 29 '13 at 19:04
  • 1
    @aet I made the body 100% height and width, and changed the canvas tag to , and it changed to 100 pixels height and width, not 100%. – Steve Worth Oct 29 '13 at 19:08
  • possible duplicate of [HTML5 Canvas resize to fit window](http://stackoverflow.com/questions/1664785/html5-canvas-resize-to-fit-window) – Mataniko Oct 29 '13 at 19:08
  • @Mataniko Yes I read that about an hour ago, and I tried both of the changes listed, and it didn't fix it. Could it not be working for me because it's a 'double buffer' canvas? – Steve Worth Oct 29 '13 at 19:12
  • When fiddling with CSS vs. HTML Canvas dimensions, you may find it helpful to understand what's going on behind the scenes. If so, I've found the description at http://www.ckollars.org/canvas-two-coordinate-scales.html helpful. – Chuck Kollars Mar 22 '14 at 02:55

2 Answers2

17

body, #canvasRain {width:100%; height:100%; margin:0px;} will set your size properly but your problem is that your canvas height/width you're using to do your drawing doesn't pick up the proper px values when setting them with %'s. And that's where the scaling comes in with the fuzzy flakes. It takes some default canvas size and stretches to 100% of the view. Adding something like

bufferCanvas.width = canvas.width = window.innerWidth;
bufferCanvas.height = canvas.height = window.innerHeight;

seems to do the trick. And you might want/need to handle resize events to recalculate it. Here is a sample. I couldn't get jsFiddle to work for me, so it's just the whole thing.

mafafu
  • 1,226
  • 1
  • 17
  • 22
  • Thank you! It works great. Do you know how to make it so the raindrops would stay the same size and shape when you resize the window? Whenever you resize it the raindrops get distorted. It should mostly fix it if it were to force the canvas size to stay at whatever it was when the page was first loaded. And if Overflow is hidden, there shouldn't be any problems with scrollbars either. – Steve Worth Oct 29 '13 at 20:13
  • @SteveWorth I took out the width/height 100% from the CSS and this leaves the canvas to whatever size you set it in your code. Check my sample again to see it. You could also handle `window.onresize` and just set your width and height again in that function. – mafafu Oct 30 '13 at 12:39
1

I've set up a fiddle that shows how to resize the canvas using some simple CSS.

http://jsfiddle.net/C7LfU/1/

$('#canvasRain').css({
   "height": window.innerHeight,
   "width": window.innerWidth
});

I've also went ahead and updated your animation to use requestAnimationFrame. This probably what caused your Flakes to be fuzzy: The animation lagged since setTimeout doesn't scale to when the browser is actually ready to draw another frame.

window.requestAnimFrame = (function () {
    return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) {
        window.setTimeout(callback, 1000 / 60);
    };
})();

function animate() {
    requestAnimFrame(animate);
    Update();
    Draw();
}

Read a little more about why you should use requestAnimationFrame at: http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/

Davide Pastore
  • 8,678
  • 10
  • 39
  • 53
Mataniko
  • 2,212
  • 16
  • 18