@operato/board 7.1.31 → 7.1.33

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.
Files changed (87) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/tsconfig.tsbuildinfo +1 -1
  3. package/package.json +14 -14
  4. package/.storybook/main.js +0 -3
  5. package/.storybook/server.mjs +0 -8
  6. package/demo/index-modeller.html +0 -112
  7. package/demo/index-player.html +0 -112
  8. package/demo/index-viewer.html +0 -112
  9. package/demo/index.html +0 -112
  10. package/src/component/3d.ts +0 -29
  11. package/src/component/chart-and-gauge.ts +0 -28
  12. package/src/component/container.ts +0 -63
  13. package/src/component/data-source.ts +0 -30
  14. package/src/component/etc.ts +0 -88
  15. package/src/component/form.ts +0 -42
  16. package/src/component/index.ts +0 -12
  17. package/src/component/iot.ts +0 -52
  18. package/src/component/line.ts +0 -156
  19. package/src/component/register-default-groups.ts +0 -28
  20. package/src/component/shape.ts +0 -156
  21. package/src/component/table.ts +0 -28
  22. package/src/component/text-and-media.ts +0 -125
  23. package/src/component/warehouse.ts +0 -26
  24. package/src/data-storage/data-storage.ts +0 -76
  25. package/src/graphql/board.ts +0 -144
  26. package/src/graphql/data-subscription.ts +0 -30
  27. package/src/graphql/favorite-board.ts +0 -25
  28. package/src/graphql/group.ts +0 -138
  29. package/src/graphql/index.ts +0 -4
  30. package/src/graphql/play-group.ts +0 -225
  31. package/src/graphql/scenario.ts +0 -79
  32. package/src/index.ts +0 -10
  33. package/src/modeller/component-toolbar/component-detail.ts +0 -52
  34. package/src/modeller/component-toolbar/component-menu.ts +0 -196
  35. package/src/modeller/component-toolbar/component-toolbar.ts +0 -196
  36. package/src/modeller/component-toolbar/mode-icons.ts +0 -88
  37. package/src/modeller/edit-toolbar-style.ts +0 -232
  38. package/src/modeller/edit-toolbar.ts +0 -587
  39. package/src/modeller/property-sidebar/abstract-property.ts +0 -69
  40. package/src/modeller/property-sidebar/data-binding/data-binding-mapper.ts +0 -475
  41. package/src/modeller/property-sidebar/data-binding/data-binding-value-map.ts +0 -19
  42. package/src/modeller/property-sidebar/data-binding/data-binding-value-range.ts +0 -19
  43. package/src/modeller/property-sidebar/data-binding/data-binding.ts +0 -480
  44. package/src/modeller/property-sidebar/effects/effects-shared-style.ts +0 -62
  45. package/src/modeller/property-sidebar/effects/effects.ts +0 -69
  46. package/src/modeller/property-sidebar/effects/property-animation.ts +0 -146
  47. package/src/modeller/property-sidebar/effects/property-animations.ts +0 -93
  48. package/src/modeller/property-sidebar/effects/property-event-hover.ts +0 -200
  49. package/src/modeller/property-sidebar/effects/property-event-tap.ts +0 -251
  50. package/src/modeller/property-sidebar/effects/property-event.ts +0 -73
  51. package/src/modeller/property-sidebar/effects/property-shadow.ts +0 -114
  52. package/src/modeller/property-sidebar/effects/value-converter.ts +0 -23
  53. package/src/modeller/property-sidebar/inspector/inspector.ts +0 -404
  54. package/src/modeller/property-sidebar/property-shared-style.ts +0 -136
  55. package/src/modeller/property-sidebar/property-sidebar.ts +0 -326
  56. package/src/modeller/property-sidebar/shapes/box-padding-editor-styles.ts +0 -94
  57. package/src/modeller/property-sidebar/shapes/shapes.ts +0 -432
  58. package/src/modeller/property-sidebar/specifics/specific-properties-builder.ts +0 -152
  59. package/src/modeller/property-sidebar/specifics/specifics.ts +0 -81
  60. package/src/modeller/property-sidebar/styles/styles.ts +0 -577
  61. package/src/modeller/scene-viewer/confidential-overlay.ts +0 -18
  62. package/src/modeller/scene-viewer/ox-scene-handler.ts +0 -40
  63. package/src/modeller/scene-viewer/ox-scene-layer.ts +0 -42
  64. package/src/modeller/scene-viewer/ox-scene-property.ts +0 -10
  65. package/src/modeller/scene-viewer/ox-scene-viewer.ts +0 -263
  66. package/src/ox-board-component-info.ts +0 -236
  67. package/src/ox-board-list.ts +0 -401
  68. package/src/ox-board-modeller.ts +0 -408
  69. package/src/ox-board-player-style.ts +0 -200
  70. package/src/ox-board-player.ts +0 -333
  71. package/src/ox-board-template-list.ts +0 -267
  72. package/src/ox-board-template-viewer.ts +0 -198
  73. package/src/ox-board-viewer.ts +0 -727
  74. package/src/ox-editor-board-selector.ts +0 -91
  75. package/src/ox-property-editor-board-selector.ts +0 -23
  76. package/src/player/ox-board-player-carousel.ts +0 -197
  77. package/src/player/ox-board-player-grid.ts +0 -78
  78. package/src/player/ox-board-wrapper.ts +0 -152
  79. package/src/selector/board-creation-popup.ts +0 -151
  80. package/src/selector/board-thumbnail-card.ts +0 -175
  81. package/src/selector/ox-board-creation-card.ts +0 -98
  82. package/src/selector/ox-board-selector.ts +0 -382
  83. package/src/types.ts +0 -63
  84. package/stories/property-data-binding.stories.ts +0 -34
  85. package/tsconfig.json +0 -24
  86. package/web-dev-server.config.mjs +0 -30
  87. package/web-test-runner.config.mjs +0 -29
@@ -1,727 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
- import '@material/web/fab/fab.js'
3
- import './ox-board-component-info.js'
4
-
5
- import { css, html, LitElement, PropertyValues } from 'lit'
6
- import { customElement, property, query, state } from 'lit/decorators.js'
7
- import * as XLSX from 'xlsx'
8
-
9
- import { Component, create, ReferenceProvider, SCENE_MODE } from '@hatiolab/things-scene'
10
- import { isIOS, togglefullscreen } from '@operato/utils'
11
- import { ScrollbarStyles } from '@operato/styles'
12
-
13
- import { BoardDataStorage } from './data-storage/data-storage.js'
14
- import { DataSubscriptionProviderImpl } from './graphql/data-subscription.js'
15
- import { runScenario, startScenario } from './graphql/scenario.js'
16
-
17
- import { BoardComponentInfo } from './ox-board-component-info.js'
18
- import { fetchPlayGroupByName } from './graphql/play-group.js'
19
-
20
- function objectToQueryString(obj: any) {
21
- const keyValuePairs = []
22
- for (const key in obj) {
23
- if (Object.hasOwnProperty.call(obj, key)) {
24
- const value = obj[key]
25
- if (typeof value === 'object') {
26
- keyValuePairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(JSON.stringify(value))}`)
27
- } else {
28
- keyValuePairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
29
- }
30
- }
31
- }
32
- return keyValuePairs.join('&')
33
- }
34
-
35
- @customElement('ox-board-viewer')
36
- export class BoardViewer extends LitElement {
37
- static styles = [
38
- ScrollbarStyles,
39
- css`
40
- :host {
41
- display: flex;
42
- flex-direction: column;
43
-
44
- position: relative;
45
-
46
- width: 100%; /* 전체화면보기를 위해서 필요함. */
47
- overflow: hidden;
48
- }
49
-
50
- #target {
51
- flex: 1;
52
-
53
- width: 100%; /* 전체화면보기를 위해서 필요함. */
54
- height: 100%;
55
-
56
- outline: 0;
57
- }
58
-
59
- ::slotted(ox-board-component-info) {
60
- position: absolute;
61
- right: 10px;
62
- top: 10px;
63
- width: 240px;
64
- opacity: 0.9;
65
- box-shadow: 2px 2px 4px gray;
66
- max-height: 600px;
67
- overflow: auto;
68
- }
69
-
70
- /* navigation buttons */
71
- #prev,
72
- #next {
73
- z-index: 10;
74
- position: absolute;
75
- top: 45%;
76
- min-width: 50px;
77
- width: 50px;
78
- height: 50px;
79
- margin: 0;
80
- padding: 0;
81
- color: #fff;
82
- user-select: none;
83
-
84
- --md-icon-size: 3em;
85
- }
86
-
87
- md-icon[hidden] {
88
- display: none;
89
- }
90
-
91
- md-icon:hover {
92
- background-color: rgba(0, 0, 0, 0.2);
93
- border-radius: 50%;
94
- }
95
-
96
- #prev {
97
- left: 5px;
98
- }
99
-
100
- #next {
101
- right: 5px;
102
- }
103
-
104
- #fullscreen {
105
- position: absolute;
106
- bottom: 15px;
107
- right: 16px;
108
- }
109
-
110
- [hidden] {
111
- display: none;
112
- }
113
-
114
- @media print {
115
- md-fab,
116
- md-icon {
117
- display: none;
118
- }
119
- }
120
- `
121
- ]
122
-
123
- @property({ type: String }) baseUrl: string = ''
124
- @property({ type: Object }) board: any = {}
125
- @property({ type: Object }) provider: ReferenceProvider | null = null
126
- @property({ type: Object }) data: any
127
- @property({ type: Object }) values: any
128
- @property({ type: Boolean }) history: boolean = false
129
-
130
- @property({ type: Boolean, reflect: true, attribute: 'hide-fullscreen' }) hideFullscreen = false
131
- @property({ type: Boolean, reflect: true, attribute: 'hide-navigation' }) hideNavigation = false
132
-
133
- @state() _scene: any = null
134
- @state() _forward: { id: string; scene: any }[] = []
135
- @state() _backward: { id: string; scene: any }[] = []
136
-
137
- @state() _oldtarget?: HTMLElement
138
- @state() _fade_animations?: Array<Animation>
139
-
140
- public currentBoardId?: string = this.board?.id
141
- private popup?: BoardComponentInfo
142
-
143
- @query('#target') _target!: HTMLElement
144
- @query('#prev') _prev!: HTMLElement
145
- @query('#next') _next!: HTMLElement
146
- @query('#fullscreen') _fullscreen!: HTMLElement
147
-
148
- render() {
149
- var fullscreen =
150
- !isIOS() && !this.hideFullscreen
151
- ? html`
152
- <md-fab
153
- id="fullscreen"
154
- @click=${(e: Event) => this.onTapFullscreen()}
155
- @mouseover=${(e: Event) => this.transientShowButtons(true)}
156
- @mouseout=${(e: Event) => this.transientShowButtons()}
157
- title="fullscreen"
158
- >
159
- <md-icon slot="icon">${document.fullscreenElement ? 'fullscreen_exit' : 'fullscreen'}</md-icon>
160
- </md-fab>
161
- `
162
- : html``
163
-
164
- var prev = !this.hideNavigation
165
- ? html`
166
- <md-icon
167
- id="prev"
168
- @click=${(e: Event) => this.onTapPrev()}
169
- @mouseover=${(e: Event) => this.transientShowButtons(true)}
170
- @mouseout=${(e: Event) => this.transientShowButtons()}
171
- hidden
172
- >keyboard_arrow_left</md-icon
173
- >
174
- `
175
- : html``
176
-
177
- var next = !this.hideNavigation
178
- ? html`
179
- <md-icon
180
- id="next"
181
- @click=${(e: Event) => this.onTapNext()}
182
- @mouseover=${(e: Event) => this.transientShowButtons(true)}
183
- @mouseout=${(e: Event) => this.transientShowButtons()}
184
- hidden
185
- >keyboard_arrow_right</md-icon
186
- >
187
- `
188
- : html``
189
-
190
- return html`
191
- ${prev}
192
-
193
- <div
194
- id="target"
195
- @touchstart=${(e: Event) => this.transientShowButtons()}
196
- @mousemove=${(e: Event) => this.transientShowButtons()}
197
- ></div>
198
-
199
- <slot></slot>
200
- ${next} ${fullscreen}
201
- `
202
- }
203
-
204
- private resizeHandler = () => {
205
- this._scene && this._scene.fit()
206
- }
207
-
208
- connectedCallback() {
209
- super.connectedCallback()
210
-
211
- window.addEventListener('resize', this.resizeHandler)
212
-
213
- window.addEventListener('orientationchange', this.resizeHandler)
214
-
215
- this.renderRoot.addEventListener(
216
- 'close-scene',
217
- e => {
218
- e.preventDefault()
219
- this.onTapPrev()
220
- },
221
- false
222
- )
223
- }
224
-
225
- disconnectedCallback() {
226
- window.removeEventListener('resize', this.resizeHandler)
227
- window.removeEventListener('orientationchange', this.resizeHandler)
228
-
229
- super.disconnectedCallback()
230
-
231
- this.closeScene()
232
- }
233
-
234
- updated(changes: PropertyValues<this>) {
235
- if (changes.has('board')) {
236
- this.hidePopup()
237
- this.closeScene()
238
-
239
- if (this.board && this.board.id) {
240
- if (this.board.model) {
241
- this.initScene()
242
- } else {
243
- this.initSceneAsync()
244
- }
245
- }
246
- }
247
-
248
- if (changes.has('data') && this._scene && this.data) {
249
- this._scene.data = this.data
250
- }
251
-
252
- if (changes.has('values') && this._scene && this.values) {
253
- this._scene.values = this.values
254
- }
255
- }
256
-
257
- async initSceneAsync() {
258
- if (!this.board || !this.board.id) return
259
-
260
- this._scene = await this.provider!.create(this.board.id)
261
- this.setupScene({ id: this.board.id, scene: this._scene })
262
- }
263
-
264
- initScene() {
265
- if (!this.board || !this.board.id) return
266
-
267
- this._scene = create({
268
- model: {
269
- ...this.board.model
270
- },
271
- mode: SCENE_MODE.VIEW,
272
- refProvider: this.provider!,
273
- dataStorage: this.board.id !== 'preview' ? new BoardDataStorage(this.board.id) : undefined,
274
- dataSubscriptionProvider: new DataSubscriptionProviderImpl()
275
- })
276
-
277
- if (this.baseUrl) {
278
- this._scene.baseUrl = this.baseUrl
279
- }
280
-
281
- // this.provider!.add(this.board.id, this._scene)
282
-
283
- this.setupScene({ id: this.board.id, scene: this._scene })
284
- }
285
-
286
- closeScene() {
287
- if (this._scene) {
288
- this.unbindSceneEvents(this._scene)
289
-
290
- this._scene.target = null
291
- this._scene.release && this._scene.release()
292
-
293
- this._scene = null
294
- }
295
-
296
- // delete queued scenes
297
- this._forward.forEach(({ scene }) => scene.release && scene.release())
298
- this._forward = []
299
-
300
- this._backward.forEach(({ scene }) => scene.release && scene.release())
301
- this._backward = []
302
- }
303
-
304
- releaseScene() {
305
- this.closeScene()
306
- this.transientShowButtons()
307
- }
308
-
309
- setupScene({ id, scene }: { id: string; scene: any }, history?: -1 | 0 | 1) {
310
- this._scene = scene
311
-
312
- const backgroundColor = this._scene?.root.state.fillStyle
313
- if (typeof backgroundColor === 'string') {
314
- this.style.backgroundColor = backgroundColor
315
- } else {
316
- this.style.backgroundColor = 'initial'
317
- }
318
-
319
- /* scene의 기존 target을 보관한다. */
320
- this._oldtarget = this._scene.target
321
-
322
- this._scene.fit(this._scene.fitMode)
323
- this._scene.target = this._target
324
-
325
- if (this.data) {
326
- this._scene.data = this.data
327
- }
328
- if (this.values) {
329
- this._scene.values = this.values
330
- }
331
- this.currentBoardId = id
332
-
333
- this.bindSceneEvents()
334
-
335
- this.transientShowButtons()
336
-
337
- if (this.history && typeof history !== 'undefined' /* && document.querySelector('things-app') */) {
338
- const currentUrl = new URL(window.location.href)
339
- const paths = currentUrl.pathname.split('/')
340
-
341
- paths[paths.length - 1] = this.currentBoardId
342
- window.history.replaceState({}, '', `${currentUrl.origin}${paths.join('/')}${currentUrl.search}`)
343
- }
344
- }
345
-
346
- async showScene(boardId: string, bindingData?: any) {
347
- if (!boardId) return
348
-
349
- try {
350
- var scene = await this.provider!.get(boardId, true)
351
-
352
- if (scene === this._scene) {
353
- scene.release && scene.release()
354
- return
355
- }
356
-
357
- if (this._scene) {
358
- /* old scene을 _backward에 보관한다. */
359
- this.unbindSceneEvents(this._scene)
360
- /* 원래의 target에 되돌린다. */
361
- this._scene.target = this._oldtarget
362
- this._backward.push({ id: this.currentBoardId!, scene: this._scene })
363
- }
364
-
365
- this._scene = scene
366
-
367
- this._forward.forEach(({ scene }) => scene.release && scene.release())
368
-
369
- /* forward를 비운다. */
370
- this._forward = []
371
-
372
- this.setupScene({ id: boardId, scene }, 0)
373
-
374
- if (bindingData) {
375
- scene.data = bindingData
376
- }
377
- } catch (e) {
378
- console.error(e)
379
- }
380
- }
381
-
382
- async gotoPlayer(playGroupName: string, bindingData?: any) {
383
- const id = (await fetchPlayGroupByName(playGroupName))?.id
384
- const queryString = bindingData ? objectToQueryString(bindingData) : ''
385
-
386
- if (document.querySelector('things-app')) {
387
- history.pushState({}, '', `board-player/${id}?${queryString}`)
388
- window.dispatchEvent(new Event('popstate'))
389
- } else {
390
- location.href = `headless-player/${id}?${queryString}`
391
- }
392
- }
393
-
394
- bindSceneEvents() {
395
- this._scene.on('run', this.onRunBoard, this)
396
- this._scene.on('goto', this.onLinkGoto, this)
397
- this._scene.on('goto-playlist', this.onLinkGotoPlaylist, this)
398
- this._scene.on('link-open', this.onLinkOpen, this)
399
- this._scene.on('link-move', this.onLinkMove, this)
400
- this._scene.on('route-page', this.onRoutePage, this)
401
- this._scene.on('start-scenario', this.onStartScenario, this)
402
- this._scene.on('run-scenario', this.onRunScenario, this)
403
- this._scene.on('export-data', this.onExportData, this)
404
- this._scene.on('import-data', this.onImportData, this)
405
- this._scene.on('click', this.onClickEvent, this)
406
- }
407
-
408
- unbindSceneEvents(scene: any) {
409
- scene.off('run', this.onRunBoard, this)
410
- scene.off('goto', this.onLinkGoto, this)
411
- scene.off('goto-playlist', this.onLinkGotoPlaylist, this)
412
- scene.off('link-open', this.onLinkOpen, this)
413
- scene.off('link-move', this.onLinkMove, this)
414
- scene.off('route-page', this.onRoutePage, this)
415
- scene.off('start-scenario', this.onStartScenario, this)
416
- scene.off('run-scenario', this.onRunScenario, this)
417
- scene.off('export-data', this.onExportData, this)
418
- scene.off('import-data', this.onImportData, this)
419
- scene.off('click', this.onClickEvent, this)
420
- }
421
-
422
- transientShowButtons(stop?: boolean) {
423
- var buttons = []
424
- !this.hideNavigation && buttons.push(this._next, this._prev)
425
- !this.hideFullscreen && buttons.push(this._fullscreen)
426
-
427
- if (buttons.length == 0) {
428
- return
429
- }
430
-
431
- if (!this._fade_animations) {
432
- this._fade_animations = buttons
433
- .filter(button => button)
434
- .map(button => {
435
- let animation = button.animate(
436
- [
437
- {
438
- opacity: 1,
439
- easing: 'ease-in'
440
- },
441
- { opacity: 0 }
442
- ],
443
- { delay: 1000, duration: 2000 }
444
- )
445
-
446
- animation.onfinish = () => {
447
- button.setAttribute('hidden', '')
448
- }
449
-
450
- return animation
451
- })
452
- }
453
-
454
- this._forward.length <= 0 ? this._next.setAttribute('hidden', '') : this._next.removeAttribute('hidden')
455
- this._backward.length <= 0 ? this._prev.setAttribute('hidden', '') : this._prev.removeAttribute('hidden')
456
- this._fullscreen && this._fullscreen.removeAttribute('hidden')
457
-
458
- this._fade_animations.forEach(animation => {
459
- animation.cancel()
460
- if (stop) return
461
-
462
- animation.play()
463
- })
464
- }
465
-
466
- /* event handlers */
467
-
468
- onTapNext() {
469
- var { id, scene } = this._forward.pop() || {}
470
- if (!scene) return
471
-
472
- if (this._scene) {
473
- this._scene.target = null
474
- /* 원래의 target에 되돌린다. */
475
- this._scene.target = this._oldtarget
476
- this.unbindSceneEvents(this._scene)
477
- this._backward.push({ id: this.currentBoardId!, scene: this._scene })
478
- }
479
-
480
- this.setupScene({ id: id!, scene }, 1)
481
- }
482
-
483
- onTapPrev() {
484
- var { id, scene } = this._backward.pop() || {}
485
- if (!scene) return
486
-
487
- if (this._scene) {
488
- this._scene.target = null
489
- /* 원래의 target에 되돌린다. */
490
- this._scene.target = this._oldtarget
491
- this.unbindSceneEvents(this._scene)
492
- this._forward.push({ id: this.currentBoardId!, scene: this._scene })
493
- }
494
-
495
- this.setupScene({ id: id!, scene }, -1)
496
- }
497
-
498
- onTapFullscreen() {
499
- togglefullscreen(
500
- this,
501
- () => this.requestUpdate(),
502
- () => this.requestUpdate()
503
- )
504
- }
505
-
506
- onRunBoard() {
507
- this.dispatchEvent(new CustomEvent('run-board', { bubbles: true, composed: true, detail: this.board.id }))
508
- }
509
-
510
- onLinkGoto(targetBoardId: string, options: any, fromComponent: any) {
511
- const { input, output } = options || { input: '(self)' }
512
- const data = input && fromComponent.root.findFirst(input, fromComponent)?.data
513
- this.showScene(targetBoardId, data)
514
- }
515
-
516
- onLinkGotoPlaylist(targetPlayGroupName: string, options: any, fromComponent: any) {
517
- const { input, output } = options || { input: '(self)' }
518
- const data = input && fromComponent.root.findFirst(input, fromComponent)?.data
519
- this.gotoPlayer(targetPlayGroupName, data)
520
- }
521
-
522
- onLinkOpen(url: string, value: any, fromComponent: Component) {
523
- if (!url) return
524
-
525
- try {
526
- window.open(url)
527
- } catch (ex) {
528
- document.dispatchEvent(
529
- new CustomEvent('notify', {
530
- detail: {
531
- level: 'error',
532
- message: ex,
533
- ex
534
- }
535
- })
536
- )
537
- }
538
- }
539
-
540
- onLinkMove(url: string, value: any, fromComponent: Component) {
541
- if (!url) {
542
- return
543
- }
544
-
545
- location.href = url
546
- }
547
-
548
- onRoutePage(page: string) {
549
- if (!page) {
550
- return
551
- }
552
-
553
- history.pushState({}, '', page)
554
- window.dispatchEvent(new Event('popstate'))
555
- }
556
-
557
- async onStartScenario(scenario: string, value: string | number | object, component: Component) {
558
- try {
559
- await startScenario(scenario, scenario, value)
560
- } catch (e) {
561
- console.error(e)
562
- }
563
- }
564
-
565
- async onRunScenario(scenario: string, value: string | number | object, component: Component) {
566
- try {
567
- component.data = await runScenario(scenario, value)
568
- } catch (e) {
569
- console.error(e)
570
- }
571
- }
572
-
573
- async onExportData(filename: string, value: string | number | object, component: Component) {
574
- try {
575
- const data = component.data
576
-
577
- const worksheet = XLSX.utils.json_to_sheet(data)
578
- const workbook = XLSX.utils.book_new()
579
- XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
580
- XLSX.writeFile(workbook, filename || 'export-data.xlsx')
581
- } catch (e) {
582
- console.error(e)
583
- }
584
- }
585
-
586
- async onImportData(_: string, value: string | number | object, component: Component) {
587
- const fileInput = document.createElement('input')
588
- fileInput.type = 'file'
589
- fileInput.accept = '.xlsx, .xls'
590
- fileInput.style.display = 'none'
591
-
592
- fileInput.addEventListener(
593
- 'change',
594
- (event: Event) => {
595
- const input = event.target as HTMLInputElement
596
- const file = input.files?.[0]
597
- if (!file) {
598
- return
599
- }
600
-
601
- const reader = new FileReader()
602
- reader.onload = function (event) {
603
- const data = new Uint8Array(event.target?.result as ArrayBuffer)
604
- const workbook = XLSX.read(data, { type: 'array' })
605
-
606
- // 첫 번째 시트의 데이타만 가져온다.
607
- const firstSheetName = workbook.SheetNames[0]
608
- const worksheet = workbook.Sheets[firstSheetName]
609
- component.data = XLSX.utils.sheet_to_json(worksheet)
610
-
611
- input.remove()
612
- }
613
- reader.readAsArrayBuffer(file)
614
- },
615
- false
616
- )
617
-
618
- document.body.appendChild(fileInput)
619
- fileInput.click()
620
- }
621
-
622
- onClickEvent(e: MouseEvent, hint: any) {
623
- const component = hint.origin
624
-
625
- if (!this.popup && e.altKey) {
626
- const popup = document.createElement('ox-board-component-info') as BoardComponentInfo
627
- popup.addEventListener('close', e => {
628
- e.stopPropagation()
629
- this.hidePopup()
630
- })
631
-
632
- this.appendChild(popup)
633
- this.popup = popup
634
- }
635
-
636
- if (this.popup) {
637
- this.popup.component = component
638
- }
639
- }
640
-
641
- hidePopup() {
642
- if (this.popup) {
643
- this.removeChild(this.popup)
644
- delete this.popup
645
- }
646
- }
647
-
648
- getSceneData() {
649
- return this._scene?.data
650
- }
651
-
652
- getSceneValues() {
653
- return this._scene?.values
654
- }
655
-
656
- async getSceneImageData(base64 = false) {
657
- if (!this._scene) {
658
- return
659
- }
660
-
661
- var { width, height } = this._scene.model
662
- var pixelRatio = window.devicePixelRatio
663
-
664
- // 1. Scene의 바운드에 근거하여, 오프스크린 캔바스를 만든다.
665
- var canvas = document.createElement('canvas')
666
- canvas.width = Number(width)
667
- canvas.height = Number(height)
668
-
669
- var root = this._scene.root
670
- // 2. 모델레이어의 원래 위치와 스케일을 저장한다.
671
- var translate = root.get('translate')
672
- var scale = root.get('scale')
673
-
674
- // 3. 위치와 스케일 기본 설정.
675
- root.set('translate', { x: 0, y: 0 })
676
- root.set('scale', { x: 1 / pixelRatio, y: 1 / pixelRatio })
677
-
678
- // 4. 오프스크린 캔바스의 Context2D를 구한뒤, 모델레이어를 그 위에 그린다.
679
- var context = canvas.getContext('2d')
680
-
681
- root.draw(context)
682
-
683
- root.set('translate', translate)
684
- root.set('scale', scale)
685
-
686
- var data = base64 ? canvas.toDataURL() : context!.getImageData(0, 0, width, height).data
687
-
688
- return {
689
- width,
690
- height,
691
- data
692
- }
693
- }
694
-
695
- async printTrick(image: string) {
696
- var viewTarget: HTMLElement | null = null
697
- var printTarget: HTMLImageElement | null = null
698
-
699
- if (!image) {
700
- image = (await this.getSceneImageData(true))?.data as string
701
- }
702
-
703
- printTarget = document.createElement('img')
704
- printTarget.id = 'target'
705
- printTarget.src = image
706
- printTarget.style.width = '100%'
707
- printTarget.style.height = '100%'
708
-
709
- const x = (mql: MediaQueryListEvent) => {
710
- if (mql.matches) {
711
- if (!viewTarget) {
712
- viewTarget = (this.renderRoot as ShadowRoot)!.getElementById('target')
713
- this.renderRoot.replaceChild(printTarget!, viewTarget!)
714
- }
715
- } else {
716
- this.renderRoot.replaceChild(viewTarget!, printTarget!)
717
- printTarget!.remove()
718
- mediaQueryList.removeEventListener('change', x)
719
- }
720
- }
721
-
722
- if (window.matchMedia) {
723
- var mediaQueryList = window.matchMedia('print')
724
- mediaQueryList.addEventListener('change', x)
725
- }
726
- }
727
- }