Mark Brown
Mark Brown

Reputation: 12534

Imitate background-size:cover in canvas element

I have a canvas element that is a set size. I would like to set a background image in the canvas that takes up the entire height and width of the canvas, but the image maintains it's aspect ratio. There will obviously be some clipping or parts of the image that aren't viewable since the aspect ratio of the image and the canvas are different. This is simple when I'm dealing with a div - I can just set background-size:cover.

How can I achieve the same effect with a canvas element, presumably using context.drawImage.

context.drawImage(image, 0, 0);

Here is a fiddle that shows what I want to happen as well as what's happening when I'm attempting to do this with css: http://jsfiddle.net/66Xfd/1/

Info on background-size:cover if required - https://developer.mozilla.org/en-US/docs/Web/CSS/background-size

Upvotes: 0

Views: 2839

Answers (1)

user1693593
user1693593

Reputation:

I created this function which at the time gave a bit of headache. But in any case does what you ask for, scales the image inside the destination rectangle proportionally to fill the whole space.

/**
 * By Ken Fyrstenberg
 *
 * drawImageProp(context, image [, x, y, width, height [,offsetX, offsetY]])
 *
 * If image and context are only arguments rectangle will equal canvas
*/
function drawImageProp(ctx, img, x, y, w, h, offsetX, offsetY) {

    if (arguments.length === 2) {
        x = y = 0;
        w = ctx.canvas.width;
        h = ctx.canvas.height;
    }

    /// default offset is center
    offsetX = offsetX ? offsetX : 0.5;
    offsetY = offsetY ? offsetY : 0.5;

    /// keep bounds [0.0, 1.0]
    if (offsetX < 0) offsetX = 0;
    if (offsetY < 0) offsetY = 0;
    if (offsetX > 1) offsetX = 1;
    if (offsetY > 1) offsetY = 1;

    var iw = img.width,
        ih = img.height,
        r = Math.min(w / iw, h / ih),
        nw = iw * r,   /// new prop. width
        nh = ih * r,   /// new prop. height
        cx, cy, cw, ch, ar = 1;

    /// decide which gap to fill    
    if (nw < w) ar = w / nw;
    if (nh < h) ar = h / nh;
    nw *= ar;
    nh *= ar;

    /// calc source rectangle
    cw = iw / (nw / w);
    ch = ih / (nh / h);

    cx = (iw - cw) * offsetX;
    cy = (ih - ch) * offsetY;

    /// make sure source rectangle is valid
    if (cx < 0) cx = 0;
    if (cy < 0) cy = 0;
    if (cw > iw) cw = iw;
    if (ch > ih) ch = ih;

    /// fill image in dest. rectangle
    ctx.drawImage(img, cx, cy, cw, ch,  x, y, w, h);
}

Upvotes: 3

Related Questions