@leafer/image 1.0.0-beta.15 → 1.0.0-beta.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@leafer/image",
3
- "version": "1.0.0-beta.15",
3
+ "version": "1.0.0-beta.16",
4
4
  "description": "@leafer/image",
5
5
  "author": "Chao (Leafer) Wan",
6
6
  "license": "MIT",
7
7
  "main": "src/index.ts",
8
8
  "types": "types/index.d.ts",
9
9
  "files": [
10
+ "src",
10
11
  "types",
11
12
  "dist"
12
13
  ],
@@ -21,10 +22,10 @@
21
22
  "leaferjs"
22
23
  ],
23
24
  "dependencies": {
24
- "@leafer/task": "1.0.0-beta.15",
25
- "@leafer/platform": "1.0.0-beta.15"
25
+ "@leafer/task": "1.0.0-beta.16",
26
+ "@leafer/platform": "1.0.0-beta.16"
26
27
  },
27
28
  "devDependencies": {
28
- "@leafer/interface": "1.0.0-beta.15"
29
+ "@leafer/interface": "1.0.0-beta.16"
29
30
  }
30
31
  }
@@ -0,0 +1,51 @@
1
+ import { IImageManager, ILeaferImageConfig, ILeaferImage } from '@leafer/interface'
2
+ import { Creator } from '@leafer/platform'
3
+ import { TaskProcessor } from '@leafer/task'
4
+
5
+ export const ImageManager: IImageManager = {
6
+
7
+ map: {},
8
+
9
+ recycledList: [],
10
+
11
+ tasker: new TaskProcessor(),
12
+
13
+ patternTasker: new TaskProcessor(),
14
+
15
+ get isComplete() { return I.tasker.isComplete && I.patternTasker.isComplete },
16
+
17
+ get(config: ILeaferImageConfig): ILeaferImage {
18
+ let image = I.map[config.url]
19
+ if (!image) {
20
+ image = Creator.image(config)
21
+ I.map[config.url] = image
22
+ }
23
+ image.use++
24
+ return image
25
+ },
26
+
27
+ recycle(image: ILeaferImage): void {
28
+ image.use--
29
+ setTimeout(() => { if (!image.use) I.recycledList.push(image) })
30
+ },
31
+
32
+ clearRecycled(): void {
33
+ const list = I.recycledList
34
+ if (list.length) {
35
+ list.forEach(image => {
36
+ if (!image.use && image.url) {
37
+ delete I.map[image.url]
38
+ image.destroy()
39
+ }
40
+ })
41
+ list.length = 0
42
+ }
43
+ },
44
+
45
+ destroy(): void {
46
+ I.map = {}
47
+ }
48
+
49
+ }
50
+
51
+ const I = ImageManager
@@ -0,0 +1,104 @@
1
+ import { ILeaferImage, ILeaferImageConfig, IFunction, IObject, InnerId } from '@leafer/interface'
2
+ import { Platform } from '@leafer/platform'
3
+ import { IncrementId } from '@leafer/math'
4
+
5
+ import { ImageManager } from './ImageManager'
6
+
7
+
8
+ const { IMAGE, create } = IncrementId
9
+
10
+ export class LeaferImage implements ILeaferImage {
11
+
12
+ public readonly innerId: InnerId
13
+ public get url() { return this.config.url }
14
+
15
+ public view: any
16
+
17
+ public width: number
18
+ public height: number
19
+
20
+ public isSVG: boolean
21
+
22
+ public get completed() { return this.ready || !!this.error }
23
+
24
+ public ready: boolean
25
+ public error: IObject
26
+ public loading: boolean
27
+
28
+ public use = 0
29
+
30
+ public config: ILeaferImageConfig
31
+
32
+ protected waitComplete: IFunction[] = []
33
+
34
+ constructor(config: ILeaferImageConfig) {
35
+ this.innerId = create(IMAGE)
36
+ this.config = config || { url: '' }
37
+ const { url } = config
38
+ if (url.startsWith('data:')) {
39
+ if (url.startsWith('data:image/svg')) this.isSVG = true
40
+ } else {
41
+ if (url.includes('.svg')) this.isSVG = true
42
+ }
43
+ if (this.config.format === 'svg') this.isSVG = true
44
+ }
45
+
46
+ public load(onSuccess: IFunction, onError: IFunction): number {
47
+ if (!this.loading) {
48
+ this.loading = true
49
+ ImageManager.tasker.add(async () => await Platform.origin.loadImage(this.url).then((img) => {
50
+ this.ready = true
51
+ this.width = img.naturalWidth || img.width
52
+ this.height = img.naturalHeight || img.height
53
+ this.view = img
54
+ this.onComplete(true)
55
+ }).catch((e) => {
56
+ this.error = e
57
+ this.onComplete(false)
58
+ }))
59
+ }
60
+ this.waitComplete.push(onSuccess, onError)
61
+ return this.waitComplete.length - 2
62
+ }
63
+
64
+ public unload(index: number, stopEvent?: boolean): void {
65
+ const l = this.waitComplete
66
+ if (stopEvent) {
67
+ const error = l[index + 1]
68
+ if (error) error({ type: 'stop' })
69
+ }
70
+ l[index] = l[index + 1] = undefined
71
+ }
72
+
73
+ protected onComplete(isSuccess: boolean): void {
74
+ let odd: number
75
+ this.waitComplete.forEach((item, index) => {
76
+ odd = index % 2
77
+ if (item) {
78
+ if (isSuccess) {
79
+ if (!odd) item(this)
80
+ } else {
81
+ if (odd) item(this.error)
82
+ }
83
+ }
84
+ })
85
+ this.waitComplete.length = 0
86
+ this.loading = false
87
+ }
88
+
89
+ public getCanvas(width: number, height: number, opacity?: number, _filters?: IObject): any {
90
+ width || (width = this.width)
91
+ height || (height = this.height)
92
+ const canvas = Platform.origin.createCanvas(width, height)
93
+ const ctx = canvas.getContext('2d')
94
+ if (opacity) ctx.globalAlpha = opacity
95
+ ctx.drawImage(this.view, 0, 0, width, height)
96
+ return canvas
97
+ }
98
+
99
+ public destroy(): void {
100
+ this.config = { url: '' }
101
+ this.waitComplete.length = 0
102
+ }
103
+
104
+ }