| static readonly PluginType = 'Picking' | static readonly PluginType = 'Picking' | ||||
| private _picker?: ObjectPicker | private _picker?: ObjectPicker | ||||
| private _widget?: SelectionWidget | private _widget?: SelectionWidget | ||||
| private _hoverWidget?: SelectionWidget | |||||
| private _pickUi: boolean | private _pickUi: boolean | ||||
| get hoverEnabled() { | get hoverEnabled() { | ||||
| } | } | ||||
| @serialize() | @serialize() | ||||
| autoFocus = false | |||||
| autoFocus | |||||
| // @serialize() // todo | |||||
| autoFocusHover = false | |||||
| public setDirty() { | public setDirty() { | ||||
| this._viewer?.setDirty() | this._viewer?.setDirty() | ||||
| super() | super() | ||||
| if (selection) { | if (selection) { | ||||
| this._widget = new selection() | this._widget = new selection() | ||||
| this._hoverWidget = new selection() | |||||
| if (this._hoverWidget.lineMaterial) { | |||||
| this._hoverWidget.lineMaterial.linewidth! /= 2 | |||||
| this._hoverWidget.lineMaterial.color!.set('#aa2222') | |||||
| } | |||||
| } | } | ||||
| this._pickUi = pickUi | this._pickUi = pickUi | ||||
| this.autoFocus = autoFocus | this.autoFocus = autoFocus | ||||
| return ret | return ret | ||||
| }) | }) | ||||
| if (this._widget) viewer.scene.addObject(this._widget, {addToRoot: true}) | if (this._widget) viewer.scene.addObject(this._widget, {addToRoot: true}) | ||||
| if (this._hoverWidget) viewer.scene.addObject(this._hoverWidget, {addToRoot: true}) | |||||
| this._picker.addEventListener('selectedObjectChanged', this._selectedObjectChanged) | this._picker.addEventListener('selectedObjectChanged', this._selectedObjectChanged) | ||||
| this._picker.addEventListener('hoverObjectChanged', this.dispatchEvent) | |||||
| this._picker.addEventListener('hoverObjectChanged', this._hoverObjectChanged) | |||||
| this._picker.addEventListener('hitObject', this._onObjectHit) | this._picker.addEventListener('hitObject', this._onObjectHit) | ||||
| // on material drop on selected object | // on material drop on selected object | ||||
| viewer.scene.removeEventListener('mainCameraChange', this._mainCameraChange) | viewer.scene.removeEventListener('mainCameraChange', this._mainCameraChange) | ||||
| this._widget?.removeFromParent() | this._widget?.removeFromParent() | ||||
| this._hoverWidget?.removeFromParent() | |||||
| if (this._picker) { | if (this._picker) { | ||||
| this._picker.removeEventListener('selectedObjectChanged', this._selectedObjectChanged) | this._picker.removeEventListener('selectedObjectChanged', this._selectedObjectChanged) | ||||
| this._picker.removeEventListener('hoverObjectChanged', this.dispatchEvent) | |||||
| this._picker.removeEventListener('hoverObjectChanged', this._hoverObjectChanged) | |||||
| this._picker.removeEventListener('hitObject', this._onObjectHit) | this._picker.removeEventListener('hitObject', this._onObjectHit) | ||||
| this._picker.dispose() | this._picker.dispose() | ||||
| this._picker = undefined | this._picker = undefined | ||||
| dispose() { | dispose() { | ||||
| super.dispose() | super.dispose() | ||||
| this._widget?.dispose() | this._widget?.dispose() | ||||
| this._hoverWidget?.dispose() | |||||
| } | } | ||||
| private _mainCameraChange = ()=>{ | private _mainCameraChange = ()=>{ | ||||
| } | } | ||||
| } | |||||
| private _hoverObjectChanged = (e: any) => { | |||||
| this.dispatchEvent(e) | |||||
| const selected = this._picker?.hoverObject || undefined | |||||
| const widget = this._hoverWidget | |||||
| if (widget && this._enableWidget) { | |||||
| if (selected) widget.attach(selected) | |||||
| else widget.detach() | |||||
| } | |||||
| // if (selected) selected.dispatchEvent({type: 'selected', source: PickingPlugin.PluginType, object: selected}) | |||||
| this._viewer?.setDirty() | |||||
| if (this.autoFocusHover) { | |||||
| // this._viewer?.resetCamera({rootObject: selected, centerOffset: new Vector3(4, 4, 4)}) | |||||
| this.focusObject(selected) | |||||
| } | |||||
| } | } | ||||
| private _onObjectHit = (e: any)=>{ | private _onObjectHit = (e: any)=>{ | ||||
| label: 'Hover Enabled', | label: 'Hover Enabled', | ||||
| type: 'checkbox', | type: 'checkbox', | ||||
| property: [this, 'hoverEnabled'], | property: [this, 'hoverEnabled'], | ||||
| onChange: ()=>this.uiConfig.uiRefresh?.(true), // for autoFocusHover | |||||
| }, | }, | ||||
| { | { | ||||
| label: 'AutoFocus', | |||||
| label: 'Auto Focus', | |||||
| type: 'checkbox', | type: 'checkbox', | ||||
| property: [this, 'autoFocus'], | property: [this, 'autoFocus'], | ||||
| onChange: ()=>{ | onChange: ()=>{ | ||||
| if (this.autoFocus && o) this.setSelectedObject(o, true) | if (this.autoFocus && o) this.setSelectedObject(o, true) | ||||
| }, | }, | ||||
| }, | }, | ||||
| { | |||||
| label: 'Auto Focus on Hover', | |||||
| type: 'checkbox', | |||||
| hidden: ()=>!this.hoverEnabled, | |||||
| property: [this, 'autoFocusHover'], | |||||
| }, | |||||
| ] | ] | ||||
| uiConfig: UiObjectConfig = { | uiConfig: UiObjectConfig = { |
| this.dispatchEvent({type: 'selectedObjectChanged', object: this.selectedObject}) | this.dispatchEvent({type: 'selectedObjectChanged', object: this.selectedObject}) | ||||
| } | } | ||||
| get hoverObject() { | |||||
| get hoverObject(): IObject3D | null { | |||||
| return this._hovering.length > 0 ? this._hovering[0] : null | return this._hovering.length > 0 ? this._hovering[0] : null | ||||
| } | } | ||||
| import {Group, Sphere, Vector2} from 'three' | import {Group, Sphere, Vector2} from 'three' | ||||
| import {AnyOptions} from 'ts-browser-helpers' | import {AnyOptions} from 'ts-browser-helpers' | ||||
| import {Box3B} from '../math/Box3B' | import {Box3B} from '../math/Box3B' | ||||
| import {IObject3D, IWidget} from '../../core' | |||||
| import {IMaterial, IObject3D, IWidget, LineMaterial2} from '../../core' | |||||
| import {LineSegments2} from 'three/examples/jsm/lines/LineSegments2.js' | import {LineSegments2} from 'three/examples/jsm/lines/LineSegments2.js' | ||||
| import {LineSegmentsGeometry} from 'three/examples/jsm/lines/LineSegmentsGeometry.js' | import {LineSegmentsGeometry} from 'three/examples/jsm/lines/LineSegmentsGeometry.js' | ||||
| import {LineMaterial2} from '../../core/material/LineMaterial2' | |||||
| export class SelectionWidget extends Group implements IWidget { | export class SelectionWidget extends Group implements IWidget { | ||||
| isWidget = true as const | isWidget = true as const | ||||
| boundingScaleMultiplier = 1. | boundingScaleMultiplier = 1. | ||||
| setDirty?: (options?: AnyOptions) => void | setDirty?: (options?: AnyOptions) => void | ||||
| lineMaterial?: IMaterial | |||||
| protected _updater() { | protected _updater() { | ||||
| const selected: IObject3D | null | undefined = this._object | const selected: IObject3D | null | undefined = this._object | ||||
| if (selected) { | if (selected) { | ||||
| if (!object) return this | if (!object) return this | ||||
| this._object = object | this._object = object | ||||
| this._object.addEventListener('objectUpdate', this._updater) | this._object.addEventListener('objectUpdate', this._updater) | ||||
| this._object.addEventListener('geometryUpdate', this._updater) | |||||
| this._updater() | this._updater() | ||||
| return this | return this | ||||
| } | } | ||||
| detach(): this { | detach(): this { | ||||
| if (!this._object) return this | if (!this._object) return this | ||||
| this._object?.removeEventListener('objectUpdate', this._updater) | this._object?.removeEventListener('objectUpdate', this._updater) | ||||
| this._object?.removeEventListener('geometryUpdate', this._updater) | |||||
| this._object = null | this._object = null | ||||
| this._updater() | this._updater() | ||||
| return this | return this | ||||
| dashed: false, | dashed: false, | ||||
| toneMapped: false, | toneMapped: false, | ||||
| }) | }) | ||||
| this.lineMaterial = matLine | |||||
| const ls = new LineSegmentsGeometry() | const ls = new LineSegmentsGeometry() | ||||
| ls.setPositions([1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1].map(v=>v - 0.5)) | ls.setPositions([1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1].map(v=>v - 0.5)) |