@leafer-ui/display 1.0.0-alpha.9 → 1.0.0-beta

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/display",
3
- "version": "1.0.0-alpha.9",
3
+ "version": "1.0.0-beta",
4
4
  "description": "@leafer-ui/display",
5
5
  "author": "Chao (Leafer) Wan",
6
6
  "license": "MIT",
@@ -19,13 +19,14 @@
19
19
  "leaferjs"
20
20
  ],
21
21
  "dependencies": {
22
- "@leafer/core": "1.0.0-alpha.9",
23
- "@leafer-ui/data": "1.0.0-alpha.9",
24
- "@leafer-ui/display-module": "1.0.0-alpha.9",
25
- "@leafer-ui/decorator": "1.0.0-alpha.9"
22
+ "@leafer/core": "1.0.0-beta",
23
+ "@leafer-ui/data": "1.0.0-beta",
24
+ "@leafer-ui/text": "1.0.0-beta",
25
+ "@leafer-ui/display-module": "1.0.0-beta",
26
+ "@leafer-ui/decorator": "1.0.0-beta"
26
27
  },
27
28
  "devDependencies": {
28
- "@leafer/interface": "1.0.0-alpha.9",
29
- "@leafer-ui/interface": "1.0.0-alpha.9"
29
+ "@leafer/interface": "1.0.0-beta",
30
+ "@leafer-ui/interface": "1.0.0-beta"
30
31
  }
31
32
  }
package/src/Box.ts ADDED
@@ -0,0 +1,105 @@
1
+ import { ILeaferCanvas, IRenderOptions, IPathDrawer, IBoundsData, IPathCommandData, __Boolean } from '@leafer/interface'
2
+ import { rewrite, rewriteAble, registerUI, BoundsHelper, dataProcessor, affectRenderBoundsType } from '@leafer/core'
3
+
4
+ import { IBox, IBoxData, IBoxInputData, IOverflow } from '@leafer-ui/interface'
5
+
6
+ import { Group } from './Group'
7
+ import { Rect } from './Rect'
8
+ import { BoxData } from '@leafer-ui/data'
9
+
10
+
11
+ const rect = Rect.prototype
12
+ const group = Group.prototype
13
+ const bounds = {} as IBoundsData
14
+ const { copy, add } = BoundsHelper
15
+
16
+ @rewriteAble()
17
+ @registerUI()
18
+ export class Box extends Group implements IBox {
19
+
20
+ public get __tag() { return 'Box' }
21
+
22
+ @dataProcessor(BoxData)
23
+ public __: IBoxData
24
+
25
+ @affectRenderBoundsType('show')
26
+ public overflow: IOverflow
27
+
28
+ constructor(data?: IBoxInputData) {
29
+ super(data)
30
+ this.isBranchLeaf = true
31
+ this.__layout.renderChanged || this.__layout.renderChange()
32
+ }
33
+
34
+ @rewrite(rect.__updateStrokeSpread)
35
+ public __updateStrokeSpread(): number { return 0 }
36
+
37
+ @rewrite(rect.__updateRenderSpread)
38
+ public __updateRectRenderSpread(): number { return 0 }
39
+
40
+ public __updateRenderSpread(): number {
41
+ let width = this.__updateRectRenderSpread() || super.__updateRenderSpread()
42
+ this.__.__drawAfterFill = this.__.overflow === 'hide'
43
+ if (!width) width = this.__.__drawAfterFill ? 0 : 1
44
+ return width
45
+ }
46
+
47
+
48
+ @rewrite(rect.__updateBoxBounds)
49
+ public __updateBoxBounds(): void { }
50
+
51
+ @rewrite(rect.__updateStrokeBounds)
52
+ public __updateStrokeBounds(): void { }
53
+
54
+ public __updateRenderBounds(): void {
55
+ this.__updateRectRenderBounds()
56
+ if (!this.__.__drawAfterFill) {
57
+ const { renderBounds } = this.__layout
58
+ copy(bounds, renderBounds)
59
+ super.__updateRenderBounds()
60
+ add(renderBounds, bounds)
61
+ }
62
+ }
63
+
64
+
65
+ @rewrite(rect.__updateRenderBounds)
66
+ public __updateRectRenderBounds(): void { }
67
+
68
+ @rewrite(rect.__updateChange)
69
+ public __updateRectChange(): void { }
70
+
71
+ public __updateChange(): void {
72
+ super.__updateChange()
73
+ this.__updateRectChange()
74
+ }
75
+
76
+
77
+ @rewrite(rect.__drawPathByData)
78
+ public __drawPathByData(_drawer: IPathDrawer, _data: IPathCommandData): void { }
79
+
80
+
81
+ @rewrite(rect.__render)
82
+ public __renderRect(_canvas: ILeaferCanvas, _options: IRenderOptions): void { }
83
+
84
+ @rewrite(group.__render)
85
+ public __renderGroup(_canvas: ILeaferCanvas, _options: IRenderOptions): void { }
86
+
87
+
88
+ public __render(canvas: ILeaferCanvas, options: IRenderOptions): void {
89
+ if (this.__.__drawAfterFill) {
90
+ this.__renderRect(canvas, options)
91
+ } else {
92
+ this.__renderRect(canvas, options)
93
+ this.__renderGroup(canvas, options)
94
+ }
95
+ }
96
+
97
+ public __drawAfterFill(canvas: ILeaferCanvas, options: IRenderOptions): void {
98
+ canvas.save()
99
+ canvas.clip()
100
+ this.__renderGroup(canvas, options)
101
+ canvas.restore()
102
+ if (this.__.stroke) this.__drawRenderPath(canvas)
103
+ }
104
+
105
+ }
package/src/Canvas.ts ADDED
@@ -0,0 +1,96 @@
1
+ import { ILeaferCanvas, ILeaferCanvasConfig, __String, __Number, IRenderOptions, IPointData, ICanvasContext2D, IScreenSizeData, ISizeData, IHitType } from '@leafer/interface'
2
+ import { Creator, Matrix, Platform, dataProcessor, registerUI, hitType } from '@leafer/core'
3
+
4
+ import { ICanvas, ICanvasData, ICanvasInputData, IUI } from '@leafer-ui/interface'
5
+ import { ImageData } from '@leafer-ui/data'
6
+
7
+ import { Rect } from './Rect'
8
+ import { resizeType } from '@leafer-ui/decorator'
9
+
10
+
11
+ @registerUI()
12
+ export class Canvas extends Rect implements ICanvas {
13
+
14
+ public get __tag() { return 'Canvas' }
15
+
16
+ @dataProcessor(ImageData)
17
+ public __: ICanvasData
18
+
19
+ @resizeType(100)
20
+ public width: __Number
21
+
22
+ @resizeType(100)
23
+ public height: __Number
24
+
25
+ @resizeType(Platform.devicePixelRatio)
26
+ public pixelRatio: __Number
27
+
28
+ @resizeType(true)
29
+ public smooth: boolean
30
+
31
+ @hitType('all')
32
+ public hitFill: IHitType
33
+
34
+ public canvas: ILeaferCanvas
35
+
36
+ public context: ICanvasContext2D
37
+
38
+ constructor(data?: ICanvasInputData) {
39
+ super(data)
40
+ this.canvas = Creator.canvas(this.__ as ILeaferCanvasConfig)
41
+ this.context = this.canvas.context
42
+ this.__.__drawAfterFill = true
43
+ }
44
+
45
+ public draw(ui: IUI, offset?: IPointData, scale?: number | IPointData, rotation?: number): void {
46
+ ui.__layout.checkUpdate()
47
+
48
+ const matrix = new Matrix(ui.__world)
49
+ matrix.invert()
50
+
51
+ const m = new Matrix()
52
+ if (offset) m.translate(offset.x, offset.y)
53
+ if (scale) typeof scale === 'number' ? m.scale(scale) : m.scale(scale.x, scale.y)
54
+ if (rotation) m.rotate(rotation)
55
+ matrix.preMultiply(m)
56
+
57
+ ui.__render(this.canvas, { matrix })
58
+ this.paint()
59
+ }
60
+
61
+ public paint(): void {
62
+ this.forceUpdate('fill')
63
+ }
64
+
65
+ public __drawAfterFill(canvas: ILeaferCanvas, _options: IRenderOptions): void {
66
+ const origin = this.canvas.view as ISizeData
67
+ const { width, height } = this
68
+ if (this.__.cornerRadius) {
69
+ canvas.save()
70
+ canvas.clip()
71
+ canvas.drawImage(this.canvas.view as any, 0, 0, origin.width, origin.height, 0, 0, width, height)
72
+ canvas.restore()
73
+ } else {
74
+ canvas.drawImage(this.canvas.view as any, 0, 0, origin.width, origin.height, 0, 0, width, height)
75
+ }
76
+ }
77
+
78
+ public __updateSize(): void {
79
+ const { canvas } = this
80
+ if (canvas) {
81
+ const { smooth } = this.__
82
+ if (canvas.smooth !== smooth) canvas.smooth = smooth
83
+ canvas.resize(this.__ as IScreenSizeData)
84
+ }
85
+ }
86
+
87
+ public destroy(): void {
88
+ if (this.canvas) {
89
+ this.canvas.destroy()
90
+ this.canvas = null
91
+ this.context = null
92
+ }
93
+ super.destroy()
94
+ }
95
+
96
+ }
package/src/Ellipse.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { __Number } from '@leafer/interface'
2
- import { PathCreator, OneRadian, dataProcessor, pathType, registerUI } from '@leafer/core'
2
+ import { PathCommandDataHelper, dataProcessor, pathType, registerUI } from '@leafer/core'
3
3
 
4
4
  import { IEllipse, IEllipseInputData, IEllipseData } from '@leafer-ui/interface'
5
5
  import { EllipseData } from '@leafer-ui/data'
@@ -7,14 +7,13 @@ import { EllipseData } from '@leafer-ui/data'
7
7
  import { UI } from './UI'
8
8
 
9
9
 
10
-
11
- const { PI } = Math
12
- const { begin, moveTo, close, ellipse } = PathCreator
13
-
10
+ const { moveTo, closePath, ellipse } = PathCommandDataHelper
14
11
 
15
12
  @registerUI()
16
13
  export class Ellipse extends UI implements IEllipse {
17
14
 
15
+ public get __tag() { return 'Ellipse' }
16
+
18
17
  @dataProcessor(EllipseData)
19
18
  public __: IEllipseData
20
19
 
@@ -36,28 +35,30 @@ export class Ellipse extends UI implements IEllipse {
36
35
  const { width, height, innerRadius, startAngle, endAngle } = this.__
37
36
  const rx = width / 2, ry = height / 2
38
37
 
39
- begin(this.__.path = [])
38
+ const path: number[] = this.__.path = []
40
39
 
41
40
  if (innerRadius) {
42
41
 
43
42
  if (startAngle || endAngle) {
44
- ellipse(rx, ry, rx * (1 - innerRadius), ry * (1 - innerRadius), 0, startAngle * OneRadian, endAngle * OneRadian, false)
45
- ellipse(rx, ry, rx, ry, 0, endAngle * OneRadian, startAngle * OneRadian, true)
46
- close()
43
+ if (innerRadius < 1) ellipse(path, rx, ry, rx * innerRadius, ry * innerRadius, 0, startAngle, endAngle, false)
44
+ ellipse(path, rx, ry, rx, ry, 0, endAngle, startAngle, true)
45
+ if (innerRadius < 1) closePath(path)
47
46
  } else {
48
- ellipse(rx, ry, rx * (1 - innerRadius), ry * (1 - innerRadius), 0, 0, 2 * PI, false)
49
- moveTo(width, ry)
50
- ellipse(rx, ry, rx, ry, 0, 0, 2 * PI, true)
47
+ if (innerRadius < 1) {
48
+ ellipse(path, rx, ry, rx * innerRadius, ry * innerRadius)
49
+ moveTo(path, width, ry)
50
+ }
51
+ ellipse(path, rx, ry, rx, ry, 0, 0, 360, true)
51
52
  }
52
53
 
53
54
  } else {
54
55
 
55
56
  if (startAngle || endAngle) {
56
- moveTo(rx, ry)
57
- ellipse(rx, ry, rx, ry, 0, startAngle * OneRadian, endAngle * OneRadian, false)
58
- close()
57
+ moveTo(path, rx, ry)
58
+ ellipse(path, rx, ry, rx, ry, 0, startAngle, endAngle, false)
59
+ closePath(path)
59
60
  } else {
60
- ellipse(rx, ry, rx, ry, 0, 0, 2 * PI, false)
61
+ ellipse(path, rx, ry, rx, ry)
61
62
  }
62
63
 
63
64
  }
package/src/Frame.ts CHANGED
@@ -1,84 +1,25 @@
1
- import { ILeaferCanvas, IRenderOptions, IPathDrawer, IBoundsData, IPathCommandData, __Boolean } from '@leafer/interface'
2
- import { BoundsHelper, dataProcessor, boundsType, rewrite, useModule, rewriteAble, registerUI } from '@leafer/core'
1
+ import { __Boolean } from '@leafer/interface'
2
+ import { dataProcessor, registerUI, affectRenderBoundsType } from '@leafer/core'
3
3
 
4
- import { IFrame, IFrameData, IFrameInputData } from '@leafer-ui/interface'
4
+ import { IFrame, IFrameData, IFrameInputData, IOverflow } from '@leafer-ui/interface'
5
5
  import { FrameData } from '@leafer-ui/data'
6
- import { FrameRender } from '@leafer-ui/display-module'
7
6
 
8
- import { Group } from './Group'
9
- import { Rect } from './Rect'
7
+ import { Box } from './Box'
10
8
 
11
9
 
12
- const rect = Rect.prototype
13
- const group = Group.prototype
14
- const bounds = {} as IBoundsData
15
- const { copy, add } = BoundsHelper
16
-
17
-
18
- @useModule(FrameRender)
19
- @rewriteAble()
20
10
  @registerUI()
21
- export class Frame extends Group implements IFrame {
11
+ export class Frame extends Box implements IFrame {
12
+
13
+ public get __tag() { return 'Frame' }
22
14
 
23
15
  @dataProcessor(FrameData)
24
16
  public __: IFrameData
25
17
 
26
- @boundsType(true)
27
- public clip: __Boolean
18
+ @affectRenderBoundsType('hide')
19
+ public overflow: IOverflow
28
20
 
29
21
  constructor(data?: IFrameInputData) {
30
22
  super(data)
31
- if (!this.fill) this.fill = '#FFFFFF'
32
- this.__isBranchLeaf = true
23
+ if (!this.__.fill) this.__.fill = '#FFFFFF'
33
24
  }
34
-
35
- @rewrite(rect.__drawPathByData)
36
- public __drawPathByData(_drawer: IPathDrawer, _data: IPathCommandData): void { }
37
-
38
- public __updateBoxBounds(): void {
39
- this.__updateRectBoxBounds()
40
- if (!this.__.clip) {
41
- const { boxBounds } = this.__layout
42
- copy(bounds, boxBounds)
43
- super.__updateBoxBounds()
44
- add(boxBounds, bounds)
45
- }
46
- }
47
-
48
- public __updateEventBounds(): void {
49
- this.__updateRectEventBounds()
50
- if (!this.__.clip) {
51
- const { eventBounds } = this.__layout
52
- copy(bounds, eventBounds)
53
- super.__updateEventBounds()
54
- add(eventBounds, bounds)
55
- }
56
- }
57
-
58
- public __updateRenderBounds(): void {
59
- this.__updateRectRenderBounds()
60
- if (!this.__.clip) {
61
- const { renderBounds } = this.__layout
62
- copy(bounds, renderBounds)
63
- super.__updateRenderBounds()
64
- add(renderBounds, bounds)
65
- }
66
- }
67
-
68
- @rewrite(rect.__updateBoxBounds)
69
- public __updateRectBoxBounds(): void { }
70
-
71
- @rewrite(rect.__updateEventBounds)
72
- public __updateRectEventBounds(): void { }
73
-
74
- @rewrite(rect.__updateRenderBounds)
75
- public __updateRectRenderBounds(): void { }
76
-
77
-
78
- @rewrite(rect.__render)
79
- public __renderRect(_canvas: ILeaferCanvas, _options: IRenderOptions): void { }
80
-
81
- @rewrite(group.__render)
82
- public __renderGroup(_canvas: ILeaferCanvas, _options: IRenderOptions): void { }
83
-
84
25
  }
package/src/Group.ts CHANGED
@@ -10,14 +10,27 @@ import { UI } from './UI'
10
10
  @registerUI()
11
11
  export class Group extends UI implements IGroup {
12
12
 
13
+ public get __tag() { return 'Group' }
14
+
13
15
  @dataProcessor(GroupData)
14
16
  public __: IGroupData
15
17
 
16
18
  public children: IUI[]
17
19
 
20
+ public set mask(child: IUI) {
21
+ if (this.__hasMask) this.__removeMask()
22
+ if (child) {
23
+ child.isMask = true
24
+ this.addAt(child, 0)
25
+ }
26
+ }
27
+ public get mask(): IUI {
28
+ return this.children.find(item => item.isMask)
29
+ }
30
+
18
31
  constructor(data?: IGroupInputData) {
19
32
  super(data)
20
- this.__isBranch = true
33
+ this.isBranch = true
21
34
  this.children = []
22
35
  }
23
36
 
package/src/Image.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { __String } from '@leafer/interface'
2
- import { boundsType, dataProcessor, registerUI } from '@leafer/core'
1
+ import { ILeaferImage, __String } from '@leafer/interface'
2
+ import { ImageEvent, boundsType, dataProcessor, registerUI } from '@leafer/core'
3
3
 
4
- import { IImage, IImageInputData, IImageData } from '@leafer-ui/interface'
4
+ import { IImage, IImageInputData, IImageData, IImagePaint } from '@leafer-ui/interface'
5
5
  import { ImageData } from '@leafer-ui/data'
6
6
 
7
7
  import { Rect } from './Rect'
@@ -10,17 +10,48 @@ import { Rect } from './Rect'
10
10
  @registerUI()
11
11
  export class Image extends Rect implements IImage {
12
12
 
13
+ public get __tag() { return 'Image' }
14
+
13
15
  @dataProcessor(ImageData)
14
16
  public __: IImageData
15
17
 
16
18
  @boundsType('')
17
19
  public url: __String
18
20
 
19
- @boundsType('')
20
- public thumb: __String
21
+ public get ready(): boolean { return this.image ? this.image.ready : false }
22
+
23
+ public image: ILeaferImage
21
24
 
22
25
  constructor(data?: IImageInputData) {
23
26
  super(data)
24
27
  }
25
28
 
29
+ public __updateBoxBounds(): void {
30
+
31
+ let update: boolean
32
+
33
+ const { url } = this
34
+ const fill = this.fill as IImagePaint
35
+
36
+ if (fill) {
37
+ if (fill.url !== url) update = true
38
+ } else {
39
+ if (url) update = true
40
+ }
41
+
42
+ if (update) {
43
+ if (this.image) this.image = null
44
+ this.fill = { type: 'image', mode: 'strench', url }
45
+ this.once(ImageEvent.LOADED, (e) => this.image = e.image)
46
+ }
47
+
48
+ super.__updateBoxBounds()
49
+
50
+ }
51
+
52
+ public destroy(): void {
53
+ this.image = null
54
+ super.destroy()
55
+ }
56
+
26
57
  }
package/src/Line.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import { IPointData, ITwoPointBoundsData, __Number } from '@leafer/interface'
2
- import { PathCreator, PointHelper, TwoPointBoundsHelper, boundsType, dataProcessor, registerUI } from '@leafer/core'
2
+ import { PathCommandDataHelper, PointHelper, TwoPointBoundsHelper, boundsType, affectStrokeBoundsType, dataProcessor, registerUI } from '@leafer/core'
3
3
 
4
- import { ILine, ILineData, ILineInputData } from '@leafer-ui/interface'
4
+ import { ILine, ILineData, ILineInputData, IStrokeAlign } from '@leafer-ui/interface'
5
5
  import { LineData } from '@leafer-ui/data'
6
6
 
7
7
  import { UI } from './UI'
8
8
 
9
9
 
10
- const { begin, moveTo, lineTo, end } = PathCreator
10
+ const { moveTo, lineTo } = PathCommandDataHelper
11
11
  const { rotate, getAngle, getDistance, defaultPoint } = PointHelper
12
12
  const { setPoint, addPoint, toBounds } = TwoPointBoundsHelper
13
13
 
@@ -17,16 +17,21 @@ const pointBounds = {} as ITwoPointBoundsData
17
17
  @registerUI()
18
18
  export class Line extends UI implements ILine {
19
19
 
20
+ public get __tag() { return 'Line' }
21
+
20
22
  @dataProcessor(LineData)
21
23
  public __: ILineData
22
24
 
23
25
  @boundsType()
24
26
  public rotation: __Number
25
27
 
28
+ @affectStrokeBoundsType('center')
29
+ public strokeAlign: IStrokeAlign
30
+
26
31
  protected __toPoint: IPointData
27
32
 
28
33
  public get toPoint(): IPointData {
29
- if (this.__toPoint && !this.__layout.boxBoundsChanged) return this.__toPoint
34
+ if (this.__toPoint && !this.__layout.boxChanged) return this.__toPoint
30
35
 
31
36
  const { width, rotation } = this.__
32
37
  const to: IPointData = { x: 0, y: 0 }
@@ -51,12 +56,11 @@ export class Line extends UI implements ILine {
51
56
 
52
57
  public __updatePath(): void {
53
58
 
54
- begin(this.__.path = [])
55
- moveTo(0, 0)
59
+ const path: number[] = this.__.path = []
60
+ moveTo(path, 0, 0)
56
61
 
57
62
  const to = this.toPoint
58
- lineTo(to.x, to.y)
59
- end()
63
+ lineTo(path, to.x, to.y)
60
64
  }
61
65
 
62
66
  public __updateBoxBounds(): void {
package/src/Path.ts CHANGED
@@ -1,21 +1,19 @@
1
- import { ITwoPointBoundsData, ILeaferCanvas, IPathCommandData, IWindingRule } from '@leafer/interface'
2
- import { PathHelper, TwoPointBoundsHelper, dataProcessor, pathType, registerUI } from '@leafer/core'
1
+ import { IPathCommandData, IWindingRule } from '@leafer/interface'
2
+ import { PathBounds, dataProcessor, pathType, affectStrokeBoundsType, registerUI } from '@leafer/core'
3
3
 
4
- import { IPath, IPathData, IPathInputData, IPathString } from '@leafer-ui/interface'
4
+ import { IPath, IPathData, IPathInputData, IPathString, IStrokeAlign } from '@leafer-ui/interface'
5
5
  import { PathData } from '@leafer-ui/data'
6
6
 
7
7
  import { UI } from './UI'
8
8
 
9
9
 
10
- const { toTwoPointBounds } = PathHelper
11
- const { toBounds } = TwoPointBoundsHelper
12
-
13
- const pointBounds = {} as ITwoPointBoundsData
14
-
10
+ const { toBounds } = PathBounds
15
11
 
16
12
  @registerUI()
17
13
  export class Path extends UI implements IPath {
18
14
 
15
+ public get __tag() { return 'Path' }
16
+
19
17
  @dataProcessor(PathData)
20
18
  public __: IPathData
21
19
 
@@ -25,18 +23,15 @@ export class Path extends UI implements IPath {
25
23
  @pathType()
26
24
  public windingRule: IWindingRule
27
25
 
26
+ @affectStrokeBoundsType('center')
27
+ public strokeAlign: IStrokeAlign
28
+
28
29
  constructor(data?: IPathInputData) {
29
30
  super(data)
30
31
  }
31
32
 
32
- public __drawRenderPath(canvas: ILeaferCanvas): void {
33
- canvas.beginPath()
34
- this.__drawPathByData(canvas, this.__.path)
35
- }
36
-
37
33
  public __updateBoxBounds(): void {
38
- toTwoPointBounds(this.__.path, pointBounds)
39
- toBounds(pointBounds, this.__layout.boxBounds)
34
+ toBounds(this.__.path, this.__layout.boxBounds)
40
35
  }
41
36
 
42
37
  }
package/src/Pen.ts ADDED
@@ -0,0 +1,78 @@
1
+ import { PathCreator, dataProcessor, registerUI, useModule } from '@leafer/core'
2
+
3
+ import { IPenData, IPenInputData, IPathInputData, IPathCommandData, IPath } from '@leafer-ui/interface'
4
+ import { PenData } from '@leafer-ui/data'
5
+
6
+ import { Group } from './Group'
7
+ import { Path } from './Path'
8
+
9
+
10
+ @useModule(PathCreator, ['beginPath'])
11
+ @registerUI()
12
+ export class Pen extends Group {
13
+
14
+ public get __tag() { return 'Pen' }
15
+
16
+ @dataProcessor(PenData)
17
+ public __: IPenData
18
+
19
+ public pathElement: IPath
20
+ public pathStyle: IPathInputData
21
+ public path: IPathCommandData
22
+
23
+ constructor(data?: IPenInputData) {
24
+ super(data)
25
+ }
26
+
27
+ public setStyle(data: IPathInputData): Pen {
28
+ const path = this.pathElement = new Path(data)
29
+ this.pathStyle = data
30
+ this.path = path.path as IPathCommandData || (path.path = [])
31
+ this.add(path)
32
+ return this
33
+ }
34
+
35
+ public beginPath(): Pen {
36
+ this.path.length = 0
37
+ this.paint()
38
+ return this
39
+ }
40
+
41
+ // svg and canvas
42
+
43
+ public moveTo(_x: number, _y: number): Pen { return this }
44
+
45
+ public lineTo(_x: number, _y: number): Pen { return this }
46
+
47
+ public bezierCurveTo(_x1: number, _y1: number, _x2: number, _y2: number, _x: number, _y: number): Pen { return this }
48
+
49
+ public quadraticCurveTo(_x1: number, _y1: number, _x: number, _y: number): Pen { return this }
50
+
51
+ public closePath(): Pen { return this }
52
+
53
+
54
+ // canvas
55
+
56
+ public rect(_x: number, _y: number, _width: number, _height: number): Pen { return this }
57
+
58
+ public roundRect(_x: number, _y: number, _width: number, _height: number, _cornerRadius: number | number[]): Pen { return this }
59
+
60
+ public ellipse(_x: number, _y: number, _radiusX: number, _radiusY: number, _rotation?: number, _startAngle?: number, _endAngle?: number, _anticlockwise?: boolean): Pen { return this }
61
+
62
+ public arc(_x: number, _y: number, _radius: number, _startAngle?: number, _endAngle?: number, _anticlockwise?: boolean): Pen { return this }
63
+
64
+ public arcTo(_x1: number, _y1: number, _x2: number, _y2: number, _radius: number): Pen { return this }
65
+
66
+
67
+ // moveTo, then draw
68
+
69
+ public moveToEllipse(_x: number, _y: number, _radiusX: number, _radiusY: number, _rotation?: number, _startAngle?: number, _endAngle?: number, _anticlockwise?: boolean): Pen { return this }
70
+
71
+ public moveToArc(_x: number, _y: number, _radius: number, _startAngle?: number, _endAngle?: number, _anticlockwise?: boolean): Pen { return this }
72
+
73
+
74
+ public paint(): void {
75
+ this.pathElement.forceUpdate('path')
76
+ }
77
+
78
+ }
package/src/Polygon.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { __Number } from '@leafer/interface'
2
- import { PathCreator, dataProcessor, pathType, registerUI } from '@leafer/core'
2
+ import { PathCommandDataHelper, dataProcessor, pathType, registerUI } from '@leafer/core'
3
3
 
4
4
  import { IPolygon, IPolygonData, IPolygonInputData } from '@leafer-ui/interface'
5
5
  import { PolygonData } from '@leafer-ui/data'
@@ -8,12 +8,14 @@ import { UI } from './UI'
8
8
 
9
9
 
10
10
  const { sin, cos, PI } = Math
11
- const { begin, moveTo, lineTo, close } = PathCreator
11
+ const { moveTo, lineTo, closePath } = PathCommandDataHelper
12
12
 
13
13
 
14
14
  @registerUI()
15
15
  export class Polygon extends UI implements IPolygon {
16
16
 
17
+ public get __tag() { return 'Polygon' }
18
+
17
19
  @dataProcessor(PolygonData)
18
20
  public __: IPolygonData
19
21
 
@@ -29,14 +31,14 @@ export class Polygon extends UI implements IPolygon {
29
31
  const { width, height, sides } = this.__
30
32
  const rx = width / 2, ry = height / 2
31
33
 
32
- begin(this.__.path = [])
33
- moveTo(rx, 0)
34
+ const path: number[] = this.__.path = []
35
+ moveTo(path, rx, 0)
34
36
 
35
37
  for (let i = 1; i < sides; i++) {
36
- lineTo(rx + rx * sin((i * 2 * PI) / sides), ry - ry * cos((i * 2 * PI) / sides))
38
+ lineTo(path, rx + rx * sin((i * 2 * PI) / sides), ry - ry * cos((i * 2 * PI) / sides))
37
39
  }
38
40
 
39
- close()
41
+ closePath(path)
40
42
  }
41
43
 
42
44
  }
package/src/Rect.ts CHANGED
@@ -12,6 +12,8 @@ import { UI } from './UI'
12
12
  @registerUI()
13
13
  export class Rect extends UI implements IRect {
14
14
 
15
+ public get __tag() { return 'Rect' }
16
+
15
17
  @dataProcessor(RectData)
16
18
  public __: IRectData
17
19
 
package/src/Star.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { __Number } from '@leafer/interface'
2
- import { PathCreator, dataProcessor, pathType, registerUI } from '@leafer/core'
2
+ import { PathCommandDataHelper, dataProcessor, pathType, registerUI } from '@leafer/core'
3
3
 
4
4
  import { IStar, IStarData, IStarInputData } from '@leafer-ui/interface'
5
5
  import { StarData } from '@leafer-ui/data'
@@ -8,19 +8,21 @@ import { UI } from './UI'
8
8
 
9
9
 
10
10
  const { sin, cos, PI } = Math
11
- const { begin, moveTo, lineTo, close } = PathCreator
11
+ const { moveTo, lineTo, closePath } = PathCommandDataHelper
12
12
 
13
13
 
14
14
  @registerUI()
15
15
  export class Star extends UI implements IStar {
16
16
 
17
+ public get __tag() { return 'Star' }
18
+
17
19
  @dataProcessor(StarData)
18
20
  public __: IStarData
19
21
 
20
22
  @pathType(5)
21
23
  public points: __Number
22
24
 
23
- @pathType(0.38)
25
+ @pathType(0.382)
24
26
  public innerRadius: __Number
25
27
 
26
28
  constructor(data?: IStarInputData) {
@@ -32,14 +34,14 @@ export class Star extends UI implements IStar {
32
34
  const { width, height, points, innerRadius } = this.__
33
35
  const rx = width / 2, ry = height / 2
34
36
 
35
- begin(this.__.path = [])
36
- moveTo(rx, 0)
37
+ const path: number[] = this.__.path = []
38
+ moveTo(path, rx, 0)
37
39
 
38
40
  for (let i = 1; i < points * 2; i++) {
39
- lineTo(rx + (i % 2 === 0 ? rx : rx * innerRadius) * sin((i * PI) / points), ry - (i % 2 === 0 ? ry : ry * innerRadius) * cos((i * PI) / points))
41
+ lineTo(path, rx + (i % 2 === 0 ? rx : rx * innerRadius) * sin((i * PI) / points), ry - (i % 2 === 0 ? ry : ry * innerRadius) * cos((i * PI) / points))
40
42
  }
41
43
 
42
- close()
44
+ closePath(path)
43
45
 
44
46
  }
45
47
 
package/src/Text.ts CHANGED
@@ -1,24 +1,40 @@
1
- import { IPathDrawer, IPathCommandData, __Boolean, __Number, __String } from '@leafer/interface'
2
- import { Platform, boundsType, dataProcessor, registerUI, useModule } from '@leafer/core'
1
+ import { ILeaferCanvas, IPathDrawer, IPathCommandData, __Boolean, __Number, __String } from '@leafer/interface'
2
+ import { BoundsHelper, boundsType, dataProcessor, registerUI, affectStrokeBoundsType } from '@leafer/core'
3
3
 
4
- import { IText, IFontWeight, ITextCase, ITextDecoration, IPercent, ITextData, ITextInputData } from '@leafer-ui/interface'
5
- import { TextData } from '@leafer-ui/data'
6
- import { TextRender } from '@leafer-ui/display-module'
4
+ import { IText, IFontWeight, ITextCase, ITextDecoration, ITextData, ITextInputData, ITextAlign, IVerticalAlign, ITextDrawData, IOverflow, IUnitData, IStrokeAlign } from '@leafer-ui/interface'
5
+ import { TextData, UnitConvert } from '@leafer-ui/data'
6
+ import { TextConvert } from '@leafer-ui/text'
7
7
 
8
8
  import { UI } from './UI'
9
9
 
10
10
 
11
- @useModule(TextRender)
11
+ const { copyAndSpread, includes, spread } = BoundsHelper
12
+
12
13
  @registerUI()
13
14
  export class Text extends UI implements IText {
14
15
 
16
+ public get __tag() { return 'Text' }
17
+
15
18
  @dataProcessor(TextData)
16
19
  public __: ITextData
17
20
 
21
+ // size
22
+ @boundsType(0)
23
+ public width: __Number
24
+
25
+ @boundsType(0)
26
+ public height: __Number
27
+
28
+ @boundsType(0)
29
+ public padding: number | number[]
30
+
31
+ @affectStrokeBoundsType('outside')
32
+ public strokeAlign: IStrokeAlign
33
+
18
34
  @boundsType('')
19
- public content: __String
35
+ public text: __String
20
36
 
21
- @boundsType('arial')
37
+ @boundsType('L')
22
38
  public fontFamily: __String
23
39
 
24
40
  @boundsType(12)
@@ -30,45 +46,108 @@ export class Text extends UI implements IText {
30
46
  @boundsType(false)
31
47
  public italic: __Boolean
32
48
 
33
- @boundsType('normal')
49
+ @boundsType('none')
34
50
  public textCase: ITextCase
35
51
 
36
- @boundsType('normal')
52
+ @boundsType('none')
37
53
  public textDecoration: ITextDecoration
38
54
 
39
- @boundsType()
40
- public letterSpacing: __Number | IPercent
55
+ @boundsType(0)
56
+ public letterSpacing: __Number | IUnitData
41
57
 
42
- @boundsType()
43
- public lineHeight: __Number | IPercent
58
+ @boundsType({ type: 'percent', value: 150 } as IUnitData)
59
+ public lineHeight: __Number | IUnitData
44
60
 
45
- @boundsType()
46
- public paragraphIndent: __Number
61
+ @boundsType(0)
62
+ public paraIndent: __Number
47
63
 
48
- @boundsType()
49
- public paragraphSpacing: __Number
64
+ @boundsType(0)
65
+ public paraSpacing: __Number
66
+
67
+ @boundsType('left')
68
+ public textAlign: ITextAlign
69
+
70
+ @boundsType('top')
71
+ public verticalAlign: IVerticalAlign
72
+
73
+ @boundsType('show')
74
+ public textOverflow: IOverflow | string
75
+
76
+ public get textDrawData(): ITextDrawData {
77
+ this.__layout.checkUpdate()
78
+ return this.__.__textDrawData
79
+ }
50
80
 
51
81
  constructor(data?: ITextInputData) {
52
82
  super(data)
53
83
  }
54
84
 
85
+ public __drawHitPath(canvas: ILeaferCanvas): void {
86
+ const { __lineHeight, __baseLine, __textDrawData: data } = this.__
87
+ canvas.beginPath()
88
+ data.rows.forEach(row => canvas.rect(row.x, row.y - __baseLine, row.width, __lineHeight))
89
+ }
90
+
55
91
  public __drawPathByData(drawer: IPathDrawer, _data: IPathCommandData): void {
56
- const { width, height } = this.__
57
- drawer.rect(0, 0, width, height)
92
+ const { x, y, width, height } = this.__layout.boxBounds
93
+ drawer.rect(x, y, width, height)
94
+ }
95
+
96
+ public __drawRenderPath(canvas: ILeaferCanvas): void {
97
+ canvas.font = this.__.__font
98
+ }
99
+
100
+ public __updateTextDrawData(): void {
101
+ const data = this.__
102
+ data.__textDrawData = TextConvert.getDrawData(data.text, this.__)
103
+
58
104
  }
59
105
 
60
106
  public __updateBoxBounds(): void {
61
- const { fontFamily, fontSize, fontWeight, italic, textCase, lineHeight } = this.__
62
- const b = this.__layout.boxBounds
63
107
 
64
- this.__.__font = Platform.canvas.font = `${italic ? 'italic' : ''} ${textCase === 'small-caps' ? 'small-caps' : 'normal'} ${fontWeight ? fontWeight : 'normal'} ${fontSize}px/${lineHeight ? lineHeight : fontSize}px ${fontFamily}`
65
- const width = Platform.canvas.measureText(this.content).width
66
- const height = fontSize
108
+ const data = this.__
109
+ const layout = this.__layout
110
+ const { width, height, lineHeight, letterSpacing, fontFamily, fontSize, fontWeight, italic, textCase } = data
111
+
112
+ // compute
113
+
114
+ data.__lineHeight = UnitConvert.number(lineHeight, fontSize)
115
+ data.__letterSpacing = UnitConvert.number(letterSpacing, fontSize)
116
+ data.__baseLine = data.__lineHeight - (data.__lineHeight - fontSize * 0.7) / 2
117
+ data.__font = `${italic ? 'italic ' : ''}${textCase === 'small-caps' ? 'small-caps ' : ''}${fontWeight !== 'normal' ? fontWeight + ' ' : ''}${fontSize}px ${fontFamily}`
118
+
119
+ this.__updateTextDrawData()
120
+
121
+ const { bounds } = data.__textDrawData
122
+ const b = layout.boxBounds
123
+
124
+ if (data.__lineHeight < fontSize) spread(bounds, fontSize / 2)
125
+
126
+ if (width && height) {
127
+ super.__updateBoxBounds()
128
+ } else {
129
+ b.x = width ? 0 : bounds.x
130
+ b.y = height ? 0 : bounds.y
131
+ b.width = width ? width : bounds.width
132
+ b.height = height ? height : bounds.height
133
+ }
134
+
135
+ const contentBounds = includes(b, bounds) ? b : bounds
136
+ if (contentBounds !== layout.contentBounds) {
137
+ layout.contentBounds = contentBounds
138
+ layout.renderChanged = true
139
+ }
140
+
141
+ }
142
+
143
+ public __updateRenderSpread(): number {
144
+ let width = super.__updateRenderSpread()
145
+ if (!width) width = this.__layout.boxBounds === this.__layout.contentBounds ? 0 : 1
146
+ return width
147
+ }
67
148
 
68
- b.x = 0
69
- b.y = -fontSize * 0.75
70
- b.width = width
71
- b.height = height
149
+ public __updateRenderBounds(): void {
150
+ copyAndSpread(this.__layout.renderBounds, this.__layout.contentBounds, this.__layout.renderSpread)
72
151
  }
73
152
 
74
153
  }
package/src/UI.ts CHANGED
@@ -1,12 +1,14 @@
1
- import { ILeaferCanvas, IPathDrawer, IPathCommandData, IMatrixData, IBoundsData, __Number, __Boolean, __String } from '@leafer/interface'
2
- import { Leaf, PathHelper, affectEventBoundsType, surfaceType, dataType, positionType, boundsType, pathType, scaleType, rotationType, opacityType, sortType, dataProcessor, useModule, rewrite, rewriteAble } from '@leafer/core'
1
+ import { ILeaferCanvas, IPathDrawer, IPathCommandData, IHitType, __Number, __Boolean, __String, IPathString } from '@leafer/interface'
2
+ import { Leaf, PathDrawer, surfaceType, dataType, positionType, boundsType, pathType, scaleType, rotationType, opacityType, sortType, maskType, dataProcessor, useModule, rewrite, rewriteAble, UICreator, PathCorner, hitType, strokeType, PathConvert } from '@leafer/core'
3
3
 
4
- import { IUI, IShadowEffect, IBlurEffect, IPaint, IStrokeAlign, IStrokeJoin, IStrokeCap, IBlendMode, IPaintString, IDashPatternString, IShadowString, IGrayscaleEffect, IUIData, IGroup, IStrokeWidthString, ICornerRadiusString } from '@leafer-ui/interface'
4
+ import { IUI, IShadowEffect, IBlurEffect, IPaint, IStrokeAlign, IStrokeJoin, IStrokeCap, IBlendMode, IPaintString, IDashPatternString, IShadowString, IGrayscaleEffect, IUIData, IGroup, IStrokeWidthString, ICornerRadiusString, IUITagInputData, IUIInputData } from '@leafer-ui/interface'
5
5
  import { effectType } from '@leafer-ui/decorator'
6
6
 
7
7
  import { UIData } from '@leafer-ui/data'
8
8
  import { UIBounds, UIHit, UIRender } from '@leafer-ui/display-module'
9
9
 
10
+ import { Paint } from '@leafer-ui/external'
11
+
10
12
 
11
13
  @useModule(UIBounds)
12
14
  @useModule(UIHit)
@@ -14,11 +16,9 @@ import { UIBounds, UIHit, UIRender } from '@leafer-ui/display-module'
14
16
  @rewriteAble()
15
17
  export class UI extends Leaf implements IUI {
16
18
 
17
-
18
19
  @dataProcessor(UIData)
19
20
  public __: IUIData
20
21
 
21
- public root?: IGroup
22
22
  public parent?: IGroup
23
23
 
24
24
  // ---
@@ -35,15 +35,24 @@ export class UI extends Leaf implements IUI {
35
35
 
36
36
 
37
37
  // layer
38
+ @surfaceType('pass-through')
39
+ public blendMode: IBlendMode
40
+
38
41
  @opacityType(1)
39
42
  public opacity: __Number
40
43
 
41
44
  @opacityType(true)
42
45
  public visible: __Boolean
43
46
 
47
+ @maskType(false)
48
+ public isMask: __Boolean
49
+
44
50
  @sortType(0)
45
51
  public zIndex: __Number
46
52
 
53
+ @dataType()
54
+ public locked: __Boolean
55
+
47
56
 
48
57
  // position
49
58
  @positionType(0)
@@ -79,21 +88,28 @@ export class UI extends Leaf implements IUI {
79
88
  @rotationType(0)
80
89
  public skewY: __Number
81
90
 
91
+
92
+ @dataType(false)
82
93
  public draggable: __Boolean
83
94
 
84
- // ---
95
+ // hit
96
+ @hitType(true)
97
+ public hittable: __Boolean
85
98
 
99
+ @hitType('path')
100
+ public hitFill: IHitType
86
101
 
87
- // layer
102
+ @strokeType('path')
103
+ public hitStroke: IHitType
88
104
 
89
- @surfaceType() // "pass-through"
90
- public blendMode: IBlendMode
105
+ @hitType(true)
106
+ public hitChildren: __Boolean
91
107
 
92
- @boundsType()
93
- public mask: __Boolean
108
+ @hitType(true)
109
+ public hitSelf: __Boolean
110
+
111
+ // ---
94
112
 
95
- @dataType()
96
- public locked: __Boolean
97
113
 
98
114
  // fill
99
115
 
@@ -102,28 +118,28 @@ export class UI extends Leaf implements IUI {
102
118
 
103
119
  // stroke
104
120
 
105
- @affectEventBoundsType()
121
+ @strokeType()
106
122
  public stroke: IPaint | IPaint[] | IPaintString
107
123
 
108
- @affectEventBoundsType('center')
124
+ @strokeType('inside')
109
125
  public strokeAlign: IStrokeAlign
110
126
 
111
- @affectEventBoundsType(1)
127
+ @strokeType(1)
112
128
  public strokeWidth: number | number[] | IStrokeWidthString
113
129
 
114
- @surfaceType('none')
130
+ @strokeType('none')
115
131
  public strokeCap: IStrokeCap
116
132
 
117
- @surfaceType('miter')
133
+ @strokeType('miter')
118
134
  public strokeJoin: IStrokeJoin
119
135
 
120
- @surfaceType()
136
+ @strokeType()
121
137
  public dashPattern: __Number[] | IDashPatternString
122
138
 
123
- @surfaceType()
139
+ @strokeType()
124
140
  public dashOffset: __Number
125
141
 
126
- @surfaceType(10)
142
+ @strokeType(10)
127
143
  public miterLimit: __Number
128
144
 
129
145
 
@@ -153,23 +169,43 @@ export class UI extends Leaf implements IUI {
153
169
  public grayscale: __Number | IGrayscaleEffect
154
170
 
155
171
 
156
- // now transform
172
+ constructor(data?: IUIInputData) {
173
+ super(data)
174
+ }
175
+
176
+
177
+ public set(data: IUITagInputData): void {
178
+ Object.assign(this, data)
179
+ }
157
180
 
158
- public get worldTransform(): IMatrixData { return this.__layout.getTransform('world') }
181
+ public get(): IUITagInputData {
182
+ return this.__.__getInputData()
183
+ }
159
184
 
160
- public get relativeTransform(): IMatrixData { return this.__layout.getTransform('relative') }
161
185
 
162
- // now bounds
186
+ public getPath(curve?: boolean): IPathCommandData {
187
+ const path = this.__.path
188
+ if (!path) return []
189
+ return curve ? PathConvert.toCanvasData(path, true) : path
190
+ }
163
191
 
164
- public get worldBoxBounds(): IBoundsData { return this.__layout.getBounds('world', 'box') }
192
+ public getPathString(curve?: boolean): IPathString {
193
+ return PathConvert.stringify(this.getPath(curve))
194
+ }
165
195
 
166
- public get worldRenderBounds(): IBoundsData { return this.__layout.getBounds('world', 'render') }
167
196
 
197
+ public __onUpdateSize(): void {
198
+ if (this.__.__input) {
199
+ const { fill, stroke } = this.__.__input
200
+ if (fill) Paint.computeFill(this)
201
+ if (stroke) Paint.computeStroke(this)
202
+ }
203
+ }
168
204
 
169
205
  public __updateRenderPath(): void {
170
206
  if (this.__.path) {
171
207
  const { __: data } = this
172
- data.__pathForRender = data.cornerRadius ? PathHelper.smoothCorner(data.path, data.cornerRadius, data.cornerSmoothing) : data.path
208
+ data.__pathForRender = data.cornerRadius ? PathCorner.smooth(data.path, data.cornerRadius, data.cornerSmoothing) : data.path
173
209
  }
174
210
  }
175
211
 
@@ -183,7 +219,11 @@ export class UI extends Leaf implements IUI {
183
219
  this.__drawPathByData(canvas, this.__.path)
184
220
  }
185
221
 
186
- @rewrite(PathHelper.drawData)
222
+ @rewrite(PathDrawer.drawPathByData)
187
223
  public __drawPathByData(_drawer: IPathDrawer, _data: IPathCommandData): void { }
188
224
 
225
+ static one(data: IUITagInputData, x?: number, y?: number, width?: number, height?: number): IUI {
226
+ return UICreator.get(data.tag || this.prototype.__tag, data, x, y, width, height) as IUI
227
+ }
228
+
189
229
  }
package/src/index.ts CHANGED
@@ -1,13 +1,22 @@
1
1
  export { UI } from './UI'
2
+
2
3
  export { Group } from './Group'
4
+ export { Box } from './Box'
3
5
  export { Frame } from './Frame'
6
+
4
7
  export { Rect } from './Rect'
5
8
  export { Ellipse } from './Ellipse'
6
9
  export { Polygon } from './Polygon'
7
10
  export { Star } from './Star'
8
11
  export { Line } from './Line'
9
- export { Path } from './Path'
10
- export { Vector } from './Vector'
11
- export { Text } from './Text'
12
+
12
13
  export { Image } from './Image'
14
+ export { Canvas } from './Canvas'
15
+
16
+ export { Text } from './Text'
17
+
18
+ export { Path } from './Path'
19
+ export { Pen } from './Pen'
20
+
21
+
13
22
 
package/src/Vector.ts DELETED
@@ -1,26 +0,0 @@
1
- import { dataProcessor, pathType, registerUI } from '@leafer/core'
2
-
3
- import { IVectorPath, IVectorPathString, IVector, IVectorData, IVectorInputData } from '@leafer-ui/interface'
4
- import { VectorData } from '@leafer-ui/data'
5
-
6
- import { Group } from './Group'
7
-
8
-
9
- @registerUI()
10
- export class Vector extends Group implements IVector {
11
-
12
- @dataProcessor(VectorData)
13
- public __: IVectorData
14
-
15
- @pathType()
16
- public paths: IVectorPath[] | IVectorPathString
17
-
18
- constructor(data?: IVectorInputData) {
19
- super(data)
20
- }
21
-
22
- public __updatePath(): void {
23
-
24
- }
25
-
26
- }