Skip to content

Instantly share code, notes, and snippets.

@fcisio
Created September 7, 2021 21:12
Show Gist options
  • Save fcisio/a6d2e4002dbc117e8193d0330667874d to your computer and use it in GitHub Desktop.
Save fcisio/a6d2e4002dbc117e8193d0330667874d to your computer and use it in GitHub Desktop.
Cloudinary SDK 2 - responsive()
import { Action } from '@cloudinary/base/internal/Action'
import { scale } from '@cloudinary/base/actions/resize'
import { clamp, debounce } from 'lodash'
import { isBrowser, isImage, isNum, updatePixelRatio, getDevicePixelRatio } from './pluginUtils'
export const responsive = (steps, percent) => responsivePlugin.bind(null, steps, percent)
const sourceWidth = (element, percent = [], dpr = 1) => {
const [value = 0, max = 4000, min = 400] = percent
const compare = {
parent: element.parentElement,
viewport: document.documentElement,
}[!!value ? 'viewport' : 'parent']
const sum = !!value
? clamp(compare?.clientWidth * (value / 100) * dpr, min, max)
: clamp(compare?.clientWidth * dpr, min, max)
return Math.ceil(sum)
}
const getSize = (steps, percent, element) => {
let resizeValue = sourceWidth(element, percent, getDevicePixelRatio())
if (isNum(steps)) {
resizeValue = Math.ceil(resizeValue / steps) * steps
} else if (Array.isArray(steps)) {
resizeValue = steps.reduce((prev, curr) =>
Math.abs(curr - resizeValue) < Math.abs(prev - resizeValue) ? curr : prev
)
}
return resizeValue
}
const responsivePlugin = (steps, percent, element, responsiveImage, htmlPluginState) => {
if (!isBrowser()) return
if (!isImage(element)) return
return new Promise((resolve) => {
htmlPluginState.cleanupCallbacks.push(() => {
window.removeEventListener('resize', resizeRef)
resolve('canceled')
})
const initialDpr = getDevicePixelRatio()
const stepSize = getSize(steps, percent, element)
responsiveImage.resize(scale().width(stepSize).setActionTag('responsive'))
let resizeRef
htmlPluginState.pluginEventSubscription.push(() => {
window.addEventListener(
'resize',
(resizeRef = debounce(() => {
onResize(steps, percent, element, responsiveImage)
}, 500))
)
updatePixelRatio(() => {
if (initialDpr < getDevicePixelRatio()) onResize(steps, percent, element, responsiveImage)
})
})
resolve()
})
}
const onResize = (steps, percent, element, responsiveImage) => {
updateByContainerWidth(steps, percent, element, responsiveImage)
element.src = responsiveImage.toURL()
}
const updateByContainerWidth = (steps, percent, element, responsiveImage) => {
const stepSize = getSize(steps, percent, element)
responsiveImage.transformation.actions.forEach((action, index) => {
if (action instanceof Action && action.getActionTag() === 'responsive') {
responsiveImage.transformation.actions[index] = scale(stepSize).setActionTag('responsive')
}
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment