// plugin
const BackgroundSizePlugin = {
name: "backgroundSize",
getSize(target, config) {
let o = {};
BackgroundSizePlugin.init.call(o, gsap.utils.toArray(target)[0], config);
return {width: o.sw + o.cw, height: o.sh + o.ch};
},
init(target, vars) {
typeof(vars) !== "object" && (vars = {size: vars});
let cs = window.getComputedStyle(target),
imageUrl = cs.backgroundImage,
{nativeWidth, nativeHeight, scale, size} = vars,
parsedScale = scale || scale === 0 ? scale : 1,
data = this,
image, w, h, ew, eh, ratio, start, end,
getSize = (size, scale) => {
if (!/\d/g.test(size) || size.indexOf("%") > -1) {
ratio = nativeWidth / nativeHeight;
if (size === "cover" || size === "contain") {
if ((size === "cover") === (nativeWidth / ew > nativeHeight / eh)) {
h = eh;
w = eh * ratio;
} else {
w = ew;
h = ew / ratio;
}
} else { // "auto" or %
size = size.split(" ");
size.push("");
w = ~size[0].indexOf("%") ? ew * parseFloat(size[0]) / 100 : nativeWidth;
h = ~size[1].indexOf("%") ? eh * parseFloat(size[1]) / 100 : nativeHeight;
}
} else {
size = size.split(" ");
size.push(nativeHeight);
w = parseFloat(size[0]) || nativeWidth;
h = parseFloat(size[1]);
}
return {w: Math.ceil(w * scale), h: Math.ceil(h * scale)};
};
if (imageUrl) {
if (!nativeWidth || !nativeHeight) {
image = new Image();
image.setAttribute("src", imageUrl.replace(/(^url\("|^url\('|^url\(|"\)$|'\)$|\)$)/gi, ""));
nativeWidth = image.naturalWidth;
nativeHeight = image.naturalHeight;
}
ew = target.offsetWidth;
eh = target.offsetHeight;
if (!nativeWidth || !nativeHeight) {
console.log("bgSize() failed;", imageUrl, "hasn't loaded yet.");
nativeWidth = ew;
nativeHeight = eh;
}
size || (size = cs.backgroundSize);
start = getSize(cs.backgroundSize, 1);
end = getSize(size, parsedScale);
data.size = parsedScale === 1 ? size : end.w + "px " + end.h + "px";
data.style = target.style;
data.sw = start.w;
data.cw = end.w - start.w;
data.sh = start.h;
data.ch = end.h - start.h;
}
},
render(ratio, data) {
data.style.backgroundSize = ratio === 1 ? data.size : (data.sw + data.cw * ratio).toFixed(1) + "px " + (data.sh + data.ch * ratio).toFixed(1) + "px";
}
};
gsap.registerPlugin(BackgroundSizePlugin);
// now let's animate...
let tween = gsap.fromTo(".photo", {
backgroundSize: {
size: "cover",
scale: 3, // optionally scale it!
nativeWidth: 1200, // you don't have to define nativeWidth/nativeHeight but it makes calculations faster and more reliable because it can skip creating an Image and loading the URL.
nativeHeight: 1200
}
}, {
backgroundSize: {
size: "cover",
nativeWidth: 1200,
nativeHeight: 1200
},
duration: 2
});
document.body.addEventListener("click", ()=> tween.restart());
// or you can grab the numeric width/height (in pixels) like this (returns an object like {width: 100, height: 100})
let containSize = BackgroundSizePlugin.getSize(".photo", {size: "contain", nativeWidth: 1200, nativeHeight: 1200});
console.log("containSize:", containSize);