threepipe
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AViewerPlugin.ts 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import type {ISerializedConfig, IViewerEvent, ThreeViewer} from './ThreeViewer'
  2. import {IViewerEventTypes} from './ThreeViewer'
  3. import {Event, EventDispatcher} from 'three'
  4. import {PartialRecord, SerializationMetaType, ThreeSerialization} from '../utils'
  5. import {IViewerPlugin, IViewerPluginAsync} from './IViewerPlugin'
  6. import {UiObjectConfig} from 'uiconfig.js'
  7. /**
  8. * Base Class for Viewer Plugins
  9. * @category Viewer
  10. */
  11. export abstract class AViewerPlugin<T extends string = string, TViewer extends ThreeViewer = ThreeViewer, IsSync extends boolean = boolean> extends EventDispatcher<Event, T|'serialize'|'deserialize'> implements IViewerPlugin<TViewer, IsSync> {
  12. declare ['constructor']: typeof AViewerPlugin
  13. public static readonly PluginType: string = 'AViewerPlugin'
  14. protected _dirty = false
  15. uiConfig?: UiObjectConfig = undefined // todo: this should work when uncommented, remove all get uiConfig and do it properly
  16. protected _viewer?: TViewer
  17. // this is just a property, not an indicator that a plugin is used, to disable a plugin, just remove it from the viewer
  18. abstract enabled: boolean
  19. abstract onAdded(viewer: TViewer): IsSync extends false ? Promise<void> : void
  20. abstract onRemove(viewer: TViewer): IsSync extends false ? Promise<void> : void
  21. dispose(): void {
  22. return
  23. }
  24. toJSON(meta?: SerializationMetaType): ISerializedConfig {
  25. const data: any = ThreeSerialization.Serialize(this, meta, true)
  26. data.type = this.constructor.PluginType
  27. data.assetType = 'config'
  28. this.dispatchEvent({type: 'serialize', data})
  29. return data
  30. }
  31. fromJSON(data: ISerializedConfig, meta?: SerializationMetaType): this|null|Promise<this|null> {
  32. if (data.type !== this.constructor.PluginType)
  33. return null
  34. ThreeSerialization.Deserialize(data, this, meta, true)
  35. this.dispatchEvent({type: 'deserialize', data, meta})
  36. return this
  37. }
  38. protected _storeKey(prefix?: string) {
  39. return (prefix ?? 'webgi') + '_' + (this.constructor.PluginType || this.constructor.name)
  40. }
  41. exportState() {
  42. return this._viewer?.exportPluginConfig(this) ?? this.toJSON?.()
  43. }
  44. async importState(state: any) {
  45. if (this._viewer) await this._viewer.importPluginConfig(state, this)
  46. else this.fromJSON?.(state)
  47. }
  48. protected _viewerListeners: PartialRecord<IViewerEventTypes, (e: IViewerEvent)=>void> = {}
  49. protected _onViewerEvent = (e: IViewerEvent)=> {
  50. const et = e.eType
  51. et && this._viewerListeners[et]?.(e)
  52. return e
  53. }
  54. private _disabledBy = new Set<any>()
  55. disable = (key: any) => {
  56. const size = this._disabledBy.size
  57. this._disabledBy.add(key)
  58. if (this.setDirty && size !== this._disabledBy.size) this.setDirty()
  59. }
  60. enable = (key: any) => {
  61. const size = this._disabledBy.size
  62. this._disabledBy.delete(key)
  63. if (this.setDirty && size !== this._disabledBy.size) this.setDirty()
  64. }
  65. isDisabled = () => {
  66. return this._disabledBy.size > 0 || !this.enabled
  67. }
  68. setDirty?(...args: any[]): any
  69. // todo: move to ThreeViewer
  70. // storeState(prefix?: string, storage?: Storage, data?: any): void {
  71. // storage = storage || (window ? window.localStorage : undefined)
  72. // if (!storage) {
  73. // console.warn('Unable to store state')
  74. // return
  75. // }
  76. // if (data === undefined) data = this.exportState()
  77. // if (data) storage.setItem(this._storeKey(prefix), JSON.stringify(data))
  78. // }
  79. //
  80. // async loadState(prefix?: string, storage?: Storage): Promise<void> {
  81. // storage = storage || (window ? window.localStorage : undefined)
  82. // if (!storage) {
  83. // console.warn('Unable to load state')
  84. // return
  85. // }
  86. // const data = storage.getItem(this._storeKey(prefix))
  87. // if (data) await this.importState(JSON.parse(data))
  88. // }
  89. get dirty(): boolean {
  90. return this.enabled && this._dirty
  91. }
  92. set dirty(value: boolean) {
  93. this._dirty = value
  94. }
  95. /**
  96. * Template
  97. toJSON(meta?: any): any {
  98. const data = super.toJSON(meta)
  99. if (!data.type) return data
  100. // add here
  101. return data
  102. }
  103. fromJSON(data: any, meta?: any): this | null {
  104. if (!super.fromJSON(data, meta)) return null
  105. // add here
  106. return this
  107. }
  108. */
  109. }
  110. /**
  111. * Base Class for Sync Viewer Plugins
  112. * @category Viewer
  113. */
  114. export abstract class AViewerPluginSync<T extends string, TViewer extends ThreeViewer = ThreeViewer> extends AViewerPlugin<T, TViewer, true> {
  115. declare ['constructor']: (typeof AViewerPluginSync) & (typeof AViewerPlugin)
  116. onAdded(viewer: TViewer): void {
  117. this._viewer = viewer
  118. this._viewer.addEventListener('*', this._onViewerEvent)
  119. }
  120. onRemove(viewer: TViewer): void {
  121. if (this._viewer !== viewer) viewer.console.error('Wrong viewer')
  122. this._viewer?.removeEventListener('*', this._onViewerEvent)
  123. this._viewer = undefined
  124. }
  125. }
  126. /**
  127. * Base Class for Async Viewer Plugins
  128. * @category Viewer
  129. */
  130. export abstract class AViewerPluginAsync<T extends string, TViewer extends ThreeViewer = ThreeViewer> extends AViewerPlugin<T, TViewer, false> implements IViewerPluginAsync<TViewer> {
  131. declare ['constructor']: (typeof AViewerPluginAsync) & (typeof AViewerPlugin)
  132. async onAdded(viewer: TViewer): Promise<void> {
  133. this._viewer = viewer
  134. this._viewer.addEventListener('*', this._onViewerEvent)
  135. }
  136. async onRemove(viewer: TViewer): Promise<void> {
  137. if (this._viewer !== viewer) viewer.console.error('Wrong viewer')
  138. this._viewer?.removeEventListener('*', this._onViewerEvent)
  139. this._viewer = undefined
  140. }
  141. }