Skip to content

Instantly share code, notes, and snippets.

@regchiu
Created November 20, 2023 08:57
Show Gist options
  • Save regchiu/d6a0dd192c713f08a4ac927726fadcc6 to your computer and use it in GitHub Desktop.
Save regchiu/d6a0dd192c713f08a4ac927726fadcc6 to your computer and use it in GitHub Desktop.
Draw canvas with path and backgroundSize(cover or percentage)
function drawImage<Number extends number>({
url,
width,
height,
path,
backgroundColor = 'transparent',
filter = 'none',
backgroundSize = 'cover'
}: {
url: string
width: number
height: number
path: string
backgroundColor?: string
filter?: string
backgroundSize?: 'cover' | `${Number}%`
}) {
const canvas = document.createElement('canvas')
canvas.width = width
canvas.height = height
const ctx = canvas.getContext('2d')
const clipPath = new Path2D(path)
ctx!.lineWidth = 6
ctx!.lineCap = 'round'
ctx!.strokeStyle = '#4969aa'
ctx?.stroke(clipPath)
ctx!.fillStyle = backgroundColor
ctx?.fill(clipPath)
ctx?.clip(clipPath)
ctx!.filter = filter
const img = new Image()
img.src = url
img.onload = () => {
let ratio = Math.min(width / img.width, height / img.height)
let imgWidth = img.width * ratio
let imgHeight = img.height * ratio
let calcX = 1
let calcY = 1
let calcWidth = 1
let calcHeight = 1
if (backgroundSize === 'cover') {
let aspectRatio = 1
// fill in the gaps
if (imgWidth < width) {
aspectRatio = width / imgWidth
}
if (Math.abs(aspectRatio - 1) < 1e-14 && imgHeight < height) {
aspectRatio = height / imgHeight
}
imgWidth *= aspectRatio
imgHeight *= aspectRatio
// calculate source rectangle
calcWidth = img.width / (imgWidth / width)
calcHeight = img.height / (imgHeight / height)
calcX = (img.width - calcWidth) * 0.5
calcY = (img.height - calcHeight) * 0.5
// make sure source rectangle is valid
if (calcX < 0) {
calcX = 0
}
if (calcY < 0) {
calcY = 0
}
if (calcWidth > img.width) {
calcWidth = img.width
}
if (calcHeight > img.height) {
calcHeight = img.height
}
console.log(calcX, calcY, calcWidth, calcHeight, width, height)
ctx?.drawImage(
img,
calcX,
calcY,
calcWidth,
calcHeight,
0,
0,
width,
height
)
} else if (backgroundSize.includes('%')) {
const scale = parseInt(backgroundSize.replace('%', ''), 10) / 100
calcWidth = imgWidth * scale
calcHeight = imgHeight * scale
calcX = (width - calcWidth) / 2
calcY = (height - calcHeight) / 2
ctx?.drawImage(img, calcX, calcY, calcWidth, calcHeight)
}
console.log(canvas.toDataURL())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment