@leafer-ui/paint 1.0.0-rc.8 → 1.0.0

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.8",
3
+ "version": "1.0.0",
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.8"
25
+ "@leafer/core": "1.0.0",
26
+ "@leafer-ui/draw": "1.0.0"
26
27
  },
27
28
  "devDependencies": {
28
- "@leafer/interface": "1.0.0-rc.8",
29
- "@leafer-ui/interface": "1.0.0-rc.8"
29
+ "@leafer/interface": "1.0.0",
30
+ "@leafer-ui/interface": "1.0.0"
30
31
  }
31
32
  }
package/src/Compute.ts CHANGED
@@ -1,50 +1,35 @@
1
- import { IUI, IPaint, ILeafPaint, IRGB, IBooleanMap, IImagePaint, IObject } from '@leafer-ui/interface'
2
- import { ColorConvert, ImageManager } 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(attrName: 'fill' | 'stroke', ui: IUI): void {
14
- const value: ILeafPaint[] = []
15
- const data = ui.__
16
-
17
- let item: ILeafPaint
18
- let paints = data.__input[attrName] as IPaint[]
7
+ export function compute(attrName: IPaintAttr, ui: IUI): void {
8
+ const data = ui.__, leafPaints: ILeafPaint[] = []
19
9
 
10
+ let paints: IPaint[] = data.__input[attrName], hasOpacityPixel: boolean
20
11
  if (!(paints instanceof Array)) paints = [paints]
21
12
 
22
- recycleMap = recycleImage(attrName, data)
13
+ recycleMap = PaintImage.recycleImage(attrName, data)
23
14
 
24
- for (let i = 0, len = paints.length; i < len; i++) {
15
+ for (let i = 0, len = paints.length, item: ILeafPaint; i < len; i++) {
25
16
  item = getLeafPaint(attrName, paints[i], ui)
26
- if (item) value.push(item)
17
+ if (item) leafPaints.push(item)
27
18
  }
28
19
 
29
- (data as IObject)['_' + attrName] = value.length ? value : undefined
20
+ (data as IObject)['_' + attrName] = leafPaints.length ? leafPaints : undefined
30
21
 
31
- // check png / svg / webp
32
-
33
- let isPixel
34
- if (paints.length === 1) {
35
- const paint = paints[0] as IImagePaint
36
- if (paint.type === 'image') isPixel = ImageManager.isPixel(paint)
37
- }
22
+ if (leafPaints.length && leafPaints[0].image) hasOpacityPixel = leafPaints[0].image.hasOpacityPixel
38
23
 
39
24
  if (attrName === 'fill') {
40
- data.__pixelFill = isPixel
25
+ data.__pixelFill = hasOpacityPixel
41
26
  } else {
42
- data.__pixelStroke = isPixel
27
+ data.__pixelStroke = hasOpacityPixel
43
28
  }
44
29
  }
45
30
 
46
31
 
47
- function getLeafPaint(attrName: string, paint: IPaint, ui: IUI,): ILeafPaint {
32
+ function getLeafPaint(attrName: string, paint: IPaint, ui: IUI): ILeafPaint {
48
33
  if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0) return undefined
49
34
  const { boxBounds } = ui.__layout
50
35
 
@@ -53,14 +38,14 @@ function getLeafPaint(attrName: string, paint: IPaint, ui: IUI,): ILeafPaint {
53
38
  let { type, blendMode, color, opacity } = paint
54
39
  return { type, blendMode, style: ColorConvert.string(color, opacity) }
55
40
  case 'image':
56
- return image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url])
41
+ return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url])
57
42
  case 'linear':
58
- return linearGradient(paint, boxBounds)
43
+ return PaintGradient.linearGradient(paint, boxBounds)
59
44
  case 'radial':
60
- return radialGradient(paint, boxBounds)
45
+ return PaintGradient.radialGradient(paint, boxBounds)
61
46
  case 'angular':
62
- return conicGradient(paint, boxBounds)
47
+ return PaintGradient.conicGradient(paint, boxBounds)
63
48
  default:
64
- return (paint as IRGB).r ? { type: 'solid', style: ColorConvert.string(paint) } : undefined
49
+ return (paint as IRGB).r !== undefined ? { type: 'solid', style: ColorConvert.string(paint) } : undefined
65
50
  }
66
51
  }
package/src/Fill.ts CHANGED
@@ -1,8 +1,8 @@
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
 
@@ -18,7 +18,7 @@ export function fills(fills: ILeafPaint[], ui: IUI, canvas: ILeaferCanvas): void
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, scaleX === scaleY ? spread * scaleX : [spread * scaleY, spread * scaleX]) : 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
@@ -1,18 +1,18 @@
1
- import { ILeaferCanvas, IRenderOptions } from '@leafer/interface'
1
+ import { ILeaferCanvas } from '@leafer/interface'
2
2
 
3
3
  import { IUI, ILeafPaint } from '@leafer-ui/interface'
4
4
 
5
5
  import { strokeText, drawStrokesStyle } from './StrokeText'
6
6
 
7
7
 
8
- export function stroke(stroke: string, ui: IUI, canvas: ILeaferCanvas, renderOptions: IRenderOptions): 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(stroke, ui, canvas, renderOptions)
15
+ strokeText(stroke, ui, canvas)
16
16
 
17
17
  } else {
18
18
 
@@ -20,14 +20,14 @@ export function stroke(stroke: string, ui: IUI, canvas: ILeaferCanvas, renderOpt
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(stroke: string, ui: IUI, canvas: ILeaferCanvas, renderOpt
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,14 +47,13 @@ export function stroke(stroke: string, ui: IUI, canvas: ILeaferCanvas, renderOpt
47
47
  options.windingRule ? out.clip(options.windingRule) : out.clip()
48
48
  out.clearWorld(ui.__layout.renderBounds)
49
49
 
50
- if (ui.__worldFlipped || renderOptions.matrix) {
51
- canvas.copyWorldByReset(out)
50
+ if (ui.__worldFlipped) {
51
+ canvas.copyWorldByReset(out, ui.__nowWorld)
52
52
  } else {
53
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds)
53
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds)
54
54
  }
55
55
 
56
- out.recycle()
57
-
56
+ out.recycle(ui.__nowWorld)
58
57
  break
59
58
  }
60
59
 
@@ -62,27 +61,27 @@ export function stroke(stroke: string, ui: IUI, canvas: ILeaferCanvas, renderOpt
62
61
  }
63
62
 
64
63
 
65
- export function strokes(strokes: ILeafPaint[], ui: IUI, canvas: ILeaferCanvas, renderOptions: IRenderOptions): void {
64
+ export function strokes(strokes: ILeafPaint[], ui: IUI, canvas: ILeaferCanvas): void {
66
65
  const options = ui.__
67
- const { strokeWidth, strokeAlign, __font } = options
68
- if (!strokeWidth) return
66
+ const { __strokeWidth, strokeAlign, __font } = options
67
+ if (!__strokeWidth) return
69
68
 
70
69
  if (__font) {
71
70
 
72
- strokeText(strokes, ui, canvas, renderOptions)
71
+ strokeText(strokes, ui, canvas)
73
72
 
74
73
  } else {
75
74
 
76
75
  switch (strokeAlign) {
77
76
 
78
77
  case 'center':
79
- canvas.setStroke(undefined, strokeWidth, options)
78
+ canvas.setStroke(undefined, __strokeWidth, options)
80
79
  drawStrokesStyle(strokes, false, ui, canvas)
81
80
  break
82
81
 
83
82
  case 'inside':
84
83
  canvas.save()
85
- canvas.setStroke(undefined, strokeWidth * 2, options)
84
+ canvas.setStroke(undefined, __strokeWidth * 2, options)
86
85
  options.windingRule ? canvas.clip(options.windingRule) : canvas.clip()
87
86
 
88
87
  drawStrokesStyle(strokes, false, ui, canvas)
@@ -92,23 +91,23 @@ export function strokes(strokes: ILeafPaint[], ui: IUI, canvas: ILeaferCanvas, r
92
91
 
93
92
  case 'outside':
94
93
  const { renderBounds } = ui.__layout
95
- const out = canvas.getSameCanvas(true)
94
+ const out = canvas.getSameCanvas(true, true)
96
95
  ui.__drawRenderPath(out)
97
96
 
98
- out.setStroke(undefined, strokeWidth * 2, ui.__)
97
+ out.setStroke(undefined, __strokeWidth * 2, options)
99
98
 
100
99
  drawStrokesStyle(strokes, false, ui, out)
101
100
 
102
101
  options.windingRule ? out.clip(options.windingRule) : out.clip()
103
102
  out.clearWorld(renderBounds)
104
103
 
105
- if (ui.__worldFlipped || renderOptions.matrix) {
106
- canvas.copyWorldByReset(out)
104
+ if (ui.__worldFlipped) {
105
+ canvas.copyWorldByReset(out, ui.__nowWorld)
107
106
  } else {
108
- canvas.copyWorldToInner(out, ui.__world, renderBounds)
107
+ canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds)
109
108
  }
110
109
 
111
- out.recycle()
110
+ out.recycle(ui.__nowWorld)
112
111
  break
113
112
  }
114
113
 
package/src/StrokeText.ts CHANGED
@@ -1,12 +1,12 @@
1
- import { ILeaferCanvas, IRenderOptions } from '@leafer/interface'
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(stroke: string | ILeafPaint[], ui: IUI, canvas: ILeaferCanvas, renderOptions?: IRenderOptions): 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) {
@@ -15,19 +15,19 @@ export function strokeText(stroke: string | ILeafPaint[], ui: IUI, canvas: ILeaf
15
15
  isStrokes ? drawStrokesStyle(stroke as ILeafPaint[], true, ui, canvas) : drawTextStroke(ui, canvas)
16
16
  break
17
17
  case 'inside':
18
- drawAlignStroke('inside', stroke, isStrokes, ui, canvas, renderOptions)
18
+ drawAlignStroke('inside', stroke, isStrokes, ui, canvas)
19
19
  break
20
20
  case 'outside':
21
- drawAlignStroke('outside', stroke, isStrokes, ui, canvas, renderOptions)
21
+ drawAlignStroke('outside', stroke, isStrokes, ui, canvas)
22
22
  break
23
23
  }
24
24
  }
25
25
 
26
- function drawAlignStroke(align: IStrokeAlign, stroke: string | ILeafPaint[], isStrokes: boolean, ui: IUI, canvas: ILeaferCanvas, renderOptions: IRenderOptions): 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
33
  isStrokes ? drawStrokesStyle(stroke as ILeafPaint[], true, ui, out) : drawTextStroke(ui, out)
@@ -36,13 +36,13 @@ function drawAlignStroke(align: IStrokeAlign, stroke: string | ILeafPaint[], isS
36
36
  fillText(ui, out)
37
37
  out.blendMode = 'normal'
38
38
 
39
- if (ui.__worldFlipped || renderOptions.matrix) {
40
- canvas.copyWorldByReset(out)
39
+ if (ui.__worldFlipped) {
40
+ canvas.copyWorldByReset(out, ui.__nowWorld)
41
41
  } else {
42
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds)
42
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds)
43
43
  }
44
44
 
45
- out.recycle()
45
+ out.recycle(ui.__nowWorld)
46
46
  }
47
47
 
48
48
  export function drawTextStroke(ui: IUI, canvas: ILeaferCanvas): void {
@@ -71,7 +71,7 @@ export function drawStrokesStyle(strokes: ILeafStrokePaint[], isText: boolean, u
71
71
  for (let i = 0, len = strokes.length; i < len; i++) {
72
72
  item = strokes[i]
73
73
 
74
- if (item.image && checkImage(ui, canvas, item, false)) continue
74
+ if (item.image && PaintImage.checkImage(ui, canvas, item, false)) continue
75
75
 
76
76
  if (item.style) {
77
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(fill: string, ui: IUI, canvas: ILeaferCanvas): void;
5
- declare function fills(fills: ILeafPaint[], ui: IUI, canvas: ILeaferCanvas): void;
3
+ declare const PaintModule: IPaintModule;
6
4
 
7
- declare function fillText(ui: IUI, canvas: ILeaferCanvas): void;
8
-
9
- declare function stroke(stroke: string, ui: IUI, canvas: ILeaferCanvas, renderOptions: IRenderOptions): void;
10
- declare function strokes(strokes: ILeafPaint[], ui: IUI, canvas: ILeaferCanvas, renderOptions: IRenderOptions): void;
11
-
12
- declare function strokeText(stroke: string | ILeafPaint[], ui: IUI, canvas: ILeaferCanvas, renderOptions?: IRenderOptions): 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(attrName: 'fill' | 'stroke', ui: IUI): void;
18
-
19
- declare function recycleImage(attrName: 'fill' | 'stroke', data: IUIData): 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,60 +0,0 @@
1
-
2
- import { ILeaferCanvas } from '@leafer/interface'
3
- import { ImageManager, Platform } from '@leafer/core'
4
-
5
- import { IUI, ILeafPaint } from '@leafer-ui/interface'
6
- import { Export } from '@leafer-ui/external'
7
-
8
- import { createPattern } from './pattern'
9
-
10
- const { abs } = Math
11
-
12
- export function checkImage(ui: IUI, canvas: ILeaferCanvas, paint: ILeafPaint, allowPaint?: boolean): boolean {
13
- const { scaleX, scaleY } = ui.__world
14
-
15
- if (!paint.data || paint.patternId === scaleX + '-' + scaleY) {
16
- return false
17
- } else {
18
-
19
- const { data } = paint
20
-
21
- if (allowPaint) {
22
- if (!data.repeat) {
23
- let { width, height } = data
24
- width *= abs(scaleX) * canvas.pixelRatio
25
- height *= abs(scaleY) * canvas.pixelRatio
26
- if (data.scaleX) {
27
- width *= data.scaleX
28
- height *= data.scaleY
29
- }
30
- allowPaint = width * height > Platform.image.maxCacheSize
31
- } else {
32
- allowPaint = false
33
- }
34
- }
35
-
36
- if (allowPaint) {
37
- canvas.save()
38
- canvas.clip()
39
- if (paint.blendMode) canvas.blendMode = paint.blendMode
40
- if (data.opacity) canvas.opacity *= data.opacity
41
- if (data.transform) canvas.transform(data.transform)
42
- canvas.drawImage(paint.image.view as any, 0, 0, data.width, data.height)
43
- canvas.restore()
44
- return true
45
- } else {
46
- if (!paint.style || Export.running) {
47
- createPattern(ui, paint, canvas.pixelRatio)
48
- } else {
49
- if (!paint.patternTask) {
50
- paint.patternTask = ImageManager.patternTasker.add(async () => {
51
- paint.patternTask = null
52
- if (canvas.bounds.hit(ui.__world)) createPattern(ui, paint, canvas.pixelRatio)
53
- ui.forceUpdate('surface')
54
- }, 300)
55
- }
56
- }
57
- return false
58
- }
59
- }
60
- }
@@ -1,45 +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, repeat } = 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
- if (!repeat) data.repeat = 'repeat'
34
- break
35
- case 'fit':
36
- case 'cover':
37
- default:
38
- if (!sameBox || rotation) fillOrFitMode(data, mode, box, width, height, rotation)
39
- }
40
-
41
- data.width = width
42
- data.height = height
43
- if (opacity) data.opacity = opacity
44
- if (repeat) data.repeat = typeof repeat === 'string' ? (repeat === 'x' ? 'repeat-x' : 'repeat-y') : 'repeat'
45
- }
@@ -1,81 +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
- if (ui.__proxyData) {
69
- ui.setProxyAttr('width', ui.__.width)
70
- ui.setProxyAttr('height', ui.__.height)
71
- }
72
- return false
73
- }
74
- }
75
- return true
76
- }
77
-
78
- function emit(type: string, data: IImageEvent): void {
79
- if (data.target.hasEvent(type)) data.target.emitEvent(new ImageEvent(type, data))
80
- }
81
-
@@ -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,90 +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, 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
- scaleX = Math.abs(scaleX) // maybe -1
17
- scaleY = Math.abs(scaleY)
18
-
19
- const { image, data } = paint
20
- let imageScale: number, imageMatrix: IMatrixData, { width, height, scaleX: sx, scaleY: sy, opacity, transform, repeat } = data
21
-
22
- if (sx) {
23
- imageMatrix = get()
24
- copy(imageMatrix, transform)
25
- scale(imageMatrix, 1 / sx, 1 / sy)
26
- scaleX *= sx
27
- scaleY *= sy
28
- }
29
-
30
- scaleX *= pixelRatio
31
- scaleY *= pixelRatio
32
- width *= scaleX
33
- height *= scaleY
34
-
35
- const size = width * height
36
-
37
- if (!repeat) {
38
- if (size > Platform.image.maxCacheSize) return false // same as check()
39
- }
40
-
41
- let maxSize = Platform.image.maxPatternSize
42
-
43
- if (!image.isSVG) {
44
- const imageSize = image.width * image.height
45
- if (maxSize > imageSize) maxSize = imageSize
46
- }
47
-
48
- if (size > maxSize) imageScale = Math.sqrt(size / maxSize)
49
-
50
- if (imageScale) {
51
- scaleX /= imageScale
52
- scaleY /= imageScale
53
- width /= imageScale
54
- height /= imageScale
55
- }
56
-
57
- if (sx) {
58
- scaleX /= sx
59
- scaleY /= sy
60
- }
61
-
62
- if (transform || scaleX !== 1 || scaleY !== 1) {
63
- if (!imageMatrix) {
64
- imageMatrix = get()
65
- if (transform) copy(imageMatrix, transform)
66
- }
67
- scale(imageMatrix, 1 / scaleX, 1 / scaleY)
68
- }
69
-
70
- const pattern = Platform.canvas.createPattern(image.getCanvas(width < 1 ? 1 : width, height < 1 ? 1 : height, opacity) as any, repeat || (Platform.origin.noRepeat || 'no-repeat'))
71
-
72
- try {
73
- if (paint.transform) paint.transform = null
74
- if (imageMatrix) pattern.setTransform ? pattern.setTransform(imageMatrix) : paint.transform = imageMatrix
75
- } catch {
76
- paint.transform = imageMatrix
77
- }
78
-
79
- paint.style = pattern
80
- paint.patternId = id
81
-
82
- return true
83
-
84
- } else {
85
-
86
- return false
87
-
88
- }
89
-
90
- }
@@ -1,41 +0,0 @@
1
- import { IBooleanMap, ILeaferImage, IObject } 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(attrName: 'fill' | 'stroke', data: IUIData): IBooleanMap {
8
- const paints = (data as IObject)['_' + attrName] 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
- }