@leafer/image
Version:
146 lines (115 loc) • 4.69 kB
text/typescript
import { ILeaferImage, ILeaferImageConfig, IFunction, IObject, InnerId, IMatrixData, ICanvasPattern, ILeaferImageCacheCanvas, ILeaferImagePatternPaint, IProgressData } from '@leafer/interface'
import { Platform } from '@leafer/platform'
import { Resource } from '@leafer/file'
import { IncrementId } from '@leafer/math'
import { DataHelper } from '@leafer/data'
import { ImageManager } from './ImageManager'
const { IMAGE, create } = IncrementId
export class LeaferImage implements ILeaferImage {
public readonly innerId: InnerId
public get url() { return this.config.url }
public view: any
public width: number
public height: number
public isSVG: boolean
public hasAlphaPixel: boolean // check png / svg / webp
public get completed() { return this.ready || !!this.error }
public ready: boolean
public error: IObject
public loading: boolean
public progress: IProgressData
public use = 0
public config: ILeaferImageConfig
protected waitComplete: IFunction[] = []
protected cache: ILeaferImageCacheCanvas
constructor(config: ILeaferImageConfig) {
this.innerId = create(IMAGE)
this.config = config || (config = { url: '' })
if (config.view) {
const { view } = config
this.setView(view.config ? view.view : view)
}
ImageManager.isFormat('svg', config) && (this.isSVG = true)
ImageManager.hasAlphaPixel(config) && (this.hasAlphaPixel = true)
}
public load(onSuccess?: IFunction, onError?: IFunction): number {
if (!this.loading) {
this.loading = true
let { loadImage, loadImageWithProgress } = Platform.origin, onProgress = this.config.showProgress && loadImageWithProgress && this.onProgress.bind(this)
if (onProgress) loadImage = loadImageWithProgress
Resource.tasker.add(async () => await loadImage(this.url, onProgress).then(img => this.setView(img)).catch((e) => {
this.error = e
this.onComplete(false)
}))
}
this.waitComplete.push(onSuccess, onError)
return this.waitComplete.length - 2
}
public unload(index: number, stopEvent?: boolean): void {
const l = this.waitComplete
if (stopEvent) {
const error = l[index + 1]
if (error) error({ type: 'stop' })
}
l[index] = l[index + 1] = undefined
}
protected setView(img: any): void {
this.ready = true
this.width = img.naturalWidth || img.width
this.height = img.naturalHeight || img.height
this.view = img
this.onComplete(true)
}
protected onProgress(progress: IProgressData): void {
this.progress = progress
}
protected onComplete(isSuccess: boolean): void {
let odd: number
this.waitComplete.forEach((item, index) => {
odd = index % 2
if (item) {
if (isSuccess) {
if (!odd) item(this)
} else {
if (odd) item(this.error)
}
}
})
this.waitComplete.length = 0
this.loading = false
}
public getFull(_filters?: IObject): any {
return this.view
}
public getCanvas(width: number, height: number, opacity?: number, _filters?: IObject): any {
width || (width = this.width)
height || (height = this.height)
if (this.cache) { // when use > 1, check cache
let { params, data } = this.cache
for (let i in params) { if (params[i] !== arguments[i]) { data = null; break } }
if (data) return data
}
const canvas = Platform.origin.createCanvas(width, height)
const ctx = canvas.getContext('2d')
if (opacity) ctx.globalAlpha = opacity
ctx.drawImage(this.view, 0, 0, width, height)
this.cache = this.use > 1 ? { data: canvas, params: arguments } : null
return canvas
}
public getPattern(canvas: any, repeat: string | null, transform?: IMatrixData, paint?: ILeaferImagePatternPaint): ICanvasPattern {
const pattern = Platform.canvas.createPattern(canvas, repeat)
try {
if (transform && pattern.setTransform) {
pattern.setTransform(transform) // maybe error
transform = undefined
}
} catch { }
if (paint) DataHelper.stintSet(paint, 'transform', transform)
return pattern
}
public destroy(): void {
this.config = { url: '' }
this.cache = null
this.waitComplete.length = 0
}
}