Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting ugly image while simulating cover in canvas

I'm trying to display the image using cover simulation in canvas. I've found some cool answer on how to do it.

The thing is when I do it with a large picture, it's being displayed ugly. How to fix that?

Here's my Codepen

HTML

<canvas id="canvas"></canvas>

CSS

    canvas {
      width: 100%;
      height: 100vh;
    }

JS

var ctx = canvas.getContext('2d'),
    img = new Image;

img.onload = draw;
img.src = 'https://upload.wikimedia.org/wikipedia/commons/0/0f/2010-02-19_3000x2000_chicago_skyline.jpg';

function draw() {
    drawImageProp(ctx, this, 0, 0, canvas.width, canvas.height);
    //drawImageProp(ctx, this, 0, 0, canvas.width, canvas.height, 0.5, 0.5);
}

/**
 * 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);
}
like image 536
Billy Logan Avatar asked Oct 27 '15 10:10

Billy Logan


2 Answers

To accomplish this you could use several techniques like HTML/CSS, CSS Only, Jquery or JS/Canvas. For more on this look here.

You do not have to set the width and height of your canvas in HTML like David Skx mentioned. You do have to erase your CSS, remove it completely.

In your JS you should set your canvas size (just define it in 1 place, don't let different languages interfere):

var canvas = document.getElementById('canvas');
canvas.width = window.innerWidth; 
canvas.height = window.innerHeight;

Window means the whole browser, Use pixels here if you want to limit it to just a canvas and not the whole background

That's all.

like image 132
Matthijs van Hest Avatar answered Nov 08 '22 22:11

Matthijs van Hest


You have to specify the width and height in pixels directly on the <canvas>-Element, else it will distort it:

<canvas id="canvas" width="500" height="500"></canvas>

Use JavaScript to measure the window width and height and set it dynamically. Something like:

var canvas = document.getElementById('canvas');
canvas.setAttribute('width', window.innerWidth);
canvas.setAttribute('height', window.innerHeight);

UPDATE: As Matthijs van Hest pointed out, the width and height attributes on the <canvas>-element are just optional.

like image 2
misantronic Avatar answered Nov 08 '22 22:11

misantronic