mirror of
https://github.com/cupcakearmy/svelte-cloudinary.git
synced 2024-12-22 16:06:25 +00:00
lazy loading, debug options and configurable step size
This commit is contained in:
parent
4aedf94b92
commit
dfd3031825
84
src/index.ts
84
src/index.ts
@ -1,57 +1,71 @@
|
|||||||
import { Cloudinary, Configuration, Transformation } from 'cloudinary-core'
|
import { Cloudinary, Configuration, Transformation } from 'cloudinary-core'
|
||||||
|
|
||||||
let cl: Cloudinary | null = null
|
type ElementOrString = Element | string
|
||||||
|
type Size = { width: number; height: number }
|
||||||
|
type BindType = ElementOrString | true
|
||||||
|
type BindObject = BindType | { width?: BindType; height?: BindType }
|
||||||
|
|
||||||
export function initialize(options: Configuration.Options) {
|
export type InitParameters = { debug?: boolean }
|
||||||
cl = Cloudinary.new(options)
|
export type ImageParameters = {
|
||||||
|
src: string
|
||||||
|
options?: Transformation | Transformation.Options
|
||||||
|
bind?: BindObject
|
||||||
|
lazy?: boolean | IntersectionObserverInit
|
||||||
|
step?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
type ElementOrString = Element | string
|
let cl: Cloudinary | null = null
|
||||||
|
let DEBUG: boolean = false
|
||||||
|
|
||||||
|
function log(...msg: any[]) {
|
||||||
|
if (DEBUG) console.debug(...msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initialize(options: Configuration.Options, { debug }: InitParameters = {}) {
|
||||||
|
DEBUG = debug || false
|
||||||
|
cl = Cloudinary.new(options)
|
||||||
|
}
|
||||||
|
|
||||||
const defaults: Transformation | Transformation.Options = {
|
const defaults: Transformation | Transformation.Options = {
|
||||||
fetchFormat: 'auto',
|
fetchFormat: 'auto',
|
||||||
quality: 'auto:good',
|
quality: 'auto:good',
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateApproxRealSize(size: string, step = 200) {
|
function calculateApproxRealSize(size: string, step: number): number {
|
||||||
const withRatio = (parseInt(size) * window.devicePixelRatio) | 0
|
const withRatio = (parseInt(size) * window.devicePixelRatio) | 0
|
||||||
return withRatio - (withRatio % step) + step
|
const approx = withRatio - (withRatio % step) + step
|
||||||
|
log('Size', withRatio, approx, step)
|
||||||
|
return approx
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSizeOfElement(el: Element) {
|
function getSizeOfElement(el: Element, step: number): Size {
|
||||||
const styles = window.getComputedStyle(el)
|
const styles = window.getComputedStyle(el)
|
||||||
|
log('GetSizeOfElement', el, styles)
|
||||||
return {
|
return {
|
||||||
width: calculateApproxRealSize(styles.width),
|
width: calculateApproxRealSize(styles.width, step),
|
||||||
height: calculateApproxRealSize(styles.height),
|
height: calculateApproxRealSize(styles.height, step),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSizeOfElementOrSelector(node: ElementOrString, elOrString: ElementOrString) {
|
function getSizeOfElementOrSelector(node: ElementOrString, elOrString: ElementOrString, step: number): Size {
|
||||||
if (typeof elOrString === 'string') {
|
if (typeof elOrString === 'string') {
|
||||||
const search = typeof node === 'string' ? window.document.querySelector(node) : node
|
const search = typeof node === 'string' ? window.document.querySelector(node) : node
|
||||||
if (!search) throw new Error('Could not find element: ' + node)
|
if (!search) throw new Error('Could not find element: ' + node)
|
||||||
const closest = search.closest(elOrString)
|
const closest = search.closest(elOrString)
|
||||||
if (closest) return getSizeOfElement(closest)
|
if (closest) return getSizeOfElement(closest, step)
|
||||||
else throw new Error('Could not find element: ' + elOrString)
|
else throw new Error('Could not find element: ' + elOrString)
|
||||||
} else {
|
} else {
|
||||||
return getSizeOfElement(elOrString)
|
return getSizeOfElement(elOrString, step)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type BindType = ElementOrString | true
|
export function image(node: HTMLImageElement, parameters: ImageParameters) {
|
||||||
type BindObject = BindType | { width?: BindType; height?: BindType }
|
if (!parameters || !parameters.src) throw new Error('No url provided for cloudinary')
|
||||||
|
|
||||||
export type ImageParameters = {
|
let { src, options, bind, lazy, step } = parameters
|
||||||
src: string
|
log('Image Declared', parameters)
|
||||||
options?: Transformation | Transformation.Options
|
|
||||||
bind?: BindObject
|
|
||||||
}
|
|
||||||
|
|
||||||
export function image(node: HTMLImageElement, parameters?: ImageParameters) {
|
|
||||||
if (!parameters) throw new Error('No url provided for cloudinary')
|
|
||||||
|
|
||||||
let { src, options, bind } = parameters
|
|
||||||
options = options || {}
|
options = options || {}
|
||||||
|
step = step ?? 200
|
||||||
|
|
||||||
if (!cl) throw new Error('Cloudinary not initialized')
|
if (!cl) throw new Error('Cloudinary not initialized')
|
||||||
if (!src) throw new Error('Src must be set in use:image')
|
if (!src) throw new Error('Src must be set in use:image')
|
||||||
@ -62,20 +76,32 @@ export function image(node: HTMLImageElement, parameters?: ImageParameters) {
|
|||||||
}
|
}
|
||||||
if (!options.crop) options.crop = 'fill'
|
if (!options.crop) options.crop = 'fill'
|
||||||
|
|
||||||
if (bind instanceof Element) Object.assign(options, getSizeOfElement(bind))
|
if (bind instanceof Element) Object.assign(options, getSizeOfElement(bind, step))
|
||||||
else if (typeof bind === 'string') {
|
else if (typeof bind === 'string') {
|
||||||
Object.assign(options, getSizeOfElementOrSelector(node, bind))
|
Object.assign(options, getSizeOfElementOrSelector(node, bind, step))
|
||||||
} else if (typeof bind === 'object') {
|
} else if (typeof bind === 'object') {
|
||||||
if (bind.width) {
|
if (bind.width) {
|
||||||
options.width = getSizeOfElementOrSelector(node, bind.width === true ? node : bind.width).width
|
options.width = getSizeOfElementOrSelector(node, bind.width === true ? node : bind.width, step).width
|
||||||
}
|
}
|
||||||
if (bind.height) {
|
if (bind.height) {
|
||||||
options.height = getSizeOfElementOrSelector(node, bind.height === true ? node : bind.height).height
|
options.height = getSizeOfElementOrSelector(node, bind.height === true ? node : bind.height, step).height
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const all: Transformation | Transformation.Options = { ...defaults, ...options }
|
const all: Transformation | Transformation.Options = { ...defaults, ...options }
|
||||||
const attrs: any = cl.imageTag(parameters.src, all).attributes()
|
const attrs: any = cl.imageTag(parameters.src, all).attributes()
|
||||||
node.src = attrs.src
|
const replace = () => (node.src = attrs.src)
|
||||||
|
|
||||||
|
if (lazy && typeof IntersectionObserver !== 'undefined') {
|
||||||
|
const options: IntersectionObserverInit = lazy === true ? { rootMargin: '25%', threshold: 0 } : lazy
|
||||||
|
new IntersectionObserver((entries, observer) => {
|
||||||
|
if (entries[0].isIntersecting) {
|
||||||
|
observer.disconnect()
|
||||||
|
replace()
|
||||||
|
}
|
||||||
|
}, options).observe(node)
|
||||||
|
} else {
|
||||||
|
replace()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user