@leafer-ui/image 1.8.0 → 1.9.1

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@leafer-ui/image",
3
- "version": "1.8.0",
3
+ "version": "1.9.1",
4
4
  "description": "@leafer-ui/image",
5
5
  "author": "Chao (Leafer) Wan",
6
6
  "license": "MIT",
@@ -22,11 +22,11 @@
22
22
  "leaferjs"
23
23
  ],
24
24
  "dependencies": {
25
- "@leafer/core": "1.8.0",
26
- "@leafer-ui/draw": "1.8.0"
25
+ "@leafer/core": "1.9.1",
26
+ "@leafer-ui/draw": "1.9.1"
27
27
  },
28
28
  "devDependencies": {
29
- "@leafer/interface": "1.8.0",
30
- "@leafer-ui/interface": "1.8.0"
29
+ "@leafer/interface": "1.9.1",
30
+ "@leafer-ui/interface": "1.9.1"
31
31
  }
32
32
  }
package/src/check.ts CHANGED
@@ -19,7 +19,7 @@ export function checkImage(ui: IUI, canvas: ILeaferCanvas, paint: ILeafPaint, al
19
19
  if (data.repeat) {
20
20
  allowDraw = false
21
21
  } else {
22
- if (!(paint.changeful || ResizeEvent.isResizing(ui) || Export.running)) {
22
+ if (!(paint.changeful || (Platform.name === 'miniapp' && ResizeEvent.isResizing(ui)) || Export.running)) { // 小程序resize过程中直接绘制原图(绕过垃圾回收bug)
23
23
  let { width, height } = data
24
24
  width *= scaleX * pixelRatio
25
25
  height *= scaleY * pixelRatio
package/src/data.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { IBoundsData, ILeaferImage, IScaleData } from '@leafer/interface'
2
- import { MatrixHelper, MathHelper, Bounds, AlignHelper, BoundsHelper, PointHelper } from '@leafer/core'
1
+ import { IBoundsData, IGap, ILeaferImage, IPointData, IPointGap, IScaleData } from '@leafer/interface'
2
+ import { MatrixHelper, MathHelper, Bounds, AlignHelper, BoundsHelper, PointHelper, isObject, isString } from '@leafer/core'
3
3
 
4
4
  import { IImagePaint, ILeafPaint, ILeafPaintPatternData } from '@leafer-ui/interface'
5
5
 
@@ -12,10 +12,9 @@ const tempScaleData = {} as IScaleData
12
12
  const tempImage = {} as IBoundsData
13
13
 
14
14
  export function createData(leafPaint: ILeafPaint, image: ILeaferImage, paint: IImagePaint, box: IBoundsData): void {
15
- const { changeful, sync, editing, scaleFixed } = paint
15
+ const { changeful, sync, scaleFixed } = paint
16
16
  if (changeful) leafPaint.changeful = changeful
17
17
  if (sync) leafPaint.sync = sync
18
- if (editing) leafPaint.editing = editing
19
18
  if (scaleFixed) leafPaint.scaleFixed = scaleFixed
20
19
  leafPaint.data = getPatternData(paint, box, image)
21
20
  }
@@ -25,7 +24,7 @@ export function getPatternData(paint: IImagePaint, box: IBoundsData, image: ILea
25
24
  if (paint.mode === 'strench' as string) paint.mode = 'stretch' // 兼容代码,后续可移除
26
25
 
27
26
  let { width, height } = image
28
- const { opacity, mode, align, offset, scale, size, rotation, skew, clipSize, repeat, filters } = paint
27
+ const { opacity, mode, align, offset, scale, size, rotation, skew, clipSize, repeat, gap, filters } = paint
29
28
  const sameBox = box.width === width && box.height === height
30
29
 
31
30
  const data: ILeafPaintPatternData = { mode }
@@ -47,9 +46,9 @@ export function getPatternData(paint: IImagePaint, box: IBoundsData, image: ILea
47
46
  scaleY = tempScaleData.scaleY
48
47
  }
49
48
 
50
- if (align) {
49
+ if (align || gap || repeat) {
51
50
  if (scaleX) BoundsHelper.scale(tempImage, scaleX, scaleY, true)
52
- AlignHelper.toPoint(align, tempImage, box, tempImage, true, true)
51
+ if (align) AlignHelper.toPoint(align, tempImage, box, tempImage, true, true)
53
52
  }
54
53
  }
55
54
 
@@ -64,8 +63,10 @@ export function getPatternData(paint: IImagePaint, box: IBoundsData, image: ILea
64
63
  if (tempImage.x || tempImage.y || scaleX || clipSize || rotation || skew) clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, paint.clipSize)
65
64
  break
66
65
  case 'repeat':
67
- if (!sameBox || scaleX || rotation) repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, align)
66
+ if (!sameBox || scaleX || rotation || skew) repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, align, paint.freeTransform)
68
67
  if (!repeat) data.repeat = 'repeat'
68
+ const count = isObject(repeat)
69
+ if (gap || count) data.gap = getGapData(gap, count && repeat, tempImage.width, tempImage.height, box)
69
70
  break
70
71
  case 'fit':
71
72
  case 'cover':
@@ -89,6 +90,21 @@ export function getPatternData(paint: IImagePaint, box: IBoundsData, image: ILea
89
90
  data.height = height
90
91
  if (opacity) data.opacity = opacity
91
92
  if (filters) data.filters = filters
92
- if (repeat) data.repeat = typeof repeat === 'string' ? (repeat === 'x' ? 'repeat-x' : 'repeat-y') : 'repeat'
93
+ if (repeat) data.repeat = isString(repeat) ? (repeat === 'x' ? 'repeat-x' : 'repeat-y') : 'repeat'
93
94
  return data
95
+ }
96
+
97
+
98
+ function getGapData(gap: IGap | IPointGap, repeat: IPointData, width: number, height: number, box: IBoundsData): IPointData {
99
+ let xGap: IGap, yGap: IGap
100
+ if (isObject(gap)) xGap = gap.x, yGap = gap.y
101
+ else xGap = yGap = gap
102
+ return { x: getGapValue(xGap, width, box.width, repeat && repeat.x), y: getGapValue(yGap, height, box.height, repeat && repeat.y) }
103
+ }
104
+
105
+ function getGapValue(gap: IGap, size: number, totalSize: number, rows: number): number {
106
+ const auto = isString(gap) || rows
107
+ const remain = rows ? totalSize - rows * size : totalSize % size
108
+ const value = auto ? remain / ((rows || Math.floor(totalSize / size)) - 1) : gap
109
+ return gap === 'auto' ? (value < 0 ? 0 : value) : value
94
110
  }
package/src/mode.ts CHANGED
@@ -15,14 +15,9 @@ export function fillOrFitMode(data: ILeafPaintPatternData, box: IBoundsData, x:
15
15
  data.transform = transform
16
16
  }
17
17
 
18
-
19
18
  export function clipMode(data: ILeafPaintPatternData, box: IBoundsData, x: number, y: number, scaleX: number, scaleY: number, rotation: number, skew: IPointData, clipSize?: ISizeData): void {
20
- // rotate -> skew -> scale -> translate
21
19
  const transform: IMatrixData = get()
22
- if (rotation) rotate(transform, rotation)
23
- if (skew) skewHelper(transform, skew.x, skew.y)
24
- if (scaleX) scaleHelper(transform, scaleX, scaleY)
25
- translate(transform, box.x + x, box.y + y)
20
+ layout(transform, box, x, y, scaleX, scaleY, rotation, skew)
26
21
  if (clipSize) {
27
22
  tempMatrix.a = box.width / clipSize.width, tempMatrix.d = box.height / clipSize.height
28
23
  multiplyParent(transform, tempMatrix)
@@ -30,30 +25,41 @@ export function clipMode(data: ILeafPaintPatternData, box: IBoundsData, x: numbe
30
25
  data.transform = transform
31
26
  }
32
27
 
33
-
34
- export function repeatMode(data: ILeafPaintPatternData, box: IBoundsData, width: number, height: number, x: number, y: number, scaleX: number, scaleY: number, rotation: number, align: IAlign): void {
28
+ export function repeatMode(data: ILeafPaintPatternData, box: IBoundsData, width: number, height: number, x: number, y: number, scaleX: number, scaleY: number, rotation: number, skew: IPointData, align: IAlign, freeTransform?: boolean): void {
35
29
  const transform = get()
36
- if (rotation) {
37
- if (align === 'center') {
38
- rotateOfOuter(transform, { x: width / 2, y: height / 2 }, rotation)
39
- } else {
40
- rotate(transform, rotation)
41
- switch (rotation) {
42
- case 90:
43
- translate(transform, height, 0)
44
- break
45
- case 180:
46
- translate(transform, width, height)
47
- break
48
- case 270:
49
- translate(transform, 0, width)
50
- break
30
+ if (freeTransform) { // 自由变换
31
+ layout(transform, box, x, y, scaleX, scaleY, rotation, skew)
32
+ } else {
33
+ if (rotation) {
34
+ if (align === 'center') {
35
+ rotateOfOuter(transform, { x: width / 2, y: height / 2 }, rotation)
36
+ } else {
37
+ rotate(transform, rotation)
38
+ switch (rotation) {
39
+ case 90:
40
+ translate(transform, height, 0)
41
+ break
42
+ case 180:
43
+ translate(transform, width, height)
44
+ break
45
+ case 270:
46
+ translate(transform, 0, width)
47
+ break
48
+ }
51
49
  }
52
50
  }
51
+ origin.x = box.x + x
52
+ origin.y = box.y + y
53
+ translate(transform, origin.x, origin.y)
54
+ if (scaleX) scaleOfOuter(transform, origin, scaleX, scaleY)
53
55
  }
54
- origin.x = box.x + x
55
- origin.y = box.y + y
56
- translate(transform, origin.x, origin.y)
57
- if (scaleX) scaleOfOuter(transform, origin, scaleX, scaleY)
58
56
  data.transform = transform
59
- }
57
+ }
58
+
59
+ function layout(transform: IMatrixData, box: IBoundsData, x: number, y: number, scaleX: number, scaleY: number, rotation: number, skew: IPointData) {
60
+ // rotate -> skew -> scale -> translate
61
+ if (rotation) rotate(transform, rotation)
62
+ if (skew) skewHelper(transform, skew.x, skew.y)
63
+ if (scaleX) scaleHelper(transform, scaleX, scaleY)
64
+ translate(transform, box.x + x, box.y + y)
65
+ }
package/src/pattern.ts CHANGED
@@ -4,7 +4,7 @@ import { IUI, ILeafPaint, IMatrixData } from '@leafer-ui/interface'
4
4
 
5
5
 
6
6
  const { get, scale, copy } = MatrixHelper
7
- const { ceil, abs } = Math
7
+ const { floor, max, abs } = Math
8
8
 
9
9
  export function createPattern(ui: IUI, paint: ILeafPaint, pixelRatio: number): boolean {
10
10
  let { scaleX, scaleY } = ui.getRenderScaleData(true, paint.scaleFixed)
@@ -13,7 +13,13 @@ export function createPattern(ui: IUI, paint: ILeafPaint, pixelRatio: number): b
13
13
  if (paint.patternId !== id && !ui.destroyed) {
14
14
 
15
15
  const { image, data } = paint
16
- let imageScale: number, imageMatrix: IMatrixData, { width, height, scaleX: sx, scaleY: sy, transform, repeat } = data
16
+ let imageScale: number, imageMatrix: IMatrixData, { width, height, scaleX: sx, scaleY: sy, transform, repeat, gap } = data
17
+
18
+ scaleX *= pixelRatio
19
+ scaleY *= pixelRatio
20
+
21
+ const xGap = gap && (gap.x * scaleX)
22
+ const yGap = gap && (gap.y * scaleY)
17
23
 
18
24
  if (sx) {
19
25
  sx = abs(sx) // maybe -1
@@ -25,8 +31,6 @@ export function createPattern(ui: IUI, paint: ILeafPaint, pixelRatio: number): b
25
31
  scaleY *= sy
26
32
  }
27
33
 
28
- scaleX *= pixelRatio
29
- scaleY *= pixelRatio
30
34
  width *= scaleX
31
35
  height *= scaleY
32
36
 
@@ -65,7 +69,12 @@ export function createPattern(ui: IUI, paint: ILeafPaint, pixelRatio: number): b
65
69
  scale(imageMatrix, 1 / scaleX, 1 / scaleY)
66
70
  }
67
71
 
68
- const canvas = image.getCanvas(ceil(width) || 1, ceil(height) || 1, data.opacity, data.filters)
72
+ if (imageMatrix) {
73
+ const canvasWidth = width + (xGap || 0), canvasHeight = height + (yGap || 0)
74
+ scale(imageMatrix, canvasWidth / max(floor(canvasWidth), 1), canvasHeight / max(floor(canvasHeight), 1)) // 缩放至floor画布宽高的状态
75
+ }
76
+
77
+ const canvas = image.getCanvas(width, height, data.opacity, data.filters, xGap, yGap)
69
78
  const pattern = image.getPattern(canvas, repeat || (Platform.origin.noRepeat || 'no-repeat'), imageMatrix, paint)
70
79
 
71
80
  paint.style = pattern
package/src/recycle.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { IBooleanMap, ILeaferImage, IObject } from '@leafer/interface'
2
- import { ImageManager } from '@leafer/core'
2
+ import { ImageManager, isArray } from '@leafer/core'
3
3
 
4
4
  import { IImagePaint, ILeafPaint, IPaintAttr, IUIData } from '@leafer-ui/interface'
5
5
 
@@ -7,7 +7,7 @@ import { IImagePaint, ILeafPaint, IPaintAttr, IUIData } from '@leafer-ui/interfa
7
7
  export function recycleImage(attrName: IPaintAttr, data: IUIData): IBooleanMap {
8
8
  const paints: ILeafPaint[] = (data as IObject)['_' + attrName]
9
9
 
10
- if (paints instanceof Array) {
10
+ if (isArray(paints)) {
11
11
 
12
12
  let paint: ILeafPaint, image: ILeaferImage, recycleMap: IBooleanMap, input: IImagePaint[], url: string
13
13
 
@@ -26,7 +26,7 @@ export function recycleImage(attrName: IPaintAttr, data: IUIData): IBooleanMap {
26
26
  if (image.loading) {
27
27
  if (!input) {
28
28
  input = (data.__input && data.__input[attrName]) || []
29
- if (!(input instanceof Array)) input = [input]
29
+ if (!isArray(input)) input = [input]
30
30
  }
31
31
  image.unload(paints[i].loadId, !input.some((item: IImagePaint) => item.url === url))
32
32
  }