KMK
KMK

Reputation: 1499

Resize div containing a canvas

I have a div containing a canvas:

<div class="canvas-wrapper">
    <canvas height="30px"></canvas>
</div>

The CSS for the "canvas-wrapper" class:

.canvas-wrapper{
    width: 100%;
    overflow: hidden;
}

Whenever the width of the div changes, the canvas width is updated (Angular directive):

link: function(scope, element, attr){
    var canvas = element.find('canvas')[0];
    var div = element.find('div')[0];

    scope.$watch(function(){
        return div.offsetWidth;
    }, function(newVal, oldVal){
        canvas.width = newVal;
    });
}

I've tested this by resizing the browser width. It works fine when I increase the window, but when I decrease the window the div will not resize.

I guess that's because it contains the canvas, but how can I get around this? The canvas is supposed to follow the div width, not block resizing.

Any ideas?

Upvotes: 1

Views: 3796

Answers (3)

user2005049
user2005049

Reputation: 550

Thanks to the answer from Spencer Evans.

I was able to add (in the resize event) the 1x1 px and it works.

$(self.canvas).attr('width', 1)
$(self.canvas).attr('height', 1);
self.dimension = (self.el.width() >= self.el.height() ? self.el.height() : self.el.width());

Upvotes: 1

Spencer Evans
Spencer Evans

Reputation: 489

You're correct when you said: "[the div doesn't decrease] I guess that's because it contains the canvas"

The accepted answer suggests using the css width property with a caveat that the canvas will stretch. This is also completely correct; the canvas will stretch.

You might want the canvas to stretch, but this is usually not desirable. For completeness, here is an answer to actually resize the canvas.

For best results, you need to use the following logic:

Steps

  1. Capture the resize event, which you've done, and then...
  2. Hide the canvas
  3. Measure the parent div size
  4. Re-size the canvas's width and height properties to match the measured parent div size
  5. Re-show your canvas
  6. Redraw your canvas graphics. This is an important extra step. Anytime you manually re-size the canvas the existing graphics are cleared.

The last step, redrawing graphics, is really important. A detailed explanation on how to redraw graphics with the correct scaling can be found here: html5 canvas redraw on resize

Demo

A demo of this logic working can be found here: http://spencer-evans.com/share/github/canvas-resizer/

JavaScript Solution

In JavaScript, a solution is:

// Call this every time the canvas resizes
function resizeCanvas()
{
    // Grab the canvas and it's parent div
    var canvas = document.getElementById("myCanvasId");
    var parent = canvas.parentNode;

    // Hide the canvas so we can get the parent's responsive bounds
    var displayBackup = canvas.style.display;
    canvas.style.display = "none";

    // Measure parent without the canvas
    var w = parent.clientWidth;
    var h = parent.clientHeight;

    // Set the new canvas dimensions
    canvas.width = w;
    canvas.height = h;

    // Restore the canvas display property
    canvas.style.display = displayBackup;

    // IMPORTANT: Call code here to redraw canvas graphics!
}

Library Solution

This can be cumbersome and I've ran into it time and time again. I've written a small JS / typescript library to handle this. You can find the library here: https://github.com/swevans/canvas-resizer

The library also has the benefit of re-sizing the canvas to match high resolution displays where devicePixelRatio is not equal to 1 (ie Retina displays).

Upvotes: 4

Amit
Amit

Reputation: 46323

You could add a CSS width of 100% to the canvas element.

While resizing a canvas via CSS is usually not a good practice as it stretches / shrinks the "image inside the canvas", if it's in sync with the canvas width & height properties there's nothing wrong with it.

You can solve that inline:

<div class="canvas-wrapper">
    <canvas height="30px" style="width: 100%;"></canvas>
</div>

Or use whatever CSS selection method you prefer instead.

Upvotes: 5

Related Questions