@leafer-ui/paint 1.0.0-beta.10 → 1.0.0-beta.12
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 +5 -5
- package/src/Compute.ts +2 -1
- package/src/index.ts +2 -1
- package/src/paint/image/check.ts +12 -10
- package/src/paint/image/data.ts +2 -6
- package/src/paint/image/image.ts +26 -26
- package/src/paint/image/index.ts +2 -0
- package/src/paint/image/pattern.ts +39 -26
- package/src/paint/image/recycle.ts +41 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leafer-ui/paint",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.12",
|
|
4
4
|
"description": "@leafer-ui/paint",
|
|
5
5
|
"author": "Chao (Leafer) Wan",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
"leaferjs"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@leafer/core": "1.0.0-beta.
|
|
23
|
-
"@leafer-ui/color": "1.0.0-beta.
|
|
22
|
+
"@leafer/core": "1.0.0-beta.12",
|
|
23
|
+
"@leafer-ui/color": "1.0.0-beta.12"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@leafer/interface": "1.0.0-beta.
|
|
27
|
-
"@leafer-ui/interface": "1.0.0-beta.
|
|
26
|
+
"@leafer/interface": "1.0.0-beta.12",
|
|
27
|
+
"@leafer-ui/interface": "1.0.0-beta.12"
|
|
28
28
|
}
|
|
29
29
|
}
|
package/src/Compute.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { image } from "./paint/image/image"
|
|
|
5
5
|
import { linearGradient } from './paint/linear'
|
|
6
6
|
import { radialGradient } from "./paint/radial"
|
|
7
7
|
import { conicGradient } from "./paint/conic"
|
|
8
|
+
import { recycleImage } from './paint/image'
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
let recycleMap: IBooleanMap
|
|
@@ -16,7 +17,7 @@ export function compute(ui: IUI, attrName: string): void {
|
|
|
16
17
|
|
|
17
18
|
if (!(paints instanceof Array)) paints = [paints]
|
|
18
19
|
|
|
19
|
-
recycleMap = ui.__
|
|
20
|
+
recycleMap = recycleImage(ui.__, attrName)
|
|
20
21
|
|
|
21
22
|
for (let i = 0, len = paints.length; i < len; i++) {
|
|
22
23
|
item = getLeafPaint(ui, paints[i], attrName)
|
package/src/index.ts
CHANGED
|
@@ -3,4 +3,5 @@ export { fillText } from './FillText'
|
|
|
3
3
|
export { stroke, strokes } from './Stroke'
|
|
4
4
|
export { strokeText, drawTextStroke } from './StrokeText'
|
|
5
5
|
export { shape } from './Shape'
|
|
6
|
-
export { compute } from './Compute'
|
|
6
|
+
export { compute } from './Compute'
|
|
7
|
+
export { recycleImage } from './paint/image'
|
package/src/paint/image/check.ts
CHANGED
|
@@ -8,16 +8,17 @@ import { createPattern } from './pattern'
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
export function checkImage(ui: IUI, canvas: ILeaferCanvas, paint: ILeafPaint, allowPaint?: boolean): boolean {
|
|
11
|
-
|
|
11
|
+
const { scaleX, scaleY } = ui.__world
|
|
12
12
|
|
|
13
|
-
if (!paint.data || paint.patternId ===
|
|
13
|
+
if (!paint.data || paint.patternId === scaleX + scaleY) {
|
|
14
14
|
return false
|
|
15
15
|
} else {
|
|
16
16
|
|
|
17
17
|
if (allowPaint) {
|
|
18
18
|
if (paint.image.isSVG && paint.data.mode !== 'repeat') {
|
|
19
|
-
width
|
|
20
|
-
|
|
19
|
+
let { width, height } = paint.data
|
|
20
|
+
width *= scaleX * canvas.pixelRatio
|
|
21
|
+
height *= scaleY * canvas.pixelRatio
|
|
21
22
|
allowPaint = width > 4096 || height > 4096
|
|
22
23
|
} else {
|
|
23
24
|
allowPaint = false
|
|
@@ -35,12 +36,13 @@ export function checkImage(ui: IUI, canvas: ILeaferCanvas, paint: ILeafPaint, al
|
|
|
35
36
|
canvas.restore()
|
|
36
37
|
return true
|
|
37
38
|
} else {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
if (!paint.style) {
|
|
40
|
+
createPattern(ui, paint, canvas.pixelRatio)
|
|
41
|
+
} else {
|
|
42
|
+
ImageManager.patternTasker.add(async () => {
|
|
43
|
+
if (canvas.bounds.hit(ui.__world) && createPattern(ui, paint, canvas.pixelRatio)) ui.forceUpdate('surface')
|
|
44
|
+
}, 300)
|
|
45
|
+
}
|
|
44
46
|
return false
|
|
45
47
|
}
|
|
46
48
|
}
|
package/src/paint/image/data.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { IBoundsData, ILeaferImage } from '@leafer/interface'
|
|
2
2
|
import { MatrixHelper } from '@leafer/core'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { IImagePaint, ILeafPaint, ILeafPaintPatternData } from '@leafer-ui/interface'
|
|
5
5
|
|
|
6
6
|
import { clipMode, fillOrFitMode, repeatMode } from './mode'
|
|
7
|
-
import { createPattern } from './pattern'
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
const { get, translate } = MatrixHelper
|
|
11
10
|
|
|
12
|
-
export function createData(
|
|
11
|
+
export function createData(leafPaint: ILeafPaint, image: ILeaferImage, paint: IImagePaint, box: IBoundsData): void {
|
|
13
12
|
let { width, height } = image
|
|
14
13
|
|
|
15
14
|
const { opacity, mode, offset, scale, rotation, blendMode } = paint
|
|
@@ -41,7 +40,4 @@ export function createData(ui: IUI, leafPaint: ILeafPaint, image: ILeaferImage,
|
|
|
41
40
|
data.width = width
|
|
42
41
|
data.height = height
|
|
43
42
|
if (opacity) data.opacity = opacity
|
|
44
|
-
|
|
45
|
-
const canvas = ui.leafer && ui.leafer.canvas
|
|
46
|
-
if (canvas && canvas.bounds.hit(ui.__world)) createPattern(ui, leafPaint, canvas.pixelRatio)
|
|
47
43
|
}
|
package/src/paint/image/image.ts
CHANGED
|
@@ -6,51 +6,51 @@ import { IUI, IImagePaint, ILeafPaint } from '@leafer-ui/interface'
|
|
|
6
6
|
import { createData } from './data'
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
export function image(ui: IUI, attrName: string, attrValue: IImagePaint, box: IBoundsData,
|
|
9
|
+
export function image(ui: IUI, attrName: string, attrValue: IImagePaint, box: IBoundsData, firstUse: boolean): ILeafPaint {
|
|
10
10
|
const leafPaint: ILeafPaint = { type: attrValue.type }
|
|
11
11
|
const image = leafPaint.image = ImageManager.get(attrValue)
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
const event: IImageEvent = (firstUse || image.loading) && { target: ui, image, attrName, attrValue }
|
|
14
14
|
|
|
15
|
-
if (
|
|
15
|
+
if (image.ready) {
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (image.ready) {
|
|
17
|
+
if (hasNaturalSize(ui, attrName, image)) createData(leafPaint, image, attrValue, box)
|
|
20
18
|
|
|
19
|
+
if (firstUse) {
|
|
21
20
|
emit(ImageEvent.LOAD, event)
|
|
22
21
|
emit(ImageEvent.LOADED, event)
|
|
22
|
+
}
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
} else if (image.error) {
|
|
25
25
|
|
|
26
|
+
if (firstUse) {
|
|
26
27
|
ui.forceUpdate('surface')
|
|
27
28
|
event.error = image.error
|
|
28
29
|
emit(ImageEvent.ERROR, event)
|
|
30
|
+
}
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
emit(ImageEvent.LOAD, event)
|
|
32
|
+
} else {
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
() => {
|
|
36
|
-
if (ui.__) {
|
|
34
|
+
if (firstUse) emit(ImageEvent.LOAD, event)
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
36
|
+
leafPaint.loadId = image.load(
|
|
37
|
+
() => {
|
|
38
|
+
if (!ui.destroyed) {
|
|
42
39
|
|
|
43
|
-
|
|
40
|
+
if (hasNaturalSize(ui, attrName, image)) {
|
|
41
|
+
createData(leafPaint, image, attrValue, box)
|
|
42
|
+
ui.forceUpdate('surface')
|
|
44
43
|
}
|
|
45
|
-
},
|
|
46
|
-
(error) => {
|
|
47
|
-
ui.forceUpdate('surface')
|
|
48
|
-
event.error = error
|
|
49
|
-
emit(ImageEvent.ERROR, event)
|
|
50
|
-
}
|
|
51
|
-
)
|
|
52
44
|
|
|
53
|
-
|
|
45
|
+
emit(ImageEvent.LOADED, event)
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
(error) => {
|
|
49
|
+
ui.forceUpdate('surface')
|
|
50
|
+
event.error = error
|
|
51
|
+
emit(ImageEvent.ERROR, event)
|
|
52
|
+
}
|
|
53
|
+
)
|
|
54
54
|
|
|
55
55
|
}
|
|
56
56
|
|
package/src/paint/image/index.ts
CHANGED
|
@@ -5,64 +5,77 @@ import { IUI, ILeafPaint, IMatrixData } from '@leafer-ui/interface'
|
|
|
5
5
|
|
|
6
6
|
const { get, scale: scaleHelper, copy } = MatrixHelper
|
|
7
7
|
|
|
8
|
-
export function createPattern(ui: IUI, paint: ILeafPaint, pixelRatio: number):
|
|
9
|
-
const id = ui.__world.width + ui.__world.height
|
|
8
|
+
export function createPattern(ui: IUI, paint: ILeafPaint, pixelRatio: number): boolean {
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
let { scaleX, scaleY } = ui.__world
|
|
11
|
+
|
|
12
|
+
const id = scaleX + scaleY
|
|
13
|
+
|
|
14
|
+
if (paint.patternId !== id && !ui.destroyed) {
|
|
12
15
|
|
|
13
16
|
paint.patternId = id
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
const { image, data } = paint
|
|
19
|
+
const maxWidth = image.isSVG ? 4096 : Math.min(image.width, 4096)
|
|
20
|
+
const maxHeight = image.isSVG ? 4096 : Math.min(image.height, 4096)
|
|
21
|
+
let scale: number, matrix: IMatrixData, { width, height, scaleX: sx, scaleY: sy, opacity, transform, mode } = data
|
|
16
22
|
|
|
17
|
-
if (
|
|
23
|
+
if (sx) {
|
|
18
24
|
matrix = get()
|
|
19
25
|
copy(matrix, transform)
|
|
20
|
-
scaleHelper(matrix, 1 /
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
scaleHelper(matrix, 1 / sx, 1 / sy)
|
|
27
|
+
scaleX *= sx
|
|
28
|
+
scaleY *= sy
|
|
23
29
|
}
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
width *=
|
|
28
|
-
height *=
|
|
29
|
-
|
|
30
|
-
const { image } = paint
|
|
31
|
-
const maxWidth = image.isSVG ? 4096 : Math.min(image.width, 4096)
|
|
32
|
-
const maxHeight = image.isSVG ? 4096 : Math.min(image.height, 4096)
|
|
31
|
+
scaleX *= pixelRatio
|
|
32
|
+
scaleY *= pixelRatio
|
|
33
|
+
width *= scaleX
|
|
34
|
+
height *= scaleY
|
|
33
35
|
|
|
34
36
|
if (width > maxWidth || height > maxHeight) {
|
|
35
37
|
scale = Math.max(width / maxWidth, height / maxHeight)
|
|
38
|
+
} else if (width < 32 || height < 32) {
|
|
39
|
+
scale = Math.min(width / 32, height / 32)
|
|
40
|
+
}
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
if (scale) {
|
|
43
|
+
scaleX /= scale
|
|
44
|
+
scaleY /= scale
|
|
39
45
|
width /= scale
|
|
40
46
|
height /= scale
|
|
41
47
|
}
|
|
42
48
|
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
if (sx) {
|
|
50
|
+
scaleX /= sx
|
|
51
|
+
scaleY /= sy
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
if (transform ||
|
|
54
|
+
if (transform || scaleX !== 1 || scaleY !== 1) {
|
|
49
55
|
if (!matrix) {
|
|
50
56
|
matrix = get()
|
|
51
57
|
if (transform) copy(matrix, transform)
|
|
52
58
|
}
|
|
53
|
-
scaleHelper(matrix, 1 /
|
|
59
|
+
scaleHelper(matrix, 1 / scaleX, 1 / scaleY)
|
|
54
60
|
}
|
|
55
61
|
|
|
56
|
-
const style = Platform.canvas.createPattern(
|
|
57
|
-
|
|
58
|
-
paint.transform = null
|
|
62
|
+
const style = Platform.canvas.createPattern(image.getCanvas(width, height, opacity) as any, mode === 'repeat' ? 'repeat' : (Platform.origin.noRepeat || 'no-repeat'))
|
|
59
63
|
|
|
60
64
|
try {
|
|
65
|
+
if (paint.transform) paint.transform = null
|
|
61
66
|
if (matrix) style.setTransform ? style.setTransform(matrix) : paint.transform = matrix
|
|
62
67
|
} catch (e) {
|
|
63
68
|
paint.transform = matrix
|
|
64
69
|
}
|
|
65
70
|
|
|
66
71
|
paint.style = style
|
|
72
|
+
|
|
73
|
+
return true
|
|
74
|
+
|
|
75
|
+
} else {
|
|
76
|
+
|
|
77
|
+
return false
|
|
78
|
+
|
|
67
79
|
}
|
|
80
|
+
|
|
68
81
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { IBooleanMap, ILeaferImage } from '@leafer/interface'
|
|
2
|
+
import { ImageManager } from '@leafer/core'
|
|
3
|
+
|
|
4
|
+
import { IImagePaint, ILeafPaint, IUIData } from '@leafer-ui/interface'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export function recycleImage(data: IUIData, attrName: string): IBooleanMap {
|
|
8
|
+
const paints = (attrName === 'fill' ? data._fill : data._stroke) as ILeafPaint[]
|
|
9
|
+
|
|
10
|
+
if (paints instanceof Array) {
|
|
11
|
+
|
|
12
|
+
let image: ILeaferImage, recycleMap: IBooleanMap, input: IImagePaint[], url: string
|
|
13
|
+
|
|
14
|
+
for (let i = 0, len = paints.length; i < len; i++) {
|
|
15
|
+
|
|
16
|
+
image = paints[i].image
|
|
17
|
+
url = image && image.url
|
|
18
|
+
|
|
19
|
+
if (url) {
|
|
20
|
+
if (!recycleMap) recycleMap = {}
|
|
21
|
+
recycleMap[url] = true
|
|
22
|
+
ImageManager.recycle(image)
|
|
23
|
+
|
|
24
|
+
// stop load
|
|
25
|
+
if (image.loading) {
|
|
26
|
+
if (!input) {
|
|
27
|
+
input = (data.__input && data.__input[attrName]) || []
|
|
28
|
+
if (!(input instanceof Array)) input = [input]
|
|
29
|
+
}
|
|
30
|
+
image.unload(paints[i].loadId, !input.some((item: IImagePaint) => item.url === url))
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return recycleMap
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return null
|
|
41
|
+
}
|