@leafer-ui/paint 1.0.0-rc.2 → 1.0.0-rc.21

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/paint",
3
- "version": "1.0.0-rc.2",
3
+ "version": "1.0.0-rc.21",
4
4
  "description": "@leafer-ui/paint",
5
5
  "author": "Chao (Leafer) Wan",
6
6
  "license": "MIT",
@@ -15,17 +15,18 @@
15
15
  "type": "git",
16
16
  "url": "https://github.com/leaferjs/ui.git"
17
17
  },
18
- "homepage": "https://github.com/leaferjs/ui/tree/main/packages/paint",
18
+ "homepage": "https://github.com/leaferjs/ui/tree/main/packages/partner/paint",
19
19
  "bugs": "https://github.com/leaferjs/ui/issues",
20
20
  "keywords": [
21
21
  "leafer-ui",
22
22
  "leaferjs"
23
23
  ],
24
24
  "dependencies": {
25
- "@leafer/core": "1.0.0-rc.2"
25
+ "@leafer/core": "1.0.0-rc.21",
26
+ "@leafer-ui/draw": "1.0.0-rc.21"
26
27
  },
27
28
  "devDependencies": {
28
- "@leafer/interface": "1.0.0-rc.2",
29
- "@leafer-ui/interface": "1.0.0-rc.2"
29
+ "@leafer/interface": "1.0.0-rc.21",
30
+ "@leafer-ui/interface": "1.0.0-rc.21"
30
31
  }
31
32
  }
package/src/Compute.ts CHANGED
@@ -1,34 +1,35 @@
1
- import { IUI, IPaint, ILeafPaint, IRGB, IBooleanMap } from '@leafer-ui/interface'
2
- import { ColorConvert } from '@leafer-ui/core'
3
-
4
- import { image } from "./paint/image/image"
5
- import { linearGradient } from './paint/linear'
6
- import { radialGradient } from "./paint/radial"
7
- import { conicGradient } from "./paint/conic"
8
- import { recycleImage } from './paint/image'
1
+ import { IUI, IPaint, ILeafPaint, IRGB, IBooleanMap, IObject, IPaintAttr } from '@leafer-ui/interface'
2
+ import { ColorConvert, PaintImage, PaintGradient } from '@leafer-ui/draw'
9
3
 
10
4
 
11
5
  let recycleMap: IBooleanMap
12
6
 
13
- export function compute(ui: IUI, attrName: string): void {
14
- const value: ILeafPaint[] = []
15
- let item: ILeafPaint
16
- let paints = ui.__.__input[attrName] as IPaint[]
7
+ export function compute(attrName: IPaintAttr, ui: IUI): void {
8
+ const data = ui.__, leafPaints: ILeafPaint[] = []
17
9
 
10
+ let paints: IPaint[] = data.__input[attrName], hasOpacityPixel: boolean
18
11
  if (!(paints instanceof Array)) paints = [paints]
19
12
 
20
- recycleMap = recycleImage(ui.__, attrName)
13
+ recycleMap = PaintImage.recycleImage(attrName, data)
21
14
 
22
- for (let i = 0, len = paints.length; i < len; i++) {
23
- item = getLeafPaint(ui, paints[i], attrName)
24
- if (item) value.push(item)
15
+ for (let i = 0, len = paints.length, item: ILeafPaint; i < len; i++) {
16
+ item = getLeafPaint(attrName, paints[i], ui)
17
+ if (item) leafPaints.push(item)
25
18
  }
26
19
 
27
- ui.__['_' + attrName] = value.length ? value : undefined
20
+ (data as IObject)['_' + attrName] = leafPaints.length ? leafPaints : undefined
21
+
22
+ if (leafPaints.length && leafPaints[0].image) hasOpacityPixel = leafPaints[0].image.hasOpacityPixel
23
+
24
+ if (attrName === 'fill') {
25
+ data.__pixelFill = hasOpacityPixel
26
+ } else {
27
+ data.__pixelStroke = hasOpacityPixel
28
+ }
28
29
  }
29
30
 
30
31
 
31
- function getLeafPaint(ui: IUI, paint: IPaint, attrName: string): ILeafPaint {
32
+ function getLeafPaint(attrName: string, paint: IPaint, ui: IUI): ILeafPaint {
32
33
  if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0) return undefined
33
34
  const { boxBounds } = ui.__layout
34
35
 
@@ -37,13 +38,13 @@ function getLeafPaint(ui: IUI, paint: IPaint, attrName: string): ILeafPaint {
37
38
  let { type, blendMode, color, opacity } = paint
38
39
  return { type, blendMode, style: ColorConvert.string(color, opacity) }
39
40
  case 'image':
40
- return image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url])
41
+ return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url])
41
42
  case 'linear':
42
- return linearGradient(paint, boxBounds)
43
+ return PaintGradient.linearGradient(paint, boxBounds)
43
44
  case 'radial':
44
- return radialGradient(paint, boxBounds)
45
+ return PaintGradient.radialGradient(paint, boxBounds)
45
46
  case 'angular':
46
- return conicGradient(paint, boxBounds)
47
+ return PaintGradient.conicGradient(paint, boxBounds)
47
48
  default:
48
49
  return (paint as IRGB).r ? { type: 'solid', style: ColorConvert.string(paint) } : undefined
49
50
  }
package/src/Fill.ts CHANGED
@@ -1,24 +1,24 @@
1
1
  import { ILeaferCanvas } from '@leafer/interface'
2
2
 
3
3
  import { ILeafPaint, IUI } from '@leafer-ui/interface'
4
+ import { PaintImage } from "@leafer-ui/draw"
4
5
 
5
- import { checkImage } from './paint/image'
6
6
  import { fillText } from './FillText'
7
7
 
8
8
 
9
- export function fill(ui: IUI, canvas: ILeaferCanvas, fill: string): void {
9
+ export function fill(fill: string, ui: IUI, canvas: ILeaferCanvas): void {
10
10
  canvas.fillStyle = fill
11
11
  ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill())
12
12
  }
13
13
 
14
14
 
15
- export function fills(ui: IUI, canvas: ILeaferCanvas, fills: ILeafPaint[]): void {
15
+ export function fills(fills: ILeafPaint[], ui: IUI, canvas: ILeaferCanvas): void {
16
16
  let item: ILeafPaint
17
17
  const { windingRule, __font } = ui.__
18
18
  for (let i = 0, len = fills.length; i < len; i++) {
19
19
  item = fills[i]
20
20
 
21
- if (item.image && checkImage(ui, canvas, item, !__font)) continue
21
+ if (item.image && PaintImage.checkImage(ui, canvas, item, !__font)) continue
22
22
 
23
23
  if (item.style) {
24
24
 
package/src/Shape.ts CHANGED
@@ -8,52 +8,52 @@ const { getSpread, getOuterOf, getByMove, getIntersectData } = BoundsHelper
8
8
 
9
9
  export function shape(ui: IUI, current: ILeaferCanvas, options: IRenderOptions): ICachedShape {
10
10
  const canvas = current.getSameCanvas()
11
+ const nowWorld = ui.__nowWorld
11
12
 
12
- let bounds: IBoundsData, matrix: IMatrix, shapeBounds: IBoundsData
13
- let worldCanvas: ILeaferCanvas
13
+ let bounds: IBoundsData, fitMatrix: IMatrix, shapeBounds: IBoundsData, worldCanvas: ILeaferCanvas
14
14
 
15
- const { __world } = ui
16
- let { scaleX, scaleY } = __world
15
+ let { scaleX, scaleY } = nowWorld
17
16
  if (scaleX < 0) scaleX = -scaleX
18
17
  if (scaleY < 0) scaleY = -scaleY
19
18
 
20
- if (!current.bounds.includes(__world, options.matrix)) {
19
+ if (current.bounds.includes(nowWorld)) {
20
+
21
+ worldCanvas = canvas
22
+ bounds = shapeBounds = nowWorld
23
+
24
+ } else {
21
25
 
22
26
  const { renderShapeSpread: spread } = ui.__layout
23
- const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, spread * scaleX, spread * scaleY) : current.bounds, __world, options.matrix)
24
- matrix = current.bounds.getFitMatrix(worldClipBounds)
27
+ const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, spread * scaleX, spread * scaleY) : current.bounds, nowWorld)
28
+ fitMatrix = current.bounds.getFitMatrix(worldClipBounds)
29
+ let { a: fitScaleX, d: fitScaleY } = fitMatrix
25
30
 
26
- if (matrix.a < 1) {
31
+ if (fitMatrix.a < 1) {
27
32
  worldCanvas = current.getSameCanvas()
28
33
  ui.__renderShape(worldCanvas, options)
29
34
 
30
- scaleX *= matrix.a
31
- scaleY *= matrix.d
35
+ scaleX *= fitScaleX
36
+ scaleY *= fitScaleY
32
37
  }
33
38
 
34
- shapeBounds = getOuterOf(__world, matrix)
35
- bounds = getByMove(shapeBounds, -matrix.e, -matrix.f)
36
-
37
- if (options.matrix) matrix.multiply(options.matrix)
38
- options = { ...options, matrix }
39
-
40
- } else {
39
+ shapeBounds = getOuterOf(nowWorld, fitMatrix)
40
+ bounds = getByMove(shapeBounds, -fitMatrix.e, -fitMatrix.f)
41
41
 
42
42
  if (options.matrix) {
43
- scaleX *= options.matrix.a
44
- scaleY *= options.matrix.d
45
- bounds = shapeBounds = getOuterOf(__world, options.matrix)
46
- } else {
47
- bounds = shapeBounds = __world
43
+ const { matrix } = options
44
+ fitMatrix.multiply(matrix)
45
+ fitScaleX *= matrix.scaleX
46
+ fitScaleY *= matrix.scaleY
48
47
  }
49
48
 
50
- worldCanvas = canvas
49
+ options = { ...options, matrix: fitMatrix.withScale(fitScaleX, fitScaleY) }
50
+
51
51
  }
52
52
 
53
53
  ui.__renderShape(canvas, options)
54
54
 
55
55
  return {
56
- canvas, matrix, bounds,
56
+ canvas, matrix: fitMatrix, bounds,
57
57
  worldCanvas, shapeBounds, scaleX, scaleY
58
58
  }
59
59
  }
package/src/Stroke.ts CHANGED
@@ -5,14 +5,14 @@ import { IUI, ILeafPaint } from '@leafer-ui/interface'
5
5
  import { strokeText, drawStrokesStyle } from './StrokeText'
6
6
 
7
7
 
8
- export function stroke(ui: IUI, canvas: ILeaferCanvas, stroke: string): void {
8
+ export function stroke(stroke: string, ui: IUI, canvas: ILeaferCanvas): void {
9
9
  const options = ui.__
10
- const { strokeWidth, strokeAlign, __font } = options
11
- if (!strokeWidth) return
10
+ const { __strokeWidth, strokeAlign, __font } = options
11
+ if (!__strokeWidth) return
12
12
 
13
13
  if (__font) {
14
14
 
15
- strokeText(ui, canvas, stroke)
15
+ strokeText(stroke, ui, canvas)
16
16
 
17
17
  } else {
18
18
 
@@ -20,14 +20,14 @@ export function stroke(ui: IUI, canvas: ILeaferCanvas, stroke: string): void {
20
20
 
21
21
  case 'center':
22
22
 
23
- canvas.setStroke(stroke, strokeWidth, options)
23
+ canvas.setStroke(stroke, __strokeWidth, options)
24
24
  canvas.stroke()
25
25
  break
26
26
 
27
27
  case 'inside':
28
28
 
29
29
  canvas.save()
30
- canvas.setStroke(stroke, strokeWidth * 2, options)
30
+ canvas.setStroke(stroke, __strokeWidth * 2, options)
31
31
 
32
32
  options.windingRule ? canvas.clip(options.windingRule) : canvas.clip()
33
33
  canvas.stroke()
@@ -37,8 +37,8 @@ export function stroke(ui: IUI, canvas: ILeaferCanvas, stroke: string): void {
37
37
  break
38
38
 
39
39
  case 'outside':
40
- const out = canvas.getSameCanvas(true)
41
- out.setStroke(stroke, strokeWidth * 2, ui.__)
40
+ const out = canvas.getSameCanvas(true, true)
41
+ out.setStroke(stroke, __strokeWidth * 2, options)
42
42
 
43
43
  ui.__drawRenderPath(out)
44
44
 
@@ -47,9 +47,13 @@ export function stroke(ui: IUI, canvas: ILeaferCanvas, stroke: string): void {
47
47
  options.windingRule ? out.clip(options.windingRule) : out.clip()
48
48
  out.clearWorld(ui.__layout.renderBounds)
49
49
 
50
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds)
51
- out.recycle()
50
+ if (ui.__worldFlipped) {
51
+ canvas.copyWorldByReset(out, ui.__nowWorld)
52
+ } else {
53
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds)
54
+ }
52
55
 
56
+ out.recycle(ui.__nowWorld)
53
57
  break
54
58
  }
55
59
 
@@ -57,48 +61,53 @@ export function stroke(ui: IUI, canvas: ILeaferCanvas, stroke: string): void {
57
61
  }
58
62
 
59
63
 
60
- export function strokes(ui: IUI, canvas: ILeaferCanvas, strokes: ILeafPaint[]): void {
64
+ export function strokes(strokes: ILeafPaint[], ui: IUI, canvas: ILeaferCanvas): void {
61
65
  const options = ui.__
62
- const { strokeWidth, strokeAlign, __font } = options
63
- if (!strokeWidth) return
66
+ const { __strokeWidth, strokeAlign, __font } = options
67
+ if (!__strokeWidth) return
64
68
 
65
69
  if (__font) {
66
70
 
67
- strokeText(ui, canvas, strokes)
71
+ strokeText(strokes, ui, canvas)
68
72
 
69
73
  } else {
70
74
 
71
75
  switch (strokeAlign) {
72
76
 
73
77
  case 'center':
74
- canvas.setStroke(undefined, strokeWidth, options)
75
- drawStrokesStyle(ui, strokes, canvas)
78
+ canvas.setStroke(undefined, __strokeWidth, options)
79
+ drawStrokesStyle(strokes, false, ui, canvas)
76
80
  break
77
81
 
78
82
  case 'inside':
79
83
  canvas.save()
80
- canvas.setStroke(undefined, strokeWidth * 2, options)
84
+ canvas.setStroke(undefined, __strokeWidth * 2, options)
81
85
  options.windingRule ? canvas.clip(options.windingRule) : canvas.clip()
82
86
 
83
- drawStrokesStyle(ui, strokes, canvas)
87
+ drawStrokesStyle(strokes, false, ui, canvas)
84
88
 
85
89
  canvas.restore()
86
90
  break
87
91
 
88
92
  case 'outside':
89
93
  const { renderBounds } = ui.__layout
90
- const out = canvas.getSameCanvas(true)
94
+ const out = canvas.getSameCanvas(true, true)
91
95
  ui.__drawRenderPath(out)
92
96
 
93
- out.setStroke(undefined, strokeWidth * 2, ui.__)
97
+ out.setStroke(undefined, __strokeWidth * 2, options)
94
98
 
95
- drawStrokesStyle(ui, strokes, out)
99
+ drawStrokesStyle(strokes, false, ui, out)
96
100
 
97
101
  options.windingRule ? out.clip(options.windingRule) : out.clip()
98
102
  out.clearWorld(renderBounds)
99
103
 
100
- canvas.copyWorldToInner(out, ui.__world, renderBounds)
101
- out.recycle()
104
+ if (ui.__worldFlipped) {
105
+ canvas.copyWorldByReset(out, ui.__nowWorld)
106
+ } else {
107
+ canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds)
108
+ }
109
+
110
+ out.recycle(ui.__nowWorld)
102
111
  break
103
112
  }
104
113
 
package/src/StrokeText.ts CHANGED
@@ -1,43 +1,48 @@
1
1
  import { ILeaferCanvas } from '@leafer/interface'
2
2
 
3
3
  import { IUI, ITextRowData, ILeafPaint, IStrokeAlign, ILeafStrokePaint } from '@leafer-ui/interface'
4
+ import { PaintImage } from "@leafer-ui/draw"
4
5
 
5
6
  import { fillText } from './FillText'
6
- import { checkImage } from './paint/image'
7
7
 
8
8
 
9
- export function strokeText(ui: IUI, canvas: ILeaferCanvas, stroke: string | ILeafPaint[]): void {
9
+ export function strokeText(stroke: string | ILeafPaint[], ui: IUI, canvas: ILeaferCanvas): void {
10
10
  const { strokeAlign } = ui.__
11
11
  const isStrokes = typeof stroke !== 'string'
12
12
  switch (strokeAlign) {
13
13
  case 'center':
14
14
  canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__)
15
- isStrokes ? drawStrokesStyle(ui, stroke as ILeafPaint[], canvas, true) : drawTextStroke(ui, canvas)
15
+ isStrokes ? drawStrokesStyle(stroke as ILeafPaint[], true, ui, canvas) : drawTextStroke(ui, canvas)
16
16
  break
17
17
  case 'inside':
18
- drawAlignStroke(ui, canvas, stroke, 'inside', isStrokes)
18
+ drawAlignStroke('inside', stroke, isStrokes, ui, canvas)
19
19
  break
20
20
  case 'outside':
21
- drawAlignStroke(ui, canvas, stroke, 'outside', isStrokes)
21
+ drawAlignStroke('outside', stroke, isStrokes, ui, canvas)
22
22
  break
23
23
  }
24
24
  }
25
25
 
26
- function drawAlignStroke(ui: IUI, canvas: ILeaferCanvas, stroke: string | ILeafPaint[], align: IStrokeAlign, isStrokes?: boolean): void {
27
- const { strokeWidth, __font } = ui.__
26
+ function drawAlignStroke(align: IStrokeAlign, stroke: string | ILeafPaint[], isStrokes: boolean, ui: IUI, canvas: ILeaferCanvas): void {
27
+ const { __strokeWidth, __font } = ui.__
28
28
 
29
- const out = canvas.getSameCanvas(true)
30
- out.setStroke(isStrokes ? undefined : stroke, strokeWidth * 2, ui.__)
29
+ const out = canvas.getSameCanvas(true, true)
30
+ out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__)
31
31
 
32
32
  out.font = __font
33
- isStrokes ? drawStrokesStyle(ui, stroke as ILeafPaint[], out, true) : drawTextStroke(ui, out)
33
+ isStrokes ? drawStrokesStyle(stroke as ILeafPaint[], true, ui, out) : drawTextStroke(ui, out)
34
34
 
35
35
  out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in'
36
36
  fillText(ui, out)
37
37
  out.blendMode = 'normal'
38
38
 
39
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds)
40
- out.recycle()
39
+ if (ui.__worldFlipped) {
40
+ canvas.copyWorldByReset(out, ui.__nowWorld)
41
+ } else {
42
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds)
43
+ }
44
+
45
+ out.recycle(ui.__nowWorld)
41
46
  }
42
47
 
43
48
  export function drawTextStroke(ui: IUI, canvas: ILeaferCanvas): void {
@@ -61,12 +66,12 @@ export function drawTextStroke(ui: IUI, canvas: ILeaferCanvas): void {
61
66
 
62
67
  }
63
68
 
64
- export function drawStrokesStyle(ui: IUI, strokes: ILeafStrokePaint[], canvas: ILeaferCanvas, isText?: boolean): void {
69
+ export function drawStrokesStyle(strokes: ILeafStrokePaint[], isText: boolean, ui: IUI, canvas: ILeaferCanvas): void {
65
70
  let item: ILeafStrokePaint
66
71
  for (let i = 0, len = strokes.length; i < len; i++) {
67
72
  item = strokes[i]
68
73
 
69
- if (item.image && checkImage(ui, canvas, item, false)) continue
74
+ if (item.image && PaintImage.checkImage(ui, canvas, item, false)) continue
70
75
 
71
76
  if (item.style) {
72
77
 
package/src/index.ts CHANGED
@@ -1,7 +1,21 @@
1
- export { fill, fills } from './Fill'
2
- export { fillText } from './FillText'
3
- export { stroke, strokes } from './Stroke'
4
- export { strokeText, drawTextStroke } from './StrokeText'
5
- export { shape } from './Shape'
6
- export { compute } from './Compute'
7
- export { recycleImage } from './paint/image'
1
+ import { IPaintModule } from '@leafer-ui/interface'
2
+
3
+ import { fill, fills } from './Fill'
4
+ import { fillText } from './FillText'
5
+ import { stroke, strokes } from './Stroke'
6
+ import { strokeText, drawTextStroke } from './StrokeText'
7
+ import { shape } from './Shape'
8
+ import { compute } from './Compute'
9
+
10
+
11
+ export const PaintModule: IPaintModule = {
12
+ compute,
13
+ fill,
14
+ fills,
15
+ fillText,
16
+ stroke,
17
+ strokes,
18
+ strokeText,
19
+ drawTextStroke,
20
+ shape
21
+ }
package/types/index.d.ts CHANGED
@@ -1,21 +1,5 @@
1
- import { ILeaferCanvas, IRenderOptions, IBooleanMap } from '@leafer/interface';
2
- import { IUI, ILeafPaint, ICachedShape, IUIData } from '@leafer-ui/interface';
1
+ import { IPaintModule } from '@leafer-ui/interface';
3
2
 
4
- declare function fill(ui: IUI, canvas: ILeaferCanvas, fill: string): void;
5
- declare function fills(ui: IUI, canvas: ILeaferCanvas, fills: ILeafPaint[]): void;
3
+ declare const PaintModule: IPaintModule;
6
4
 
7
- declare function fillText(ui: IUI, canvas: ILeaferCanvas): void;
8
-
9
- declare function stroke(ui: IUI, canvas: ILeaferCanvas, stroke: string): void;
10
- declare function strokes(ui: IUI, canvas: ILeaferCanvas, strokes: ILeafPaint[]): void;
11
-
12
- declare function strokeText(ui: IUI, canvas: ILeaferCanvas, stroke: string | ILeafPaint[]): void;
13
- declare function drawTextStroke(ui: IUI, canvas: ILeaferCanvas): void;
14
-
15
- declare function shape(ui: IUI, current: ILeaferCanvas, options: IRenderOptions): ICachedShape;
16
-
17
- declare function compute(ui: IUI, attrName: string): void;
18
-
19
- declare function recycleImage(data: IUIData, attrName: string): IBooleanMap;
20
-
21
- export { compute, drawTextStroke, fill, fillText, fills, recycleImage, shape, stroke, strokeText, strokes };
5
+ export { PaintModule };
@@ -1,48 +0,0 @@
1
- import { IMatrixData, IPointData, IBoundsData } from '@leafer/interface'
2
- import { Platform, PointHelper, MatrixHelper } from '@leafer/core'
3
-
4
- import { IGradientPaint, ILeafPaint } from '@leafer-ui/interface'
5
-
6
- import { applyStops } from './linear'
7
-
8
-
9
- const { set, getAngle, getDistance } = PointHelper
10
- const { get, rotateOfOuter, scaleOfOuter } = MatrixHelper
11
-
12
- const defaultFrom = { x: 0.5, y: 0.5 }
13
- const defaultTo = { x: 0.5, y: 1 }
14
-
15
- const realFrom = {} as IPointData
16
- const realTo = {} as IPointData
17
-
18
- export function conicGradient(paint: IGradientPaint, box: IBoundsData): ILeafPaint {
19
-
20
- let { from, to, type, opacity, blendMode, stretch } = paint
21
-
22
- from || (from = defaultFrom)
23
- to || (to = defaultTo)
24
-
25
- const { x, y, width, height } = box
26
-
27
- set(realFrom, x + from.x * width, y + from.y * height)
28
- set(realTo, x + to.x * width, y + to.y * height)
29
-
30
- const transform: IMatrixData = get()
31
- const angle = getAngle(realFrom, realTo)
32
-
33
- if (Platform.conicGradientRotate90) {
34
- scaleOfOuter(transform, realFrom, width / height * (stretch || 1), 1)
35
- rotateOfOuter(transform, realFrom, angle + 90)
36
- } else {
37
- scaleOfOuter(transform, realFrom, 1, width / height * (stretch || 1))
38
- rotateOfOuter(transform, realFrom, angle)
39
- }
40
-
41
- const style = Platform.conicGradientSupport ? Platform.canvas.createConicGradient(0, realFrom.x, realFrom.y) : Platform.canvas.createRadialGradient(realFrom.x, realFrom.y, 0, realFrom.x, realFrom.y, getDistance(realFrom, realTo))
42
- applyStops(style, paint.stops, opacity)
43
-
44
- const data: ILeafPaint = { type, style, transform }
45
- if (blendMode) data.blendMode = blendMode
46
- return data
47
-
48
- }
@@ -1,49 +0,0 @@
1
-
2
- import { ILeaferCanvas } from '@leafer/interface'
3
- import { ImageManager } from '@leafer/core'
4
-
5
- import { IUI, ILeafPaint } from '@leafer-ui/interface'
6
-
7
- import { createPattern } from './pattern'
8
-
9
-
10
- export function checkImage(ui: IUI, canvas: ILeaferCanvas, paint: ILeafPaint, allowPaint?: boolean): boolean {
11
- const { scaleX, scaleY } = ui.__world
12
-
13
- if (!paint.data || paint.patternId === scaleX + '-' + scaleY) {
14
- return false
15
- } else {
16
-
17
- if (allowPaint) {
18
- if (paint.image.isSVG && paint.data.mode !== 'repeat') {
19
- let { width, height } = paint.data
20
- width *= scaleX * canvas.pixelRatio
21
- height *= scaleY * canvas.pixelRatio
22
- allowPaint = width > 4096 || height > 4096
23
- } else {
24
- allowPaint = false
25
- }
26
- }
27
-
28
- if (allowPaint) {
29
- canvas.save()
30
- canvas.clip()
31
- const { data } = paint
32
- if (paint.blendMode) canvas.blendMode = paint.blendMode
33
- if (data.opacity) canvas.opacity *= data.opacity
34
- if (data.transform) canvas.transform(data.transform)
35
- canvas.drawImage(paint.image.view as any, 0, 0, data.width, data.height)
36
- canvas.restore()
37
- return true
38
- } else {
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
- }
46
- return false
47
- }
48
- }
49
- }
@@ -1,43 +0,0 @@
1
- import { IBoundsData, ILeaferImage } from '@leafer/interface'
2
- import { MatrixHelper } from '@leafer/core'
3
-
4
- import { IImagePaint, ILeafPaint, ILeafPaintPatternData } from '@leafer-ui/interface'
5
-
6
- import { clipMode, fillOrFitMode, repeatMode } from './mode'
7
-
8
-
9
- const { get, translate } = MatrixHelper
10
-
11
- export function createData(leafPaint: ILeafPaint, image: ILeaferImage, paint: IImagePaint, box: IBoundsData): void {
12
- let { width, height } = image
13
-
14
- const { opacity, mode, offset, scale, rotation, blendMode } = paint
15
- const sameBox = box.width === width && box.height === height
16
- if (blendMode) leafPaint.blendMode = blendMode
17
-
18
- const data: ILeafPaintPatternData = leafPaint.data = { mode }
19
-
20
- switch (mode) {
21
- case 'strench':
22
- if (!sameBox) width = box.width, height = box.height
23
- if (box.x || box.y) {
24
- data.transform = get()
25
- translate(data.transform, box.x, box.y)
26
- }
27
- break
28
- case 'clip':
29
- if (offset || scale || rotation) clipMode(data, box, offset, scale, rotation)
30
- break
31
- case 'repeat':
32
- if (!sameBox || scale || rotation) repeatMode(data, box, width, height, scale as number, rotation)
33
- break
34
- case 'fit':
35
- case 'cover':
36
- default:
37
- if (!sameBox || rotation) fillOrFitMode(data, mode, box, width, height, rotation)
38
- }
39
-
40
- data.width = width
41
- data.height = height
42
- if (opacity) data.opacity = opacity
43
- }
@@ -1,77 +0,0 @@
1
- import { IBoundsData, IImageEvent, ISizeData } from '@leafer/interface'
2
- import { ImageEvent, ImageManager } from '@leafer/core'
3
-
4
- import { IUI, IImagePaint, ILeafPaint } from '@leafer-ui/interface'
5
-
6
- import { createData } from './data'
7
-
8
-
9
- export function image(ui: IUI, attrName: string, attrValue: IImagePaint, box: IBoundsData, firstUse: boolean): ILeafPaint {
10
- const leafPaint: ILeafPaint = { type: attrValue.type }
11
- const image = leafPaint.image = ImageManager.get(attrValue)
12
-
13
- const event: IImageEvent = (firstUse || image.loading) && { target: ui, image, attrName, attrValue }
14
-
15
- if (image.ready) {
16
-
17
- if (hasNaturalSize(ui, attrName, image)) createData(leafPaint, image, attrValue, box)
18
-
19
- if (firstUse) {
20
- emit(ImageEvent.LOAD, event)
21
- emit(ImageEvent.LOADED, event)
22
- }
23
-
24
- } else if (image.error) {
25
-
26
- if (firstUse) {
27
- ui.forceUpdate('surface')
28
- event.error = image.error
29
- emit(ImageEvent.ERROR, event)
30
- }
31
-
32
- } else {
33
-
34
- if (firstUse) emit(ImageEvent.LOAD, event)
35
-
36
- leafPaint.loadId = image.load(
37
- () => {
38
- if (!ui.destroyed) {
39
-
40
- if (hasNaturalSize(ui, attrName, image)) {
41
- createData(leafPaint, image, attrValue, box)
42
- ui.forceUpdate('surface')
43
- }
44
-
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
-
55
- }
56
-
57
- return leafPaint
58
- }
59
-
60
-
61
- function hasNaturalSize(ui: IUI, attrName: string, image: ISizeData): boolean {
62
- if (attrName === 'fill' && !ui.__.__naturalWidth) {
63
- const { __: d } = ui
64
- d.__naturalWidth = image.width
65
- d.__naturalHeight = image.height
66
- if (!d.__getInput('width') || !d.__getInput('height')) {
67
- ui.forceUpdate('width')
68
- return false
69
- }
70
- }
71
- return true
72
- }
73
-
74
- function emit(type: string, data: IImageEvent): void {
75
- if (data.target.hasEvent(type)) data.target.emitEvent(new ImageEvent(type, data))
76
- }
77
-
@@ -1,4 +0,0 @@
1
- export { image } from './image'
2
- export { checkImage } from './check'
3
- export { recycleImage } from './recycle'
4
-
@@ -1,62 +0,0 @@
1
- import { IBoundsData } from '@leafer/interface'
2
- import { MatrixHelper } from '@leafer/core'
3
-
4
- import { IMatrixData, IImagePaintMode, IPointData, ILeafPaintPatternData } from '@leafer-ui/interface'
5
-
6
-
7
- const { get, rotateOfOuter, translate, scaleOfOuter, scale: scaleHelper, rotate } = MatrixHelper
8
-
9
- export function fillOrFitMode(data: ILeafPaintPatternData, mode: IImagePaintMode, box: IBoundsData, width: number, height: number, rotation: number): void {
10
- const transform: IMatrixData = get()
11
- const swap = rotation && rotation !== 180
12
- const sw = box.width / (swap ? height : width)
13
- const sh = box.height / (swap ? width : height)
14
- const scale = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh)
15
- const x = box.x + (box.width - width * scale) / 2
16
- const y = box.y + (box.height - height * scale) / 2
17
- translate(transform, x, y)
18
- scaleHelper(transform, scale)
19
- if (rotation) rotateOfOuter(transform, { x: box.x + box.width / 2, y: box.y + box.height / 2 }, rotation)
20
- data.scaleX = data.scaleY = scale
21
- data.transform = transform
22
- }
23
-
24
-
25
- export function clipMode(data: ILeafPaintPatternData, box: IBoundsData, offset: IPointData, scale: number | IPointData, rotation: number): void {
26
- const transform: IMatrixData = get()
27
- translate(transform, box.x, box.y)
28
- if (offset) translate(transform, offset.x, offset.y)
29
- if (scale) {
30
- typeof scale === 'number' ? scaleHelper(transform, scale) : scaleHelper(transform, scale.x, scale.y)
31
- data.scaleX = transform.a
32
- data.scaleY = transform.d
33
- }
34
- if (rotation) rotate(transform, rotation)
35
- data.transform = transform
36
- }
37
-
38
-
39
- export function repeatMode(data: ILeafPaintPatternData, box: IBoundsData, width: number, height: number, scale: number, rotation: number): void {
40
- const transform = get()
41
-
42
- if (rotation) {
43
- rotate(transform, rotation)
44
- switch (rotation) {
45
- case 90:
46
- translate(transform, height, 0)
47
- break
48
- case 180:
49
- translate(transform, width, height)
50
- break
51
- case 270:
52
- translate(transform, 0, width)
53
- break
54
- }
55
- }
56
- translate(transform, box.x, box.y)
57
- if (scale) {
58
- scaleOfOuter(transform, box, scale)
59
- data.scaleX = data.scaleY = scale
60
- }
61
- data.transform = transform
62
- }
@@ -1,82 +0,0 @@
1
- import { Platform, MatrixHelper } from '@leafer/core'
2
-
3
- import { IUI, ILeafPaint, IMatrixData } from '@leafer-ui/interface'
4
-
5
-
6
- const { get, scale: scaleHelper, copy } = MatrixHelper
7
-
8
- export function createPattern(ui: IUI, paint: ILeafPaint, pixelRatio: number): boolean {
9
-
10
- let { scaleX, scaleY } = ui.__world
11
-
12
- const id = scaleX + '-' + scaleY
13
-
14
- if (paint.patternId !== id && !ui.destroyed) {
15
-
16
- paint.patternId = id
17
-
18
- scaleX = Math.abs(scaleX) // maybe -1
19
- scaleY = Math.abs(scaleY)
20
-
21
- const { image, data } = paint
22
- const maxWidth = image.isSVG ? 4096 : Math.min(image.width, 4096)
23
- const maxHeight = image.isSVG ? 4096 : Math.min(image.height, 4096)
24
- let scale: number, matrix: IMatrixData, { width, height, scaleX: sx, scaleY: sy, opacity, transform, mode } = data
25
-
26
- if (sx) {
27
- matrix = get()
28
- copy(matrix, transform)
29
- scaleHelper(matrix, 1 / sx, 1 / sy)
30
- scaleX *= sx
31
- scaleY *= sy
32
- }
33
-
34
- scaleX *= pixelRatio
35
- scaleY *= pixelRatio
36
- width *= scaleX
37
- height *= scaleY
38
-
39
- if (width > maxWidth || height > maxHeight) {
40
- scale = Math.max(width / maxWidth, height / maxHeight)
41
- }
42
-
43
- if (scale) {
44
- scaleX /= scale
45
- scaleY /= scale
46
- width /= scale
47
- height /= scale
48
- }
49
-
50
- if (sx) {
51
- scaleX /= sx
52
- scaleY /= sy
53
- }
54
-
55
- if (transform || scaleX !== 1 || scaleY !== 1) {
56
- if (!matrix) {
57
- matrix = get()
58
- if (transform) copy(matrix, transform)
59
- }
60
- scaleHelper(matrix, 1 / scaleX, 1 / scaleY)
61
- }
62
-
63
- const style = Platform.canvas.createPattern(image.getCanvas(width < 1 ? 1 : width, height < 1 ? 1 : height, opacity) as any, mode === 'repeat' ? 'repeat' : (Platform.origin.noRepeat || 'no-repeat'))
64
-
65
- try {
66
- if (paint.transform) paint.transform = null
67
- if (matrix) style.setTransform ? style.setTransform(matrix) : paint.transform = matrix
68
- } catch {
69
- paint.transform = matrix
70
- }
71
-
72
- paint.style = style
73
-
74
- return true
75
-
76
- } else {
77
-
78
- return false
79
-
80
- }
81
-
82
- }
@@ -1,41 +0,0 @@
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
- }
@@ -1,33 +0,0 @@
1
- import { IObject, IBoundsData } from '@leafer/interface'
2
- import { Platform } from '@leafer/core'
3
-
4
- import { IGradientPaint, ILeafPaint, IColorStop } from '@leafer-ui/interface'
5
- import { ColorConvert } from '@leafer-ui/core'
6
-
7
-
8
- const defaultFrom = { x: 0.5, y: 0 }
9
- const defaultTo = { x: 0.5, y: 1 }
10
-
11
- export function linearGradient(paint: IGradientPaint, box: IBoundsData): ILeafPaint {
12
-
13
- let { from, to, type, blendMode, opacity } = paint
14
-
15
- from || (from = defaultFrom)
16
- to || (to = defaultTo)
17
-
18
- const style = Platform.canvas.createLinearGradient(box.x + from.x * box.width, box.y + from.y * box.height, box.x + to.x * box.width, box.y + to.y * box.height)
19
- applyStops(style, paint.stops, opacity)
20
-
21
- const data: ILeafPaint = { type, style }
22
- if (blendMode) data.blendMode = blendMode
23
- return data
24
-
25
- }
26
-
27
- export function applyStops(gradient: IObject, stops: IColorStop[], opacity: number): void {
28
- let stop: IColorStop
29
- for (let i = 0, len = stops.length; i < len; i++) {
30
- stop = stops[i]
31
- gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity))
32
- }
33
- }
@@ -1,44 +0,0 @@
1
- import { IBoundsData } from '@leafer/interface'
2
- import { Platform, PointHelper, MatrixHelper } from '@leafer/core'
3
-
4
- import { IGradientPaint, ILeafPaint, IMatrixData, IPointData } from '@leafer-ui/interface'
5
-
6
- import { applyStops } from './linear'
7
-
8
-
9
- const { set, getAngle, getDistance } = PointHelper
10
- const { get, rotateOfOuter, scaleOfOuter } = MatrixHelper
11
-
12
- const defaultFrom = { x: 0.5, y: 0.5 }
13
- const defaultTo = { x: 0.5, y: 1 }
14
-
15
- const realFrom = {} as IPointData
16
- const realTo = {} as IPointData
17
-
18
- export function radialGradient(paint: IGradientPaint, box: IBoundsData): ILeafPaint {
19
-
20
- let { from, to, type, opacity, blendMode, stretch } = paint
21
-
22
- from || (from = defaultFrom)
23
- to || (to = defaultTo)
24
-
25
- const { x, y, width, height } = box
26
- set(realFrom, x + from.x * width, y + from.y * height)
27
- set(realTo, x + to.x * width, y + to.y * height)
28
-
29
- let transform: IMatrixData
30
-
31
- if (width !== height || stretch) {
32
- transform = get()
33
- scaleOfOuter(transform, realFrom, width / height * (stretch || 1), 1)
34
- rotateOfOuter(transform, realFrom, getAngle(realFrom, realTo) + 90)
35
- }
36
-
37
- const style = Platform.canvas.createRadialGradient(realFrom.x, realFrom.y, 0, realFrom.x, realFrom.y, getDistance(realFrom, realTo))
38
- applyStops(style, paint.stops, opacity)
39
-
40
- const data: ILeafPaint = { type, style, transform }
41
- if (blendMode) data.blendMode = blendMode
42
- return data
43
-
44
- }