bus events connectes ! + some CSS improvements
This commit is contained in:
+161
-16
@@ -4,17 +4,157 @@ import * as TWEEN from './tween.module.js'
|
||||
|
||||
export class Threetobus{
|
||||
|
||||
constructor(){
|
||||
constructor(options){
|
||||
this._curEventsMapping = []
|
||||
this._stagedEventsMapping = options.eventsMapping
|
||||
this.commitConfig()
|
||||
|
||||
this.cameras = {}
|
||||
this.renderers = []
|
||||
}
|
||||
|
||||
initScene(){
|
||||
get EventsMapping() { return this._stagedEventsMapping }
|
||||
get liveEventsMapping() { return this._curEventsMapping }
|
||||
set EventsMapping(newConfig) { this._stagedEventsMapping = newConfig }
|
||||
|
||||
async commitConfig(){
|
||||
const chansToAdd = []
|
||||
const chansToKeep = []
|
||||
for(const chanObj of this._stagedEventsMapping){
|
||||
console.log('staged chan:',chanObj.chan,' current ones:', this._curEventsMapping.map(item => item.chan))
|
||||
if(this._curEventsMapping.map(item => item.chan).includes(chanObj.chan)) chansToKeep.push(chanObj)
|
||||
else chansToAdd.push(chanObj)
|
||||
}
|
||||
const chansToDel = this._curEventsMapping.filter(item => (!chansToKeep.map(c=>c.chan).includes(item.chan) && !chansToAdd.map(c=>c.chan).includes(item.chan)))
|
||||
await app.MessageBus.subscribe(chansToAdd.map(item => item.chan))
|
||||
await app.MessageBus.unSubscribe(chansToDel.map(item => item.chan))
|
||||
// console.log('subscribe:', chansToAdd.map(item => item.chan))
|
||||
// console.log('unSubscribe:', chansToDel)
|
||||
|
||||
const eventsToAdd = chansToAdd.flatMap(item => item.events.map(ev => ({ chan:item.chan, eventName:ev.eventName })))
|
||||
let eventsToDel = []//= chansToDel.flatMap(item => item.events.map(ev => ({ chan:item.chan, eventName:ev.eventName })))
|
||||
for(const oldChan of this._curEventsMapping){
|
||||
for(const oldEvent of oldChan.events){
|
||||
for(const keepChan of chansToKeep){
|
||||
if(!keepChan.events.map(item=>item.eventName).includes(oldEvent.eventName)) eventsToDel.push({chan: oldChan.chan, eventName: oldEvent.eventName})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// console.log('eventsToAdd:', eventsToAdd)
|
||||
// console.log('eventsToDel:', eventsToDel)
|
||||
for(const eventToAdd of eventsToAdd){
|
||||
app.MessageBus.addBusListener(eventToAdd.eventName, [eventToAdd.chan], this.processBusEvent.bind(this, eventToAdd.eventName,), 'threetobus')
|
||||
}
|
||||
for(const eventToDel of eventsToDel){
|
||||
app.MessageBus.removeBusListener(eventToDel.eventName, this.processBusEvent.bind(this, eventToDel.eventName), 'threetobus')
|
||||
}
|
||||
|
||||
this._curEventsMapping = this.deepClone(this._stagedEventsMapping)
|
||||
}
|
||||
|
||||
deepClone(obj) { // Needed because structuredClone doesn't take functions (and we have transformers)
|
||||
if (obj === null || typeof obj !== 'object') {
|
||||
return obj
|
||||
}
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((el => this.deepClone(el)))
|
||||
}
|
||||
const clone = {}
|
||||
for (const key in obj) {
|
||||
clone[key] = this.deepClone(obj[key])
|
||||
}
|
||||
return clone
|
||||
}
|
||||
|
||||
|
||||
processBusEvent(eventType, chan, payload, userId, x){
|
||||
console.log('processBusEvent====>',eventType, chan, payload, userId)
|
||||
const chanObj = this._curEventsMapping.find(item => item.chan==chan)
|
||||
if(!chanObj) return
|
||||
console.log('processBusEvent====>chanObj', chanObj)
|
||||
const eventObj = chanObj.events.find(item => item.eventName==eventType)
|
||||
if(!eventObj) return
|
||||
console.log('processBusEvent====>eventObj', eventObj)
|
||||
|
||||
for(const mapping of eventObj.mappings){
|
||||
const id = this.getValueByPath(payload, mapping.id)
|
||||
console.log('agent ID:', id)
|
||||
|
||||
if(id){
|
||||
const obj3D = this.scene.getObjectByName(id)
|
||||
this.assignFromConfig(payload, mapping.assign, obj3D)
|
||||
}
|
||||
|
||||
|
||||
// console.log(`found ${mappings.length} mappings`)
|
||||
// mappings.forEach(snapEl => {
|
||||
// const newAttr = this.assignFromConfig(payload, mapping.assign)
|
||||
// if(mapping.animate){
|
||||
// snapEl.animate(
|
||||
// newAttr,
|
||||
// 400,
|
||||
// mina.linear
|
||||
// )
|
||||
// } else {
|
||||
// snapEl.attr(newAttr)
|
||||
// }
|
||||
// })
|
||||
}
|
||||
}
|
||||
|
||||
assignFromConfig(payload, replaceDef, obj3D) {
|
||||
console.log('assignFromConfig', payload, replaceDef)
|
||||
for (const [path, rule] of Object.entries(replaceDef)) {
|
||||
let value
|
||||
if (typeof rule === 'string') { // plain path
|
||||
value= this.getValueByPath(payload, rule)
|
||||
|
||||
} else if((typeof(rule) == 'object') && (typeof(rule.transformer) == 'function')) { // transformer
|
||||
const fnargs = (rule.arguments || []).map(arg => this.getValueByPath(payload,arg))
|
||||
value = rule.transformer(...fnargs)
|
||||
}
|
||||
|
||||
console.log('====>',path ,value)
|
||||
if (value !== undefined) {
|
||||
this.setProp(obj3D, path, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setProp(obj3D, path, value) { console.log('====>setProp', path, value)
|
||||
const parts = path.split('.')
|
||||
let target = obj3D
|
||||
for (let i = 0; i < parts.length - 1; i++) {
|
||||
target = target[parts[i]]
|
||||
if (!target) return // path broken
|
||||
}
|
||||
const last = parts[parts.length - 1]
|
||||
|
||||
// Handle Three.Color objects
|
||||
if (target[last] && target[last].isColor) {
|
||||
target[last].set(value)
|
||||
} else {
|
||||
target[last] = value
|
||||
}
|
||||
}
|
||||
|
||||
getValueByPath(obj, path) {
|
||||
return(path.split('.').reduce((acc, key) => acc?.[key], obj))
|
||||
}
|
||||
|
||||
initScene(options){
|
||||
// Scene
|
||||
this.scene = new THREE.Scene()
|
||||
|
||||
this.grid = new THREE.GridHelper(20, 20, 0x8888AA, 0x8888AA)
|
||||
this.scene.add(this.grid)
|
||||
if(options.grid){
|
||||
this.grid = new THREE.GridHelper(20, 20, 0x8888AA, 0x8888AA)
|
||||
this.scene.add(this.grid)
|
||||
}
|
||||
if(options.axes){
|
||||
this.axes = new THREE.AxesHelper(5, 5)
|
||||
this.scene.add(this.axes)
|
||||
}
|
||||
|
||||
// Cameras
|
||||
this.cameras.camPerspective = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
|
||||
@@ -47,15 +187,14 @@ export class Threetobus{
|
||||
renderEngine = new RenderingEngine(canvasEl, this.scene, this.cameras.cam2Dtop)
|
||||
} else if(mode=='3D') {
|
||||
renderEngine = new RenderingEngine(canvasEl, this.scene, this.cameras.camPerspective)
|
||||
renderEngine.addControls()
|
||||
} else console.error('Unknown rendering mode !')
|
||||
|
||||
renderEngine.addControls(mode)
|
||||
renderEngine.render()
|
||||
this.renderers.push(renderEngine)
|
||||
}
|
||||
|
||||
|
||||
buildFromJSON(desc){
|
||||
buildFromJSON(id, desc){ console.log('===buildFromJSON molecule1==>', desc)
|
||||
let obj
|
||||
if(desc.type === 'Mesh') {
|
||||
const geom = new THREE[desc.geometry.type](...(desc.geometry.args || []))
|
||||
@@ -75,14 +214,14 @@ export class Threetobus{
|
||||
// Recursively add children
|
||||
if(desc.children) {
|
||||
desc.children.forEach(childDesc => {
|
||||
obj.add(this.buildFromJSON(childDesc))
|
||||
const childId = (childDesc.idSuffix) ? `${id}_${childDesc.idSuffix}` : ''
|
||||
obj.add(this.buildFromJSON(childId, childDesc))
|
||||
})
|
||||
}
|
||||
|
||||
obj.name = id
|
||||
return obj
|
||||
}
|
||||
|
||||
|
||||
smoothRelMove(options){
|
||||
// options: object, dX, dY, dZ, delay, easing, easingMode
|
||||
// easings: Linear, Quadratic, Cubic, Quartic, Quintic, Sinusoidal, Exponential, Circular, Elastic, Back, Bounce
|
||||
@@ -110,13 +249,19 @@ class RenderingEngine{
|
||||
this.camera = camera
|
||||
}
|
||||
|
||||
addControls(){
|
||||
addControls(mode){
|
||||
this.controls = new OrbitControls(this.camera, this.canvasEl)
|
||||
window.addEventListener('resize', () => {
|
||||
this.camera.aspect = window.innerWidth / window.innerHeight
|
||||
this.camera.updateProjectionMatrix()
|
||||
this.renderer.setSize(window.innerWidth, window.innerHeight)
|
||||
})
|
||||
if(mode=='2D'){
|
||||
this.controls.maxPolarAngle = 0 // Math.PI / 2
|
||||
this.controls.minPolarAngle = 0 // Math.PI / 2
|
||||
} else if(mode=='3D'){
|
||||
}
|
||||
|
||||
this.controls.mouseButtons = {
|
||||
LEFT: THREE.MOUSE.ROTATE, // keep orbit on left
|
||||
MIDDLE: THREE.MOUSE.PAN, // pan with middle-click
|
||||
RIGHT: THREE.MOUSE.DOLLY // zoom with right-click
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
Reference in New Issue
Block a user