@leafer-ui/display 1.0.0-rc.9 → 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 +8 -8
- package/src/Box.ts +58 -37
- package/src/Canvas.ts +17 -18
- package/src/Ellipse.ts +3 -3
- package/src/Frame.ts +8 -5
- package/src/Group.ts +24 -31
- package/src/Image.ts +1 -1
- package/src/Leafer.ts +447 -0
- package/src/Line.ts +19 -30
- package/src/Path.ts +4 -21
- package/src/Pen.ts +18 -8
- package/src/Polygon.ts +3 -6
- package/src/Rect.ts +2 -6
- package/src/Star.ts +2 -2
- package/src/Text.ts +34 -29
- package/src/UI.ts +258 -92
- package/src/index.ts +1 -0
- package/types/index.d.ts +252 -118
- package/src/Arrow.ts +0 -24
package/src/Leafer.ts
ADDED
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
import { ILeaferCanvas, IRenderer, ILayouter, ISelector, IWatcher, IInteraction, ILeaferConfig, ICanvasManager, IHitCanvasManager, IAutoBounds, IScreenSizeData, IResizeEvent, IEventListenerId, ITimer, IValue, IObject, IControl, IPointData, ILeaferType, ICursorType, IBoundsData, INumber, IZoomType, IFourNumber, IBounds, IClientPointData } from '@leafer/interface'
|
|
2
|
+
import { AutoBounds, LayoutEvent, ResizeEvent, LeaferEvent, CanvasManager, ImageManager, DataHelper, Creator, Run, Debug, RenderEvent, registerUI, boundsType, canvasSizeAttrs, dataProcessor, WaitHelper, WatchEvent, Bounds, LeafList } from '@leafer/core'
|
|
3
|
+
|
|
4
|
+
import { ILeaferInputData, ILeaferData, IFunction, IUIInputData, ILeafer, IApp, IEditorBase } from '@leafer-ui/interface'
|
|
5
|
+
import { LeaferData } from '@leafer-ui/data'
|
|
6
|
+
import { Group } from './Group'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
const debug = Debug.get('Leafer')
|
|
10
|
+
|
|
11
|
+
@registerUI()
|
|
12
|
+
export class Leafer extends Group implements ILeafer {
|
|
13
|
+
|
|
14
|
+
static list = new LeafList() // 所有leafer实例
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
public get __tag() { return 'Leafer' }
|
|
18
|
+
|
|
19
|
+
@dataProcessor(LeaferData)
|
|
20
|
+
declare public __: ILeaferData
|
|
21
|
+
|
|
22
|
+
@boundsType()
|
|
23
|
+
declare public pixelRatio?: INumber
|
|
24
|
+
|
|
25
|
+
public get isApp(): boolean { return false }
|
|
26
|
+
public get app(): ILeafer { return this.parent || this }
|
|
27
|
+
|
|
28
|
+
public get isLeafer(): boolean { return true }
|
|
29
|
+
|
|
30
|
+
declare public parent?: IApp
|
|
31
|
+
|
|
32
|
+
public running: boolean
|
|
33
|
+
public created: boolean
|
|
34
|
+
public ready: boolean
|
|
35
|
+
public viewReady: boolean
|
|
36
|
+
public viewCompleted: boolean
|
|
37
|
+
public get imageReady(): boolean { return this.viewReady && ImageManager.isComplete }
|
|
38
|
+
public get layoutLocked() { return !this.layouter.running }
|
|
39
|
+
|
|
40
|
+
public transforming: boolean
|
|
41
|
+
|
|
42
|
+
public view: unknown
|
|
43
|
+
|
|
44
|
+
// manager
|
|
45
|
+
public canvas: ILeaferCanvas
|
|
46
|
+
public renderer: IRenderer
|
|
47
|
+
|
|
48
|
+
public watcher: IWatcher
|
|
49
|
+
public layouter: ILayouter
|
|
50
|
+
|
|
51
|
+
public selector?: ISelector
|
|
52
|
+
public interaction?: IInteraction
|
|
53
|
+
|
|
54
|
+
public canvasManager: ICanvasManager
|
|
55
|
+
public hitCanvasManager?: IHitCanvasManager
|
|
56
|
+
|
|
57
|
+
// plugin
|
|
58
|
+
public editor: IEditorBase
|
|
59
|
+
|
|
60
|
+
public userConfig: ILeaferConfig
|
|
61
|
+
public config: ILeaferConfig = {
|
|
62
|
+
type: 'design',
|
|
63
|
+
start: true,
|
|
64
|
+
hittable: true,
|
|
65
|
+
smooth: true,
|
|
66
|
+
lazySpeard: 100,
|
|
67
|
+
zoom: {
|
|
68
|
+
min: 0.01,
|
|
69
|
+
max: 256
|
|
70
|
+
},
|
|
71
|
+
move: {
|
|
72
|
+
holdSpaceKey: true,
|
|
73
|
+
holdMiddleKey: true,
|
|
74
|
+
autoDistance: 2
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public autoLayout?: IAutoBounds
|
|
79
|
+
public lazyBounds: IBounds
|
|
80
|
+
|
|
81
|
+
public get FPS(): number { return this.renderer ? this.renderer.FPS : 60 }
|
|
82
|
+
public get cursorPoint(): IPointData { return (this.interaction && this.interaction.hoverData) || { x: this.width / 2, y: this.height / 2 } }
|
|
83
|
+
public get clientBounds(): IBoundsData { return this.canvas && this.canvas.getClientBounds() }
|
|
84
|
+
public leafs = 0
|
|
85
|
+
|
|
86
|
+
public __eventIds: IEventListenerId[] = []
|
|
87
|
+
protected __startTimer: ITimer
|
|
88
|
+
protected __controllers: IControl[] = []
|
|
89
|
+
|
|
90
|
+
protected __initWait: IFunction[] // assign in waitInit()
|
|
91
|
+
protected __readyWait: IFunction[] = []
|
|
92
|
+
protected __viewReadyWait: IFunction[] = []
|
|
93
|
+
protected __viewCompletedWait: IFunction[] = []
|
|
94
|
+
public __nextRenderWait: IFunction[] = []
|
|
95
|
+
|
|
96
|
+
constructor(userConfig?: ILeaferConfig, data?: ILeaferInputData) {
|
|
97
|
+
super(data)
|
|
98
|
+
this.userConfig = userConfig
|
|
99
|
+
if (userConfig && (userConfig.view || userConfig.width)) this.init(userConfig)
|
|
100
|
+
Leafer.list.add(this)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public init(userConfig?: ILeaferConfig, parentApp?: IApp): void {
|
|
104
|
+
if (this.canvas) return
|
|
105
|
+
|
|
106
|
+
this.__setLeafer(this)
|
|
107
|
+
if (userConfig) DataHelper.assign(this.config, userConfig)
|
|
108
|
+
|
|
109
|
+
let start: boolean
|
|
110
|
+
const { config } = this
|
|
111
|
+
|
|
112
|
+
this.initType(config.type) // LeaferType
|
|
113
|
+
|
|
114
|
+
// render / layout
|
|
115
|
+
const canvas = this.canvas = Creator.canvas(config)
|
|
116
|
+
this.__controllers.push(
|
|
117
|
+
this.renderer = Creator.renderer(this, canvas, config),
|
|
118
|
+
this.watcher = Creator.watcher(this, config),
|
|
119
|
+
this.layouter = Creator.layouter(this, config)
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
if (this.isApp) this.__setApp()
|
|
123
|
+
this.__checkAutoLayout(config)
|
|
124
|
+
this.view = canvas.view
|
|
125
|
+
|
|
126
|
+
// interaction / manager
|
|
127
|
+
if (parentApp) {
|
|
128
|
+
this.__bindApp(parentApp)
|
|
129
|
+
start = parentApp.running
|
|
130
|
+
} else {
|
|
131
|
+
this.selector = Creator.selector(this)
|
|
132
|
+
this.interaction = Creator.interaction(this, canvas, this.selector, config)
|
|
133
|
+
|
|
134
|
+
if (this.interaction) {
|
|
135
|
+
this.__controllers.unshift(this.interaction)
|
|
136
|
+
this.hitCanvasManager = Creator.hitCanvasManager()
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
this.canvasManager = new CanvasManager()
|
|
140
|
+
|
|
141
|
+
start = config.start
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
this.hittable = config.hittable
|
|
145
|
+
this.fill = config.fill
|
|
146
|
+
this.canvasManager.add(canvas)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
this.__listenEvents()
|
|
150
|
+
|
|
151
|
+
if (start) this.__startTimer = setTimeout(this.start.bind(this))
|
|
152
|
+
|
|
153
|
+
WaitHelper.run(this.__initWait)
|
|
154
|
+
this.onInit() // can rewrite init event
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public onInit(): void { }
|
|
158
|
+
|
|
159
|
+
public initType(_type: ILeaferType): void { } // rewrite in @leafer-ui/type
|
|
160
|
+
|
|
161
|
+
public set(data: IUIInputData): void {
|
|
162
|
+
this.waitInit(() => { super.set(data) })
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
public start(): void {
|
|
166
|
+
clearTimeout(this.__startTimer)
|
|
167
|
+
if (!this.running && this.canvas) {
|
|
168
|
+
this.ready ? this.emitLeafer(LeaferEvent.RESTART) : this.emitLeafer(LeaferEvent.START)
|
|
169
|
+
this.__controllers.forEach(item => item.start())
|
|
170
|
+
if (!this.isApp) this.renderer.render()
|
|
171
|
+
this.running = true
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
public stop(): void {
|
|
176
|
+
clearTimeout(this.__startTimer)
|
|
177
|
+
if (this.running && this.canvas) {
|
|
178
|
+
this.__controllers.forEach(item => item.stop())
|
|
179
|
+
this.running = false
|
|
180
|
+
this.emitLeafer(LeaferEvent.STOP)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
public unlockLayout(): void {
|
|
185
|
+
this.layouter.start()
|
|
186
|
+
this.updateLayout()
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
public lockLayout(): void {
|
|
190
|
+
this.updateLayout()
|
|
191
|
+
this.layouter.stop()
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
public resize(size: IScreenSizeData): void {
|
|
195
|
+
const data = DataHelper.copyAttrs({}, size, canvasSizeAttrs)
|
|
196
|
+
Object.keys(data).forEach(key => (this as any)[key] = data[key])
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
override forceRender(bounds?: IBoundsData): void {
|
|
200
|
+
this.renderer.addBlock(bounds ? new Bounds(bounds) : this.canvas.bounds)
|
|
201
|
+
if (this.viewReady) this.renderer.update()
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
public updateCursor(cursor?: ICursorType): void {
|
|
205
|
+
const i = this.interaction
|
|
206
|
+
if (i) cursor ? i.setCursor(cursor) : i.updateCursor()
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
public updateLazyBounds(): void {
|
|
210
|
+
this.lazyBounds = this.canvas.bounds.clone().spread(this.config.lazySpeard)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
protected __doResize(size: IScreenSizeData): void {
|
|
214
|
+
const { canvas } = this
|
|
215
|
+
if (!canvas || canvas.isSameSize(size)) return
|
|
216
|
+
const old = DataHelper.copyAttrs({}, this.canvas, canvasSizeAttrs) as IScreenSizeData
|
|
217
|
+
canvas.resize(size)
|
|
218
|
+
this.updateLazyBounds()
|
|
219
|
+
this.__onResize(new ResizeEvent(size, old))
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
protected __onResize(event: IResizeEvent): void {
|
|
223
|
+
this.emitEvent(event)
|
|
224
|
+
DataHelper.copyAttrs(this.__, event, canvasSizeAttrs)
|
|
225
|
+
if (!event.width || !event.height) debug.warn('w = 0 or h = 0')
|
|
226
|
+
setTimeout(() => { if (this.canvasManager) this.canvasManager.clearRecycled() }, 0)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
protected __setApp(): void { }
|
|
230
|
+
|
|
231
|
+
protected __bindApp(app: IApp): void {
|
|
232
|
+
this.selector = app.selector
|
|
233
|
+
this.interaction = app.interaction
|
|
234
|
+
|
|
235
|
+
this.canvasManager = app.canvasManager
|
|
236
|
+
this.hitCanvasManager = app.hitCanvasManager
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
public __setLeafer(leafer: ILeafer): void {
|
|
240
|
+
this.leafer = leafer
|
|
241
|
+
this.__level = 1
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
protected __checkAutoLayout(config: ILeaferConfig): void {
|
|
245
|
+
if (!config.width || !config.height) {
|
|
246
|
+
this.autoLayout = new AutoBounds(config)
|
|
247
|
+
this.canvas.startAutoLayout(this.autoLayout, this.__onResize.bind(this))
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
override __setAttr(attrName: string, newValue: IValue): boolean {
|
|
252
|
+
if (this.canvas) {
|
|
253
|
+
if (canvasSizeAttrs.includes(attrName)) {
|
|
254
|
+
if (!newValue) debug.warn(attrName + ' is 0')
|
|
255
|
+
this.__changeCanvasSize(attrName, newValue as number)
|
|
256
|
+
} else if (attrName === 'fill') {
|
|
257
|
+
this.__changeFill(newValue as string)
|
|
258
|
+
} else if (attrName === 'hittable') {
|
|
259
|
+
if (!this.parent) this.canvas.hittable = newValue as boolean
|
|
260
|
+
} else if (attrName === 'zIndex') {
|
|
261
|
+
this.canvas.zIndex = newValue as any
|
|
262
|
+
setTimeout(() => this.parent && this.parent.__updateSortChildren())
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return super.__setAttr(attrName, newValue)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
override __getAttr(attrName: string): IValue {
|
|
269
|
+
if (this.canvas && canvasSizeAttrs.includes(attrName)) return this.canvas[attrName]
|
|
270
|
+
return super.__getAttr(attrName)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
protected __changeCanvasSize(attrName: string, newValue: number): void {
|
|
274
|
+
const data = DataHelper.copyAttrs({}, this.canvas, canvasSizeAttrs)
|
|
275
|
+
data[attrName] = (this.config as IObject)[attrName] = newValue
|
|
276
|
+
if (newValue) this.canvas.stopAutoLayout()
|
|
277
|
+
this.__doResize(data as IScreenSizeData)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
protected __changeFill(newValue: string): void {
|
|
281
|
+
this.config.fill = newValue as string
|
|
282
|
+
if (this.canvas.allowBackgroundColor) {
|
|
283
|
+
this.canvas.backgroundColor = newValue as string
|
|
284
|
+
} else {
|
|
285
|
+
this.forceRender()
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
protected __onCreated(): void {
|
|
290
|
+
this.created = true
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
protected __onReady(): void {
|
|
294
|
+
if (this.ready) return
|
|
295
|
+
this.ready = true
|
|
296
|
+
this.emitLeafer(LeaferEvent.BEFORE_READY)
|
|
297
|
+
this.emitLeafer(LeaferEvent.READY)
|
|
298
|
+
this.emitLeafer(LeaferEvent.AFTER_READY)
|
|
299
|
+
WaitHelper.run(this.__readyWait)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
protected __onViewReady(): void {
|
|
303
|
+
if (this.viewReady) return
|
|
304
|
+
this.viewReady = true
|
|
305
|
+
this.emitLeafer(LeaferEvent.VIEW_READY)
|
|
306
|
+
WaitHelper.run(this.__viewReadyWait)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
protected __onNextRender(): void {
|
|
310
|
+
if (this.viewReady) {
|
|
311
|
+
WaitHelper.run(this.__nextRenderWait)
|
|
312
|
+
|
|
313
|
+
const { imageReady } = this
|
|
314
|
+
if (imageReady && !this.viewCompleted) this.__checkViewCompleted()
|
|
315
|
+
if (!imageReady) this.viewCompleted = false
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
protected __checkViewCompleted(emit: boolean = true): void {
|
|
320
|
+
this.nextRender(() => {
|
|
321
|
+
if (this.imageReady) {
|
|
322
|
+
if (emit) this.emitLeafer(LeaferEvent.VIEW_COMPLETED)
|
|
323
|
+
WaitHelper.run(this.__viewCompletedWait)
|
|
324
|
+
this.viewCompleted = true
|
|
325
|
+
}
|
|
326
|
+
})
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
protected __onWatchData(): void {
|
|
330
|
+
if (this.watcher.childrenChanged && this.interaction) {
|
|
331
|
+
this.nextRender(() => this.interaction.updateCursor())
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
public waitInit(item: IFunction, bind?: IObject): void {
|
|
336
|
+
if (bind) item = item.bind(bind)
|
|
337
|
+
if (!this.__initWait) this.__initWait = [] // set() use
|
|
338
|
+
this.canvas ? item() : this.__initWait.push(item)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
public waitReady(item: IFunction, bind?: IObject): void {
|
|
342
|
+
if (bind) item = item.bind(bind)
|
|
343
|
+
this.ready ? item() : this.__readyWait.push(item)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
public waitViewReady(item: IFunction, bind?: IObject): void {
|
|
347
|
+
if (bind) item = item.bind(bind)
|
|
348
|
+
this.viewReady ? item() : this.__viewReadyWait.push(item)
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
public waitViewCompleted(item: IFunction, bind?: IObject): void {
|
|
352
|
+
if (bind) item = item.bind(bind)
|
|
353
|
+
this.__viewCompletedWait.push(item)
|
|
354
|
+
if (this.viewCompleted) {
|
|
355
|
+
this.__checkViewCompleted(false)
|
|
356
|
+
} else {
|
|
357
|
+
if (!this.running) this.start()
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
public nextRender(item: IFunction, bind?: IObject, off?: 'off'): void {
|
|
362
|
+
if (bind) item = item.bind(bind)
|
|
363
|
+
const list = this.__nextRenderWait
|
|
364
|
+
if (off) {
|
|
365
|
+
for (let i = 0; i < list.length; i++) {
|
|
366
|
+
if (list[i] === item) { list.splice(i, 1); break }
|
|
367
|
+
}
|
|
368
|
+
} else {
|
|
369
|
+
list.push(item)
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// need view plugin
|
|
374
|
+
public zoom(_zoomType: IZoomType, _padding?: IFourNumber, _fixedScale?: boolean): IBoundsData { return undefined }
|
|
375
|
+
|
|
376
|
+
// interaction window rewrite
|
|
377
|
+
public getValidMove(moveX: number, moveY: number): IPointData { return { x: moveX, y: moveY } }
|
|
378
|
+
public getValidScale(changeScale: number): number { return changeScale }
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
public getWorldPointByClient(clientPoint: IClientPointData, updateClient?: boolean): IPointData {
|
|
382
|
+
return this.interaction && this.interaction.getLocal(clientPoint, updateClient)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
protected __checkUpdateLayout(): void {
|
|
386
|
+
this.__layout.update()
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
protected emitLeafer(type: string): void {
|
|
390
|
+
this.emitEvent(new LeaferEvent(type, this))
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
protected __listenEvents(): void {
|
|
394
|
+
const runId = Run.start('FirstCreate ' + this.innerName)
|
|
395
|
+
this.once(LeaferEvent.START, () => Run.end(runId))
|
|
396
|
+
this.once(LayoutEvent.START, () => this.updateLazyBounds())
|
|
397
|
+
this.once(LayoutEvent.END, () => this.__onReady())
|
|
398
|
+
this.once(RenderEvent.START, () => this.__onCreated())
|
|
399
|
+
this.once(RenderEvent.END, () => this.__onViewReady())
|
|
400
|
+
this.__eventIds.push(
|
|
401
|
+
this.on_(WatchEvent.DATA, this.__onWatchData, this),
|
|
402
|
+
this.on_(RenderEvent.NEXT, this.__onNextRender, this),
|
|
403
|
+
this.on_(LayoutEvent.CHECK_UPDATE, this.__checkUpdateLayout, this)
|
|
404
|
+
)
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
protected __removeListenEvents(): void {
|
|
408
|
+
this.off_(this.__eventIds)
|
|
409
|
+
this.__eventIds.length = 0
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
override destroy(sync?: boolean): void {
|
|
413
|
+
const doDestory = () => {
|
|
414
|
+
if (!this.destroyed) {
|
|
415
|
+
Leafer.list.remove(this)
|
|
416
|
+
try {
|
|
417
|
+
this.stop()
|
|
418
|
+
this.emitEvent(new LeaferEvent(LeaferEvent.END, this))
|
|
419
|
+
this.__removeListenEvents()
|
|
420
|
+
|
|
421
|
+
this.__controllers.forEach(item => {
|
|
422
|
+
if (!(this.parent && item === this.interaction)) item.destroy()
|
|
423
|
+
})
|
|
424
|
+
this.__controllers.length = 0
|
|
425
|
+
|
|
426
|
+
if (!this.parent) {
|
|
427
|
+
if (this.selector) this.selector.destroy()
|
|
428
|
+
if (this.hitCanvasManager) this.hitCanvasManager.destroy()
|
|
429
|
+
this.canvasManager.destroy()
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
this.canvas.destroy()
|
|
433
|
+
|
|
434
|
+
this.config.view = this.view = null
|
|
435
|
+
if (this.userConfig) this.userConfig.view = null
|
|
436
|
+
|
|
437
|
+
super.destroy()
|
|
438
|
+
|
|
439
|
+
setTimeout(() => { ImageManager.clearRecycled() }, 100)
|
|
440
|
+
} catch (e) {
|
|
441
|
+
debug.error(e)
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
sync ? doDestory() : setTimeout(doDestory)
|
|
446
|
+
}
|
|
447
|
+
}
|
package/src/Line.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { IPointData, INumber } from '@leafer/interface'
|
|
2
|
-
import { PathBounds, PathCommandDataHelper, PointHelper, boundsType, pathType, affectStrokeBoundsType, dataProcessor, registerUI,
|
|
2
|
+
import { PathBounds, PathCommandDataHelper, PointHelper, boundsType, pathType, affectStrokeBoundsType, dataProcessor, registerUI, getPointData } from '@leafer/core'
|
|
3
3
|
|
|
4
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
|
+
import { PathArrow } from '@leafer-ui/external'
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
const { moveTo, lineTo, drawPoints } = PathCommandDataHelper
|
|
@@ -13,7 +14,7 @@ const { toBounds } = PathBounds
|
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
@registerUI()
|
|
16
|
-
export class Line extends UI implements ILine {
|
|
17
|
+
export class Line extends UI implements ILine { // tip: rewrited Polygon
|
|
17
18
|
|
|
18
19
|
public get __tag() { return 'Line' }
|
|
19
20
|
|
|
@@ -21,20 +22,23 @@ export class Line extends UI implements ILine {
|
|
|
21
22
|
declare public __: ILineData
|
|
22
23
|
|
|
23
24
|
@affectStrokeBoundsType('center')
|
|
24
|
-
declare public strokeAlign
|
|
25
|
+
declare public strokeAlign?: IStrokeAlign
|
|
25
26
|
|
|
26
27
|
@boundsType(0)
|
|
27
|
-
declare public height
|
|
28
|
+
declare public height?: INumber
|
|
28
29
|
|
|
29
30
|
@pathType()
|
|
30
|
-
public points
|
|
31
|
+
public points?: number[]
|
|
31
32
|
|
|
32
33
|
@pathType(0)
|
|
33
|
-
public curve
|
|
34
|
+
public curve?: boolean | number
|
|
35
|
+
|
|
36
|
+
@pathType(false)
|
|
37
|
+
declare public closed?: boolean
|
|
34
38
|
|
|
35
39
|
public get toPoint(): IPointData {
|
|
36
40
|
const { width, rotation } = this.__
|
|
37
|
-
const to: IPointData =
|
|
41
|
+
const to: IPointData = getPointData()
|
|
38
42
|
|
|
39
43
|
if (width) to.x = width
|
|
40
44
|
if (rotation) rotate(to, rotation)
|
|
@@ -55,11 +59,12 @@ export class Line extends UI implements ILine {
|
|
|
55
59
|
|
|
56
60
|
public __updatePath(): void {
|
|
57
61
|
|
|
58
|
-
const
|
|
62
|
+
const data = this.__
|
|
63
|
+
const path: number[] = data.path = []
|
|
59
64
|
|
|
60
|
-
if (
|
|
65
|
+
if (data.points) {
|
|
61
66
|
|
|
62
|
-
drawPoints(path,
|
|
67
|
+
drawPoints(path, data.points, false, data.closed)
|
|
63
68
|
|
|
64
69
|
} else {
|
|
65
70
|
|
|
@@ -70,8 +75,10 @@ export class Line extends UI implements ILine {
|
|
|
70
75
|
}
|
|
71
76
|
|
|
72
77
|
public __updateRenderPath(): void {
|
|
73
|
-
|
|
74
|
-
|
|
78
|
+
const data = this.__
|
|
79
|
+
if (!this.pathInputed && data.points && data.curve) {
|
|
80
|
+
drawPoints(data.__pathForRender = [], data.points, data.curve, data.closed)
|
|
81
|
+
if (data.__useArrow) PathArrow.addArrows(this, false)
|
|
75
82
|
} else {
|
|
76
83
|
super.__updateRenderPath()
|
|
77
84
|
}
|
|
@@ -85,22 +92,4 @@ export class Line extends UI implements ILine {
|
|
|
85
92
|
}
|
|
86
93
|
}
|
|
87
94
|
|
|
88
|
-
public __scaleResize(scaleX: number, scaleY: number): void {
|
|
89
|
-
if (this.points) {
|
|
90
|
-
PathScaler.scalePoints(this.__.points, scaleX, scaleY)
|
|
91
|
-
this.points = this.__.points
|
|
92
|
-
} else {
|
|
93
|
-
|
|
94
|
-
if (this.__tag === 'Line') {
|
|
95
|
-
const point = this.toPoint
|
|
96
|
-
point.x *= scaleX
|
|
97
|
-
point.y *= scaleY
|
|
98
|
-
this.toPoint = point
|
|
99
|
-
} else {
|
|
100
|
-
// Polygon ...
|
|
101
|
-
super.__scaleResize(scaleX, scaleY)
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
95
|
}
|
package/src/Path.ts
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { PathBounds, dataProcessor, pathType, affectStrokeBoundsType, registerUI, PathScaler } from '@leafer/core'
|
|
1
|
+
import { dataProcessor, affectStrokeBoundsType, registerUI } from '@leafer/core'
|
|
3
2
|
|
|
4
|
-
import { IPath, IPathData, IPathInputData,
|
|
3
|
+
import { IPath, IPathData, IPathInputData, IStrokeAlign } from '@leafer-ui/interface'
|
|
5
4
|
import { PathData } from '@leafer-ui/data'
|
|
6
5
|
|
|
7
6
|
import { UI } from './UI'
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
const { toBounds } = PathBounds
|
|
11
|
-
|
|
12
9
|
@registerUI()
|
|
13
10
|
export class Path extends UI implements IPath {
|
|
14
11
|
|
|
@@ -17,26 +14,12 @@ export class Path extends UI implements IPath {
|
|
|
17
14
|
@dataProcessor(PathData)
|
|
18
15
|
declare public __: IPathData
|
|
19
16
|
|
|
20
|
-
@pathType()
|
|
21
|
-
public path: IPathCommandData | IPathString
|
|
22
|
-
|
|
23
|
-
@pathType()
|
|
24
|
-
public windingRule: IWindingRule
|
|
25
|
-
|
|
26
17
|
@affectStrokeBoundsType('center')
|
|
27
|
-
declare public strokeAlign
|
|
18
|
+
declare public strokeAlign?: IStrokeAlign
|
|
28
19
|
|
|
29
20
|
constructor(data?: IPathInputData) {
|
|
30
21
|
super(data)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
public __scaleResize(scaleX: number, scaleY: number): void {
|
|
34
|
-
PathScaler.scale(this.__.path, scaleX, scaleY)
|
|
35
|
-
this.path = this.__.path
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
public __updateBoxBounds(): void {
|
|
39
|
-
toBounds(this.__.path, this.__layout.boxBounds)
|
|
22
|
+
this.__.__pathInputed = 2
|
|
40
23
|
}
|
|
41
24
|
|
|
42
25
|
}
|
package/src/Pen.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PathCreator, dataProcessor, registerUI, useModule } from '@leafer/core'
|
|
1
|
+
import { PathCreator, dataProcessor, defineKey, registerUI, useModule } from '@leafer/core'
|
|
2
2
|
|
|
3
3
|
import { IPenData, IPenInputData, IPathInputData, IPathCommandData, IPath, IPen } from '@leafer-ui/interface'
|
|
4
4
|
import { PenData } from '@leafer-ui/data'
|
|
@@ -7,7 +7,7 @@ import { Group } from './Group'
|
|
|
7
7
|
import { Path } from './Path'
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
@useModule(PathCreator, ['beginPath'])
|
|
10
|
+
@useModule(PathCreator, ['set', 'beginPath', 'path'])
|
|
11
11
|
@registerUI()
|
|
12
12
|
export class Pen extends Group implements IPen {
|
|
13
13
|
|
|
@@ -18,7 +18,11 @@ export class Pen extends Group implements IPen {
|
|
|
18
18
|
|
|
19
19
|
public pathElement: IPath
|
|
20
20
|
public pathStyle: IPathInputData
|
|
21
|
-
|
|
21
|
+
|
|
22
|
+
@penPathType()
|
|
23
|
+
declare public path: IPathCommandData // use __path, readonly
|
|
24
|
+
|
|
25
|
+
public __path: IPathCommandData
|
|
22
26
|
|
|
23
27
|
constructor(data?: IPenInputData) {
|
|
24
28
|
super(data)
|
|
@@ -27,13 +31,13 @@ export class Pen extends Group implements IPen {
|
|
|
27
31
|
public setStyle(data: IPathInputData): Pen {
|
|
28
32
|
const path = this.pathElement = new Path(data)
|
|
29
33
|
this.pathStyle = data
|
|
30
|
-
this.
|
|
34
|
+
this.__path = path.path as IPathCommandData || (path.path = [])
|
|
31
35
|
this.add(path)
|
|
32
36
|
return this
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
public beginPath(): Pen {
|
|
36
|
-
this.
|
|
40
|
+
this.__path.length = 0
|
|
37
41
|
this.paint()
|
|
38
42
|
return this
|
|
39
43
|
}
|
|
@@ -72,13 +76,19 @@ export class Pen extends Group implements IPen {
|
|
|
72
76
|
|
|
73
77
|
public drawPoints(_points: number[], _curve?: boolean | number, _close?: boolean): Pen { return this }
|
|
74
78
|
|
|
79
|
+
public clearPath(): Pen { return this }
|
|
75
80
|
|
|
76
81
|
public paint(): void {
|
|
77
82
|
this.pathElement.forceUpdate('path')
|
|
78
83
|
}
|
|
79
84
|
|
|
80
|
-
public clear(): void {
|
|
81
|
-
this.removeAll(true)
|
|
82
|
-
}
|
|
83
85
|
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function penPathType() {
|
|
89
|
+
return (target: IPen, key: string) => {
|
|
90
|
+
defineKey(target, key, {
|
|
91
|
+
get() { return this.__path }
|
|
92
|
+
})
|
|
93
|
+
}
|
|
84
94
|
}
|
package/src/Polygon.ts
CHANGED
|
@@ -22,13 +22,13 @@ export class Polygon extends UI implements IPolygon {
|
|
|
22
22
|
declare public __: IPolygonData
|
|
23
23
|
|
|
24
24
|
@pathType(3)
|
|
25
|
-
sides
|
|
25
|
+
public sides?: INumber
|
|
26
26
|
|
|
27
27
|
@pathType()
|
|
28
|
-
points
|
|
28
|
+
public points?: number[]
|
|
29
29
|
|
|
30
30
|
@pathType(0)
|
|
31
|
-
curve
|
|
31
|
+
public curve?: boolean | number
|
|
32
32
|
|
|
33
33
|
constructor(data?: IPolygonInputData) {
|
|
34
34
|
super(data)
|
|
@@ -64,7 +64,4 @@ export class Polygon extends UI implements IPolygon {
|
|
|
64
64
|
@rewrite(line.__updateBoxBounds)
|
|
65
65
|
public __updateBoxBounds(): void { }
|
|
66
66
|
|
|
67
|
-
@rewrite(line.__scaleResize)
|
|
68
|
-
public __scaleResize(_scaleX: number, _scaleY: number): void { }
|
|
69
|
-
|
|
70
67
|
}
|