<script>
function clamp(num, a, b) {
return num > b ? b
: num < a ? a
: num
}
/**
* @param {CanvasRenderingContext2D} ctx
* @param {HTMLImageElement} img
* @param {Number} dx
* @param {Number} dy
* @param {Number} dw
* @param {Number} dh
* @param {Number} offsetX
* @param {Number} offsetY
* */
function drawImageProp(ctx, img, {dx = 0, dy = 0, dw = undefined, dh = undefined, offsetX = 0.5, offsetY = 0.5}) {
dw = dw ?? ctx.canvas.width
dh = dh ?? ctx.canvas.height
// keep bounds [0.0, 1.0]
offsetX = clamp(offsetX, 0, 1)
offsetY = clamp(offsetY, 0, 1)
let iw = img.width,
ih = img.height,
ratio = Math.min(dw / iw, dh / ih),
nw = iw * ratio,
nh = ih * ratio, // new prop. height
sx, sy, sw, sh, ar = 1;
// decide which gap to fill
if (nw < dw) ar = dw / nw
if (Math.abs(ar - 1) < 1e-14 && nh < dh) ar = dh / nh // updated
nw *= ar
nh *= ar
// source rectangle
sw = iw / (nw / dw)
sh = ih / (nh / dh)
sx = (iw - sw) * offsetX
sy = (ih - sh) * offsetY
// make sure source rectangle is valid
if (sx < 0) sx = 0
if (sy < 0) sy = 0
if (sw > iw) sw = iw
if (sh > ih) sh = ih
img.onload = (event) => {
// fill image in dest. rectangle
ctx.drawImage(event.target, sx, sy, sw, sh, dx, dy, dw, dh)
}
}
// Test Only 👇
window.onload = () => {
const testArray = [
["Default", (ctx, img)=>{drawImageProp(ctx, img, {})}],
["Full", (ctx, img)=>{drawImageProp(ctx, img, {offsetY:0})}], // If you don't want to it cutting from two sides, you can set "offsetY = 0" then it will cut a large part from the bottom
["1/2",(ctx, img)=>{drawImageProp(ctx, img, {dx:window.innerWidth/4, dy:window.innerHeight/4, dw: window.innerWidth/2, dh:window.innerHeight/2})}],
["3/4",(ctx, img)=>{drawImageProp(ctx, img, {dx:window.innerWidth/8, dy:window.innerHeight/8, dw: window.innerWidth*3/4, dh:window.innerHeight*3/4})}]
]
for (const [testName, drawFunc] of testArray) {
const btn = document.createElement("button")
btn.innerText = testName
btn.onclick = () => {
document.querySelectorAll(`canvas`).forEach(e=>e.remove()) // remove old data
const img = new Image(590, 470)
img.src = "https://upload.wikimedia.org/wikipedia/commons/b/bd/Test.svg"
const canvas = document.createElement("canvas")
canvas.width = window.innerWidth
canvas.height = window.innerHeight
const ctx = canvas.getContext("2d")
drawFunc(ctx, img)
document.querySelector(`body`).append(canvas)
}
document.querySelector(`body`).append(btn)
}
}
</script>