Simulation background-size: cover in canvas
It's a bit more complicated to get a cover functionality, though here is one solution for this:
Updated 2016-04-03 to address special cases. Also see @Yousef's comment below.
/**
* By Ken Fyrstenberg Nilsen
*
* 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 = typeof offsetX === "number" ? offsetX : 0.5;
offsetY = typeof offsetY === "number" ? 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 (Math.abs(ar - 1) < 1e-14 && nh < h) ar = h / nh; // updated
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);
}
Now you can call it like this:
drawImageProp(ctx, image, 0, 0, width, height);
and it will scale the image proportionally to fit inside in that container.
Use the two last parameters to offset the image:
var offsetX = 0.5; // center x
var offsetY = 0.5; // center y
drawImageProp(ctx, image, 0, 0, width, height, offsetX, offsetY);
Hope this helps!
Adjust canvas image size like 'background-size: cover' and responsive
The canvas width / height attributes do not reflect it's actual size in relation to it being sized with CSS. Given your code, cw/ch
are fixed at 300/150
. So the whole calculation is based on incorrect values.
You need to use values that actually reflect it's visible size. Like clientWidth / clientHeight.
A very simple solution is to update the canvas width/height attributes before using them for any calculations. E.g.:
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
Full example:
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
// only load the image once
const img = new Promise(r => {
const img = new Image();
img.src = 'https://source.unsplash.com/WLUHO9A_xik/1600x900';
img.onload = () => r(img);
});
const draw = async () => {
// resize the canvas to match it's visible size
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
const loaded = await img;
const iw = loaded.width;
const ih = loaded.height;
const cw = canvas.width;
const ch = canvas.height;
const f = Math.max(cw/iw, ch/ih);
ctx.setTransform(
/* scale x */ f,
/* skew x */ 0,
/* skew y */ 0,
/* scale y */ f,
/* translate x */ (cw - f * iw) / 2,
/* translate y */ (ch - f * ih) / 2,
);
ctx.drawImage(loaded, 0, 0);
};
window.addEventListener('load', draw);
window.addEventListener('resize', draw);
.--dimensions {
width: 90%;
height: 300px;
}
.--border {
border: 3px solid #333;
}
canvas {
display: block;
margin: 0 auto;
}
#test {
background: url(https://source.unsplash.com/WLUHO9A_xik/1600x900) no-repeat center center;
background-size: cover;
margin: 1rem auto 0;
}
<canvas id="canvas" class="--dimensions --border"></canvas>
<div id="test" class="--dimensions --border"></div>
Getting ugly image while simulating cover in canvas
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.
Scaling an image to fit on canvas
Provide the source image (img) size as the first rectangle:
ctx.drawImage(img, 0, 0, img.width, img.height, // source rectangle
0, 0, canvas.width, canvas.height); // destination rectangle
The second rectangle will be the destination size (what source rectangle will be scaled to).
Update 2016/6: For aspect ratio and positioning (ala CSS' "cover" method), check out:
Simulation background-size: cover in canvas
Make canvas stretch to fit image
In order to get dynamically your canvas dimensions you could have the following componentWillReceiveProps()
method:
componentWillReceiveProps(nextProps) {
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.onload = function () {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
};
img.src = URL.createObjectURL(nextProps.image)
}
How to crop images when placing them on an HTML5 canvas?
Your nested for loops execute img.onload
and img.src = 'https://source.unsplash.com/random';
25 times.
let ii = 0;
for (let xCell = 0; xCell < 5; xCell++) {
for (let yCell = 0; yCell < 5; yCell++) {
console.log(++ii + ": ", xCell, yCell);
}
}
Display the Full Image Size (100% Width/Height) inside a HTML5 Canvas of a certain Width/Height using JavaScript, maybe CSS
var canvas = document.getElementById('my_canvas'); var ctx = canvas.getContext('2d'); var imageObj = new Image(); ctx.canvas.width = window.innerWidth; ctx.canvas.height = window.innerHeight; imageObj.onload = function() { ctx.drawImage(imageObj, 0, 0,window.innerWidth,window.innerHeight); }; imageObj.src = 'https://www.google.com/images/srpr/logo4w.png';
<canvas id="my_canvas" style="border:2px solid;"></canvas>
background-size:cover equivalent
Here is a solution but similar to @Moob.
div{
width: 100%;
height: 200px;
position: relative;
overflow: hidden;
}
img {
display: block;
width: 100%;
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
}
Working jsfiddle
Related Topics
How to Force a Script Reload and Re-Execute
How to Add/Update an Attribute to an HTML Element Using JavaScript
How to Create a Link Using JavaScript
Losing Scope When Using Ng-Include
How to Open a Pdf File in an ≪Iframe≫
Three.Js Ray Intersect Fails by Adding Div
How to Fix Getimagedata() Error the Canvas Has Been Tainted by Cross-Origin Data
Check With Jquery If Div Has Overflowing Elements
How to Validate Inputs Dynamically Created Using Ng-Repeat, Ng-Show (Angular)
How to Detect Keypresses in JavaScript
How to Get the Values of Data Attributes in JavaScript Code
Show Datalist Labels But Submit the Actual Value
How to Add/Remove Several Classes in One Single Instruction With Classlist