@leafer/canvas-web 1.0.0-beta.15 → 1.0.0-beta.16
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 +4 -3
- package/src/LeaferCanvas.ts +194 -0
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leafer/canvas-web",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.16",
|
|
4
4
|
"description": "@leafer/canvas-web",
|
|
5
5
|
"author": "Chao (Leafer) Wan",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "src/index.ts",
|
|
8
8
|
"types": "types/index.d.ts",
|
|
9
9
|
"files": [
|
|
10
|
+
"src",
|
|
10
11
|
"types",
|
|
11
12
|
"dist"
|
|
12
13
|
],
|
|
@@ -21,9 +22,9 @@
|
|
|
21
22
|
"leaferjs"
|
|
22
23
|
],
|
|
23
24
|
"dependencies": {
|
|
24
|
-
"@leafer/core": "1.0.0-beta.
|
|
25
|
+
"@leafer/core": "1.0.0-beta.16"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
|
-
"@leafer/interface": "1.0.0-beta.
|
|
28
|
+
"@leafer/interface": "1.0.0-beta.16"
|
|
28
29
|
}
|
|
29
30
|
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { IAutoBounds, ISizeData, IScreenSizeData, IResizeEventListener, ICursorType } from '@leafer/interface'
|
|
2
|
+
import { LeaferCanvasBase, canvasSizeAttrs, ResizeEvent, DataHelper, Platform, Debug, Cursor } from '@leafer/core'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const debug = Debug.get('LeaferCanvas')
|
|
6
|
+
|
|
7
|
+
export class LeaferCanvas extends LeaferCanvasBase {
|
|
8
|
+
|
|
9
|
+
declare public view: HTMLCanvasElement
|
|
10
|
+
declare public parentView: HTMLElement
|
|
11
|
+
|
|
12
|
+
protected resizeObserver: ResizeObserver
|
|
13
|
+
protected autoBounds: IAutoBounds
|
|
14
|
+
protected resizeListener: IResizeEventListener
|
|
15
|
+
|
|
16
|
+
public init(): void {
|
|
17
|
+
const { view } = this.config
|
|
18
|
+
|
|
19
|
+
view ? this.__createViewFrom(view) : this.__createView()
|
|
20
|
+
const { style } = this.view
|
|
21
|
+
style.display || (style.display = 'block')
|
|
22
|
+
this.parentView = this.view.parentElement
|
|
23
|
+
|
|
24
|
+
if (Platform.syncDomFont && !this.parentView) { // fix: firefox default font
|
|
25
|
+
this.view.style.display = 'none'
|
|
26
|
+
document.body.appendChild(this.view)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
this.__createContext()
|
|
30
|
+
|
|
31
|
+
if (!this.autoLayout) this.resize(this.config as IScreenSizeData)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public set backgroundColor(color: string) { this.view.style.backgroundColor = color }
|
|
35
|
+
public get backgroundColor(): string { return this.view.style.backgroundColor }
|
|
36
|
+
|
|
37
|
+
public set hittable(hittable: boolean) { this.view.style.pointerEvents = hittable ? 'auto' : 'none' }
|
|
38
|
+
public get hittable() { return this.view.style.pointerEvents !== 'none' }
|
|
39
|
+
|
|
40
|
+
protected __createView(): void {
|
|
41
|
+
this.view = document.createElement('canvas')
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public setCursor(cursor: ICursorType | ICursorType[]): void {
|
|
45
|
+
const list: ICursorType[] = []
|
|
46
|
+
this.eachCursor(cursor, list)
|
|
47
|
+
if (typeof list[list.length - 1] === 'object') list.push('default')
|
|
48
|
+
this.view.style.cursor = list.map(item => (typeof item === 'object') ? `url(${item.url}) ${item.x || 0} ${item.y || 0}` : item).join(',')
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
protected eachCursor(cursor: ICursorType | ICursorType[], list: ICursorType[], level = 0): void {
|
|
52
|
+
level++
|
|
53
|
+
if (cursor instanceof Array) {
|
|
54
|
+
cursor.forEach(item => this.eachCursor(item, list, level))
|
|
55
|
+
} else {
|
|
56
|
+
const custom = typeof cursor === 'string' && Cursor.get(cursor)
|
|
57
|
+
if (custom && level < 2) {
|
|
58
|
+
this.eachCursor(custom, list, level)
|
|
59
|
+
} else {
|
|
60
|
+
list.push(cursor)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
protected __createViewFrom(inputView: string | object): void {
|
|
66
|
+
let find: unknown = (typeof inputView === 'string') ? document.getElementById(inputView) : inputView as HTMLElement
|
|
67
|
+
if (find) {
|
|
68
|
+
if (find instanceof HTMLCanvasElement) {
|
|
69
|
+
|
|
70
|
+
this.view = find
|
|
71
|
+
|
|
72
|
+
} else {
|
|
73
|
+
|
|
74
|
+
let parent = find as HTMLDivElement
|
|
75
|
+
if (find === window || find === document) {
|
|
76
|
+
const div = document.createElement('div')
|
|
77
|
+
const { style } = div
|
|
78
|
+
style.position = 'absolute'
|
|
79
|
+
style.top = style.bottom = style.left = style.right = '0px'
|
|
80
|
+
document.body.appendChild(div)
|
|
81
|
+
parent = div
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this.__createView()
|
|
85
|
+
const view = this.view
|
|
86
|
+
|
|
87
|
+
if (parent.hasChildNodes()) {
|
|
88
|
+
const { style } = view
|
|
89
|
+
style.position = 'absolute'
|
|
90
|
+
style.top = style.left = '0px'
|
|
91
|
+
parent.style.position || (parent.style.position = 'relative')
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
parent.appendChild(view)
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
debug.error(`no id: ${inputView}`)
|
|
98
|
+
this.__createView()
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public updateViewSize(): void {
|
|
103
|
+
const { width, height, pixelRatio } = this
|
|
104
|
+
|
|
105
|
+
const { style } = this.view
|
|
106
|
+
style.width = width + 'px'
|
|
107
|
+
style.height = height + 'px'
|
|
108
|
+
|
|
109
|
+
this.view.width = width * pixelRatio
|
|
110
|
+
this.view.height = height * pixelRatio
|
|
111
|
+
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public updateClientBounds(): void {
|
|
115
|
+
this.clientBounds = this.view.getBoundingClientRect()
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public startAutoLayout(autoBounds: IAutoBounds, listener: IResizeEventListener): void {
|
|
119
|
+
this.autoBounds = autoBounds
|
|
120
|
+
this.resizeListener = listener
|
|
121
|
+
try {
|
|
122
|
+
|
|
123
|
+
this.resizeObserver = new ResizeObserver((entries) => {
|
|
124
|
+
this.updateClientBounds()
|
|
125
|
+
for (const entry of entries) this.checkAutoBounds(entry.contentRect)
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
const parent = this.parentView
|
|
129
|
+
if (parent) {
|
|
130
|
+
this.resizeObserver.observe(parent)
|
|
131
|
+
this.checkAutoBounds(parent.getBoundingClientRect())
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
} catch {
|
|
135
|
+
|
|
136
|
+
this.imitateResizeObserver()
|
|
137
|
+
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
protected imitateResizeObserver(): void {
|
|
142
|
+
if (this.autoLayout) {
|
|
143
|
+
if (this.parentView) this.checkAutoBounds(this.parentView.getBoundingClientRect())
|
|
144
|
+
Platform.requestRender(this.imitateResizeObserver.bind(this))
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
protected checkAutoBounds(parentSize: ISizeData): void {
|
|
149
|
+
const view = this.view
|
|
150
|
+
const { x, y, width, height } = this.autoBounds.getBoundsFrom(parentSize)
|
|
151
|
+
if (width !== this.width || height !== this.height) {
|
|
152
|
+
const { style } = view
|
|
153
|
+
const { pixelRatio } = this
|
|
154
|
+
style.marginLeft = x + 'px'
|
|
155
|
+
style.marginTop = y + 'px'
|
|
156
|
+
const size = { width, height, pixelRatio }
|
|
157
|
+
const oldSize = {} as IScreenSizeData
|
|
158
|
+
DataHelper.copyAttrs(oldSize, this, canvasSizeAttrs)
|
|
159
|
+
this.resize(size)
|
|
160
|
+
if (this.width !== undefined) this.resizeListener(new ResizeEvent(size, oldSize))
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
public stopAutoLayout(): void {
|
|
165
|
+
this.autoLayout = false
|
|
166
|
+
this.resizeListener = null
|
|
167
|
+
if (this.resizeObserver) {
|
|
168
|
+
this.resizeObserver.disconnect()
|
|
169
|
+
this.resizeObserver = null
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
public unrealCanvas(): void { // App needs to use
|
|
174
|
+
if (!this.unreal && this.parentView) {
|
|
175
|
+
const view = this.view
|
|
176
|
+
if (view) view.remove()
|
|
177
|
+
|
|
178
|
+
this.view = this.parentView as HTMLCanvasElement
|
|
179
|
+
this.unreal = true
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
public destroy(): void {
|
|
184
|
+
if (this.view) {
|
|
185
|
+
this.stopAutoLayout()
|
|
186
|
+
if (!this.unreal) {
|
|
187
|
+
const view = this.view
|
|
188
|
+
if (view.parentElement) view.remove()
|
|
189
|
+
}
|
|
190
|
+
super.destroy()
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
}
|