@leafer-ui/paint 1.0.0-alpha.10 → 1.0.0-alpha.23

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-alpha.10",
3
+ "version": "1.0.0-alpha.23",
4
4
  "description": "@leafer-ui/paint",
5
5
  "author": "Chao (Leafer) Wan",
6
6
  "license": "MIT",
@@ -19,7 +19,7 @@
19
19
  "leaferjs"
20
20
  ],
21
21
  "devDependencies": {
22
- "@leafer/interface": "1.0.0-alpha.10",
23
- "@leafer-ui/interface": "1.0.0-alpha.10"
22
+ "@leafer/interface": "1.0.0-alpha.23",
23
+ "@leafer-ui/interface": "1.0.0-alpha.23"
24
24
  }
25
25
  }
package/src/Compute.ts ADDED
@@ -0,0 +1,48 @@
1
+ import { IUI, IPaint, ILeafPaint } from '@leafer-ui/interface'
2
+ import { stringColor } from '@leafer-ui/color'
3
+
4
+ import { image } from "./paint/image"
5
+ import { linearGradient } from './paint/linear'
6
+ import { radialGradient } from "./paint/radial"
7
+ import { conicGradient } from "./paint/conic"
8
+
9
+
10
+ export function computeFill(ui: IUI): void {
11
+ compute(ui, 'fill')
12
+ }
13
+
14
+ export function computeStroke(ui: IUI): void {
15
+ compute(ui, 'stroke')
16
+ }
17
+
18
+ function compute(ui: IUI, attrName: string): void {
19
+ const paint: IPaint[] = ui.__.__input[attrName] as IPaint[]
20
+ if (typeof paint === 'object') {
21
+ let item: ILeafPaint
22
+ const value: ILeafPaint[] = []
23
+ for (let i = 0, len = paint.length; i < len; i++) {
24
+ item = getLeafPaint(ui, paint[i], attrName)
25
+ if (item) value.push(item)
26
+ }
27
+ ui.__['_' + attrName] = value.length ? value : undefined
28
+ }
29
+ }
30
+
31
+ function getLeafPaint(ui: IUI, paint: IPaint, attrName: string): ILeafPaint {
32
+ if (paint.visible === false || paint.opacity === 0) return undefined
33
+
34
+ const { width, height } = ui.__layout.boxBounds
35
+ switch (paint.type) {
36
+ case 'solid':
37
+ let { type, blendMode, color } = paint
38
+ return { type, blendMode, style: stringColor(color) }
39
+ case 'image':
40
+ return image(ui, attrName, paint, width, height)
41
+ case 'linear':
42
+ return linearGradient(paint, width, height)
43
+ case 'radial':
44
+ return radialGradient(paint, width, height)
45
+ case 'angular':
46
+ return conicGradient(paint, width, height)
47
+ }
48
+ }
package/src/Fill.ts CHANGED
@@ -15,6 +15,25 @@ export function fills(ui: IUI, canvas: ILeaferCanvas, fills: ILeafPaint[]): void
15
15
  for (let i = 0, len = fills.length; i < len; i++) {
16
16
  item = fills[i]
17
17
  canvas.fillStyle = item.style
18
- canvas.fill(windingRule)
18
+
19
+ if (item.transform) {
20
+ canvas.save()
21
+
22
+ const { a, b, c, d, e, f } = item.transform
23
+ canvas.transform(a, b, c, d, e, f)
24
+
25
+ if (item.blendMode) canvas.blendMode = item.blendMode
26
+ canvas.fill(windingRule)
27
+
28
+ canvas.restore()
29
+ } else {
30
+ if (item.blendMode) {
31
+ canvas.saveBlendMode(item.blendMode)
32
+ canvas.fill(windingRule)
33
+ canvas.restoreBlendMode()
34
+ } else {
35
+ canvas.fill(windingRule)
36
+ }
37
+ }
19
38
  }
20
39
  }
package/src/Shape.ts ADDED
@@ -0,0 +1,48 @@
1
+ import { IBoundsData, ILeaferCanvas, IRenderOptions, IMatrix } from '@leafer/interface'
2
+ import { BoundsHelper } from '@leafer/math'
3
+
4
+ import { IUI, ICachedShape } from '@leafer-ui/interface'
5
+
6
+
7
+ export function shape(ui: IUI, current: ILeaferCanvas, options: IRenderOptions): ICachedShape {
8
+ const canvas = current.getSameCanvas()
9
+
10
+ let bounds: IBoundsData, matrix: IMatrix, shapeBounds: IBoundsData
11
+ let worldCanvas: ILeaferCanvas
12
+
13
+ const { __world } = ui
14
+ let { a: scaleX, d: scaleY } = __world
15
+
16
+ if (!current.bounds.includes(__world, options.matrix)) {
17
+
18
+ const { renderBoundsSpreadWidth } = ui.__layout
19
+ const worldClipBounds = BoundsHelper.getIntersectData(renderBoundsSpreadWidth ? BoundsHelper.getSpread(current.bounds, renderBoundsSpreadWidth * __world.a) : current.bounds, __world, options.matrix)
20
+ matrix = current.bounds.getFitMatrix(worldClipBounds)
21
+
22
+ if (matrix.a < 1) {
23
+ worldCanvas = current.getSameCanvas()
24
+ ui.__renderShape(worldCanvas, options)
25
+
26
+ scaleX *= matrix.a
27
+ scaleY *= matrix.d
28
+ }
29
+
30
+ shapeBounds = BoundsHelper.getOuterOf(__world, matrix)
31
+ bounds = BoundsHelper.getByMove(shapeBounds, -matrix.e, -matrix.f)
32
+
33
+ if (options.matrix) matrix.multiply(options.matrix)
34
+ options = { ...options, matrix }
35
+
36
+ } else {
37
+
38
+ bounds = shapeBounds = __world
39
+ worldCanvas = canvas
40
+ }
41
+
42
+ ui.__renderShape(canvas, options)
43
+
44
+ return {
45
+ canvas, matrix, bounds,
46
+ worldCanvas, shapeBounds, scaleX, scaleY
47
+ }
48
+ }
package/src/Stroke.ts CHANGED
@@ -36,9 +36,9 @@ export function stroke(ui: IUI, canvas: ILeaferCanvas, stroke: string | object):
36
36
  out.stroke()
37
37
 
38
38
  out.clip(options.windingRule)
39
- out.clearBounds(ui.__layout.renderBounds)
39
+ out.clearWorld(ui.__layout.renderBounds)
40
40
 
41
- canvas.copyWorldToLocal(out, ui.__world, ui.__layout.renderBounds)
41
+ canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds)
42
42
  out.recycle()
43
43
  break
44
44
  }
@@ -76,18 +76,33 @@ export function strokes(ui: IUI, canvas: ILeaferCanvas, strokes: ILeafPaint[]):
76
76
  drawStrokesStyle(strokes, out)
77
77
 
78
78
  out.clip(options.windingRule)
79
- out.clearBounds(renderBounds)
79
+ out.clearWorld(renderBounds)
80
80
 
81
- canvas.copyWorldToLocal(out, ui.__world, renderBounds)
81
+ canvas.copyWorldToInner(out, ui.__world, renderBounds)
82
82
  out.recycle()
83
83
  break
84
84
  }
85
-
86
85
  }
87
86
 
88
87
  function drawStrokesStyle(strokes: ILeafStrokePaint[], canvas: ILeaferCanvas): void {
89
88
  strokes.forEach((item: ILeafStrokePaint) => {
90
89
  canvas.strokeStyle = item.style
91
- canvas.stroke()
90
+
91
+ // if (item.transform) {
92
+ // canvas.save()
93
+ // if (item.blendMode) canvas.blendMode = item.blendMode
94
+ // const { a, b, c, d, e, f } = item.transform
95
+ // canvas.transform(a, b, c, d, e, f)
96
+ // canvas.stroke()
97
+ // canvas.restore()
98
+ // } else {
99
+ if (item.blendMode) {
100
+ canvas.saveBlendMode(item.blendMode)
101
+ canvas.stroke()
102
+ canvas.restoreBlendMode()
103
+ } else {
104
+ canvas.stroke()
105
+ }
106
+ //}
92
107
  })
93
108
  }
package/src/index.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  export { fill, fills } from './Fill'
2
2
  export { stroke, strokes } from './Stroke'
3
+ export { shape } from './Shape'
4
+ export { computeFill, computeStroke } from './Compute'
3
5
 
@@ -0,0 +1,46 @@
1
+ import { IGradientPaint, ILeafPaint, IMatrixData, IPointData } from '@leafer-ui/interface'
2
+ import { Platform, PointHelper, MatrixHelper } from '@leafer/core'
3
+ import { applyStops } from './linear'
4
+
5
+
6
+ const { set, getAngle } = PointHelper
7
+ const { get, rotateOf, scaleOf } = MatrixHelper
8
+
9
+ const defaultFrom = { x: 0.5, y: 0.5 }
10
+ const defaultTo = { x: 0.5, y: 1 }
11
+
12
+ const realFrom = {} as IPointData
13
+ const realTo = {} as IPointData
14
+
15
+ export function conicGradient(paint: IGradientPaint, width: number, height: number): ILeafPaint {
16
+
17
+ let { from, to, type, opacity, blendMode, stretch } = paint
18
+
19
+ from || (from = defaultFrom)
20
+ to || (to = defaultTo)
21
+
22
+ set(realFrom, from.x * width, from.y * height)
23
+ set(realTo, to.x * width, to.y * height)
24
+
25
+ const transform: IMatrixData = get()
26
+ const angle = getAngle(realFrom, realTo)
27
+
28
+ if (Platform.conicGradientRotate90) {
29
+ scaleOf(transform, realFrom, width / height * (stretch || 1), 1)
30
+ rotateOf(transform, realFrom, angle + 90)
31
+ } else {
32
+ scaleOf(transform, realFrom, 1, width / height * (stretch || 1))
33
+ rotateOf(transform, realFrom, angle)
34
+ }
35
+
36
+ const style = Platform.canvas.createConicGradient(0, realFrom.x, realFrom.y)
37
+ applyStops(style, paint.stops, opacity)
38
+
39
+ return {
40
+ type,
41
+ blendMode,
42
+ style,
43
+ transform
44
+ }
45
+
46
+ }
@@ -0,0 +1,112 @@
1
+ import { IUI, IImagePaint, ILeafPaint, IMatrixData, IImagePaintMode, IPointData } from '@leafer-ui/interface'
2
+ import { Platform, MatrixHelper, ImageEvent } from '@leafer/core'
3
+
4
+
5
+ const { get, rotateOf, translate, scaleOf, scale: scaleHelper, rotate } = MatrixHelper
6
+
7
+ export function image(ui: IUI, attrName: string, paint: IImagePaint, boxWidth: number, boxHeight: number): ILeafPaint {
8
+ let { type, blendMode } = paint
9
+ let leaferPaint: ILeafPaint = {
10
+ type,
11
+ blendMode,
12
+ style: 'rgba(255,255,255,0)'
13
+ }
14
+
15
+ const image = ui.leafer.imageManager.get(paint)
16
+
17
+ if (image.ready) {
18
+
19
+ let transform: IMatrixData
20
+ let { opacity, mode, offset, scale, rotation } = paint
21
+ let { width, height } = image
22
+ const sameBox = boxWidth === width && boxHeight === height
23
+
24
+ switch (mode) {
25
+ case 'strench':
26
+ if (!sameBox) width = boxWidth, height = boxHeight
27
+ break
28
+ case 'clip':
29
+ if (offset || scale || rotation) transform = getCropTransform(offset, scale, rotation)
30
+ break
31
+ case 'repeat':
32
+ if (!sameBox || scale || rotation) transform = getRepeatTransform(width, height, scale as number, rotation)
33
+ break
34
+ case 'fit':
35
+ case 'cover':
36
+ default:
37
+ if (!sameBox || rotation) transform = getFillOrFitTransform(mode, width, height, boxWidth, boxHeight, rotation)
38
+ }
39
+
40
+ leaferPaint.style = createPattern(image.getCanvas(width, height, opacity), transform, mode === 'repeat')
41
+
42
+ } else {
43
+
44
+ image.load(() => {
45
+ if (!ui.__.__getInput('width')) ui.width = image.width
46
+ if (!ui.__.__getInput('height')) ui.height = image.height
47
+ ui.__updateAttr('width')
48
+ ui.emitEvent(new ImageEvent(ImageEvent.LOADED, ui, image, attrName, paint))
49
+ }, (error) => {
50
+ ui.emitEvent(new ImageEvent(ImageEvent.ERROR, ui, image, attrName, paint, error))
51
+ })
52
+
53
+ }
54
+
55
+ return leaferPaint
56
+ }
57
+
58
+ function getCropTransform(offset: IPointData, scale: number | IPointData, rotation: number): IMatrixData {
59
+ const transform: IMatrixData = get()
60
+ if (offset) translate(transform, offset.x, offset.y)
61
+ if (scale) typeof scale === 'number' ? scaleHelper(transform, scale) : scaleHelper(transform, scale.x, scale.y)
62
+ if (rotation) rotate(transform, rotation)
63
+ return transform
64
+ }
65
+
66
+ function getFillOrFitTransform(mode: IImagePaintMode, imageWidth: number, imageHeight: number, boxWidth: number, boxHeight: number, rotation: number): IMatrixData {
67
+ const transform: IMatrixData = get()
68
+ const swap = rotation && rotation !== 180
69
+ const sw = boxWidth / (swap ? imageHeight : imageWidth)
70
+ const sh = boxHeight / (swap ? imageWidth : imageHeight)
71
+ const scale = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh)
72
+ const x = (boxWidth - imageWidth * scale) / 2
73
+ const y = (boxHeight - imageHeight * scale) / 2
74
+ translate(transform, x, y)
75
+ scaleHelper(transform, scale)
76
+ if (rotation) {
77
+ const center = { x: boxWidth / 2, y: boxHeight / 2 }
78
+ rotateOf(transform, center, rotation)
79
+ }
80
+ return transform
81
+ }
82
+
83
+
84
+ function getRepeatTransform(imageWidth: number, imageHeight: number, scale: number, rotation: number): IMatrixData {
85
+ const transform = get()
86
+ if (rotation) {
87
+ rotate(transform, rotation)
88
+ switch (rotation) {
89
+ case 90:
90
+ translate(transform, imageHeight, 0)
91
+ break
92
+ case 180:
93
+ translate(transform, imageWidth, imageHeight)
94
+ break
95
+ case 270:
96
+ translate(transform, 0, imageWidth)
97
+ break
98
+ }
99
+ }
100
+ if (scale) scaleOf(transform, { x: 0, y: 0 }, scale)
101
+ return transform
102
+ }
103
+
104
+
105
+ function createPattern(canvas: any, transform?: IMatrixData, repeat?: boolean,): CanvasPattern {
106
+ let style = Platform.canvas.createPattern(canvas, repeat ? 'repeat' : 'no-repeat')
107
+ if (transform) {
108
+ const { a, b, c, d, e, f } = transform
109
+ style.setTransform(new DOMMatrix([a, b, c, d, e, f]))
110
+ }
111
+ return style
112
+ }
@@ -0,0 +1,35 @@
1
+ import { IObject } from '@leafer/interface'
2
+ import { Platform } from '@leafer/core'
3
+
4
+ import { IGradientPaint, ILeafPaint, IColorStop } from '@leafer-ui/interface'
5
+ import { stringColor } from '@leafer-ui/color'
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, width: number, height: number): 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(from.x * width, from.y * height, to.x * width, to.y * height)
19
+ applyStops(style, paint.stops, opacity)
20
+
21
+ return {
22
+ type,
23
+ blendMode,
24
+ style
25
+ }
26
+
27
+ }
28
+
29
+ export function applyStops(gradient: IObject, stops: IColorStop[], opacity: number): void {
30
+ let stop: IColorStop
31
+ for (let i = 0, len = stops.length; i < len; i++) {
32
+ stop = stops[i]
33
+ gradient.addColorStop(stop.offset, stringColor(stop.color, opacity))
34
+ }
35
+ }
@@ -0,0 +1,42 @@
1
+ import { IGradientPaint, ILeafPaint, IMatrixData, IPointData } from '@leafer-ui/interface'
2
+ import { Platform, PointHelper, MatrixHelper } from '@leafer/core'
3
+ import { applyStops } from './linear'
4
+
5
+
6
+ const { set, getAngle, getDistance } = PointHelper
7
+ const { get, rotateOf, scaleOf } = MatrixHelper
8
+
9
+ const defaultFrom = { x: 0.5, y: 0.5 }
10
+ const defaultTo = { x: 0.5, y: 1 }
11
+
12
+ const realFrom = {} as IPointData
13
+ const realTo = {} as IPointData
14
+
15
+ export function radialGradient(paint: IGradientPaint, width: number, height: number): ILeafPaint {
16
+
17
+ let { from, to, type, opacity, blendMode, stretch } = paint
18
+
19
+ from || (from = defaultFrom)
20
+ to || (to = defaultTo)
21
+
22
+ set(realFrom, from.x * width, from.y * height)
23
+ set(realTo, to.x * width, to.y * height)
24
+
25
+ let transform: IMatrixData
26
+ if (width !== height || stretch) {
27
+ transform = get()
28
+ scaleOf(transform, realFrom, width / height * (stretch || 1), 1)
29
+ rotateOf(transform, realFrom, getAngle(realFrom, realTo) + 90)
30
+ }
31
+
32
+ const style = Platform.canvas.createRadialGradient(realFrom.x, realFrom.y, 0, realFrom.x, realFrom.y, getDistance(realFrom, realTo))
33
+ applyStops(style, paint.stops, opacity)
34
+
35
+ return {
36
+ type,
37
+ blendMode,
38
+ style,
39
+ transform
40
+ }
41
+
42
+ }