Load KF works

This commit is contained in:
STEINNI
2025-10-29 17:41:29 +00:00
parent f349ff38f4
commit dfab013abe
8 changed files with 105 additions and 21 deletions
+8
View File
@@ -17,6 +17,14 @@
} }
}, },
"/keyframes": { "/keyframes": {
"list": {
"uri": "/api/keyframes",
"method": "POST"
},
"get": {
"uri": "/api/keyframes/{kfId}",
"method": "GET"
},
"create": { "create": {
"uri": "/api/keyframes", "uri": "/api/keyframes",
"method": "PUT" "method": "PUT"
+5 -2
View File
@@ -6,7 +6,7 @@ if(!app.helpers) app.helpers = {}
*/ */
app.helpers.formBuilder = { app.helpers.formBuilder = {
fieldsFromJSON(fieldsObj, fieldsValues, fieldsetLabel=null){ fieldsFromJSON(fieldsObj, fieldsValues, fieldsetLabel=null, changeCB=null){
let allFields = [] let allFields = []
for(const propName in fieldsObj){ for(const propName in fieldsObj){
const fieldRow = ui.create(`<div class="cols-2"><label>${fieldsObj[propName].label}</label></div>`) const fieldRow = ui.create(`<div class="cols-2"><label>${fieldsObj[propName].label}</label></div>`)
@@ -18,11 +18,13 @@ app.helpers.formBuilder = {
component.setAttribute('type','number') component.setAttribute('type','number')
if('min' in fieldsObj[propName]) component.setAttribute('min', fieldsObj[propName].min) if('min' in fieldsObj[propName]) component.setAttribute('min', fieldsObj[propName].min)
if('max' in fieldsObj[propName]) component.setAttribute('max', fieldsObj[propName].max) if('max' in fieldsObj[propName]) component.setAttribute('max', fieldsObj[propName].max)
if(typeof(changeCB) == 'function') component.addEventListener('input', (evt) => { changeCB(evt, component) })
break break
case 'string': case 'string':
component = document.createElement('input') component = document.createElement('input')
component.setAttribute('name',propName) component.setAttribute('name',propName)
component.setAttribute('type','text') component.setAttribute('type','text')
if(typeof(changeCB) == 'function') component.addEventListener('input', (evt) => { changeCB(evt, component) })
break break
case 'boolean': case 'boolean':
component = document.createElement('bz-toggler') component = document.createElement('bz-toggler')
@@ -30,6 +32,7 @@ app.helpers.formBuilder = {
component.setAttribute('trueValue','1') component.setAttribute('trueValue','1')
component.setAttribute('falseValue','0') component.setAttribute('falseValue','0')
fieldRow.append(component.el) fieldRow.append(component.el)
if(typeof(changeCB) == 'function') component.addEventListener('change', (evt) => { changeCB(evt, component) })
break break
case 'list': case 'list':
component = document.createElement('bz-select') component = document.createElement('bz-select')
@@ -37,6 +40,7 @@ app.helpers.formBuilder = {
component.fillOptions( fieldsObj[propName].choices.map(item => { component.fillOptions( fieldsObj[propName].choices.map(item => {
return({ markup: `${item}`, value: item}) return({ markup: `${item}`, value: item})
})) }))
if(typeof(changeCB) == 'function') component.addEventListener('change', (evt) => { changeCB(evt, component) })
break break
default: default:
console.warn(`Unknown field type ${fieldsObj[propName].type}`) console.warn(`Unknown field type ${fieldsObj[propName].type}`)
@@ -90,5 +94,4 @@ app.helpers.formBuilder = {
return(result) return(result)
}, },
} }
+1 -1
View File
@@ -160,7 +160,7 @@ app.helpers.helpers3D = {
}, },
getNamedParent(obj) { getNamedParent(obj) {
while (obj && !obj.name) { while (obj && ((!obj.name) || (obj.name.includes('_'))) ) {
obj = obj.parent obj = obj.parent
} }
return obj return obj
+20
View File
@@ -5,6 +5,25 @@ class KeyframesModel extends WindozModel {
this.ressource = '/keyframes' this.ressource = '/keyframes'
} }
async list(kfId, prevKFId='') {
let endpoint = {...app.config.api[this.ressource].list}
const filters = {}
//Caution, undefined is != NULL here, because prev_kfId ull means root, while undefined means no filtering
if((typeof(kfId) != 'undefined') && (kfId!=='')) filters['kfId'] = kfId
if((typeof(prevKFId) != 'undefined') && (prevKFId!=='')) filters['prevKFId'] = prevKFId
return (
this.request(endpoint.uri, endpoint.method, filters)
)
}
async getKeyframe(kfId){
let endpoint = {...app.config.api[this.ressource].get}
endpoint.uri = endpoint.uri.replace('{kfId}', kfId)
return (
this.request(endpoint.uri, endpoint.method, kfId)
)
}
async create(kfData, prevKFId) { async create(kfData, prevKFId) {
let endpoint = {...app.config.api[this.ressource].create} let endpoint = {...app.config.api[this.ressource].create}
return ( return (
@@ -24,6 +43,7 @@ class KeyframesModel extends WindozModel {
const { position, speed, ...storeValues} = data[aid].values const { position, speed, ...storeValues} = data[aid].values
return({ return({
aid: aid, aid: aid,
type: data[aid].type,
storeValues: storeValues, storeValues: storeValues,
gpsValues: { position: data[aid].values.position, speed: data[aid].values.speed } gpsValues: { position: data[aid].values.position, speed: data[aid].values.speed }
}) })
+2 -2
View File
@@ -32,7 +32,7 @@ bz-select > button::after {
bz-select > div.options-container{ bz-select > div.options-container{
pointer-events: none; pointer-events: none;
position: absolute; position: absolute;
top: 2em; top: 1.8em;
left: 0; left: 0;
width: 100%; width: 100%;
z-index: 99; z-index: 99;
@@ -45,7 +45,7 @@ bz-select option{
background-color: #DDD; background-color: #DDD;
border: 1px solid black; border: 1px solid black;
color: #000; color: #000;
padding: 0.2em .2em .3em .5em; padding: 0.2em .2em .5em .5em;
margin: -1em 0 0 0; margin: -1em 0 0 0;
border-radius: 1em; border-radius: 1em;
height: 1em; height: 1em;
+8 -3
View File
@@ -33,7 +33,7 @@
text-align: center; text-align: center;
margin-top: .3em; margin-top: .3em;
} }
.kf-editor article.left-pane > section > bz-select{ margin: 0 0.5em 1em 0.5em; } .kf-editor article.left-pane > section > bz-select{ margin: 1em 0.5em 1em 0.5em; }
.kf-editor article.kfArena section{ .kf-editor article.kfArena section{
padding: 0; padding: 0;
height: 100%; height: 100%;
@@ -62,7 +62,7 @@
color: #DDD; color: #DDD;
padding: 0 0 0 0; padding: 0 0 0 0;
} }
.kf-editor button[data-trigger="onAddAgent"] { background-color: #473; } .kf-editor button[data-trigger="onAddAgent"] { background-color: #6B5; }
.kf-editor button[data-trigger="onRemoveAgent"] { background-color: #A00; } .kf-editor button[data-trigger="onRemoveAgent"] { background-color: #A00; }
.kf-editor button[data-trigger="onSaveKF"] { background-color: #367; } .kf-editor button[data-trigger="onSaveKF"] { background-color: #367; }
.kf-editor button[data-trigger="onResetKF"] { background-color: #A00; } .kf-editor button[data-trigger="onResetKF"] { background-color: #A00; }
@@ -76,16 +76,21 @@
margin-top: 1em; margin-top: 1em;
font-size: .8em; font-size: .8em;
} }
.kf-editor bz-select[data-output="keyframesSelector"]{
margin-top:1em;
}
</style> </style>
<div class="kf-editor cols-3"> <div class="kf-editor cols-3">
<article eiccard class="left-pane"> <article eiccard class="left-pane">
<section class="selector"> <section class="selector">
<header><h1>Agent type browser</h1></header> <header><h1>Agent type browser</h1></header>
<canvas data-output="agentSampleCanvas"></canvas> <canvas data-output="agentSampleCanvas"></canvas>
<bz-select label="Agent type..." data-output="agentsSelector"></bz-select> <bz-select label="Select agent type..." data-output="agentsSelector"></bz-select>
</section> </section>
<section class="browser"> <section class="browser">
<header><h1>Keyframes browser</h1></header> <header><h1>Keyframes browser</h1></header>
<!-- Temporary... -->
<bz-select label="Existing keyframes..." data-output="keyframesSelector"></bz-select>
</section> </section>
</article> </article>
<article eiccard class="kfArena"> <article eiccard class="kfArena">
+46 -11
View File
@@ -44,6 +44,16 @@ class KeyframeView extends WindozDomContent {
this.agentPreview.startRendering() this.agentPreview.startRendering()
this.agentPreview.animation = true this.agentPreview.animation = true
this.models.keyframes.list('', null).then(data => data.payload).then(kflist => {
this.outputs.keyframesSelector.fillOptions(kflist.map(item => {
return({
markup: item.ekf_name,
value: item.ekf_uuid
})
}))
})
this.outputs.keyframesSelector.addEventListener('change',this.onChangeKeyframe.bind(this))
this.kfArena = new app.LoadedModules.kfArena(this.outputs.kfArenaCanvas, this.agentSprites) this.kfArena = new app.LoadedModules.kfArena(this.outputs.kfArenaCanvas, this.agentSprites)
this.kfArena.onclickAgent = this.onclickAgent.bind(this) this.kfArena.onclickAgent = this.onclickAgent.bind(this)
this.kfArena.startRendering() this.kfArena.startRendering()
@@ -70,6 +80,17 @@ class KeyframeView extends WindozDomContent {
} }
} }
async onChangeKeyframe(event){
if(!this.outputs.keyframesSelector.value) return
let kfData = await this.models.keyframes.getKeyframe(this.outputs.keyframesSelector.value).then(data => data.payload)
this.currentKeyframe = {
kfId: kfData.info.ekf_uuid,
kfName: kfData.info.ekf_name,
prevKfId: kfData.info.ekf_prev_uuid,
}
this.kfArena.reloadAgents(kfData.agents)
}
onclickAgent(obj3D){ onclickAgent(obj3D){
const aid = obj3D.name const aid = obj3D.name
this.kfArena.highlighted3DObjects.length = 0 //truncate but keep the ref ! this.kfArena.highlighted3DObjects.length = 0 //truncate but keep the ref !
@@ -77,11 +98,13 @@ class KeyframeView extends WindozDomContent {
this.currentlySelectedAid = null this.currentlySelectedAid = null
} else { // Select } else { // Select
this.currentlySelectedAid = aid this.currentlySelectedAid = aid
this.kfArena.highlighted3DObjects.push(obj3D) if(this.kfArena.agents[aid]) {
this.fillAgentProperties(aid, this.kfArena.agents[aid].props, this.kfArena.agents[aid].values) this.kfArena.highlighted3DObjects.push(obj3D)
this.notUserChange = true this.fillAgentProperties(aid, this.kfArena.agents[aid].props, this.kfArena.agents[aid].values)
this.outputs.agentsSelector.value = this.kfArena.agents[aid].type this.notUserChange = true
this.notUserChange = false this.outputs.agentsSelector.value = this.kfArena.agents[aid].type
this.notUserChange = false
}
} }
this.updateKfButtons() this.updateKfButtons()
} }
@@ -100,11 +123,18 @@ class KeyframeView extends WindozDomContent {
else { this.outputs.btnSaveKF.disabled = true } else { this.outputs.btnSaveKF.disabled = true }
} }
onPropsChanged(evt, comp){
console.log('onPropsChanged', comp, evt)
if(this.currentlySelectedAid && this.kfArena.agents[this.currentlySelectedAid]){
}
}
fillAgentProperties(aid, agentProps, agentValues = {}){ fillAgentProperties(aid, agentProps, agentValues = {}){
this.outputs.agentProperties.innerHTML = ` this.outputs.agentProperties.innerHTML = `
<div data-output="agentId">ID: ${aid}</div> <div data-output="agentId">ID: ${aid}</div>
` `
this.outputs.agentProperties.append(...this.fieldsFromJSON(agentProps, agentValues, 'Internal properties')) this.outputs.agentProperties.append(...this.fieldsFromJSON(agentProps, agentValues, 'Internal properties', this.onPropsChanged.bind(this)))
this.outputs.agentProperties.append(...this.fieldsFromJSON({ this.outputs.agentProperties.append(...this.fieldsFromJSON({
"position.x": { "position.x": {
label: "Position X", label: "Position X",
@@ -121,7 +151,7 @@ class KeyframeView extends WindozDomContent {
type: "number", type: "number",
default: "0" default: "0"
}, },
}, agentValues, 'Coordinates')) }, agentValues, 'Coordinates', this.onPropsChanged.bind(this)))
this.outputs.agentProperties.append(...this.fieldsFromJSON({ this.outputs.agentProperties.append(...this.fieldsFromJSON({
"speed.x": { "speed.x": {
label: "Speed X", label: "Speed X",
@@ -138,21 +168,26 @@ class KeyframeView extends WindozDomContent {
type: "number", type: "number",
default: "0" default: "0"
}, },
}, agentValues, 'Speed vector')) }, agentValues, 'Speed vector', this.onPropsChanged.bind(this)))
this.outputs.btnAddAgent.disabled = false this.outputs.btnAddAgent.disabled = false
this.setupRefs() this.setupRefs()
} }
async onSaveKF(evt){ async onSaveKF(evt){
let result = { success: true }
if(!this.currentKeyframe.kfId){ // Create first (and get new kfId) if(!this.currentKeyframe.kfId){ // Create first (and get new kfId)
this.currentKeyframe.kfName = this.outputs.kfName.value this.currentKeyframe.kfName = this.outputs.kfName.value
const result = await this.models.keyframes.create(this.currentKeyframe) result = await this.models.keyframes.create(this.currentKeyframe)
this.currentKeyframe.kfId = result.payload.kfId this.currentKeyframe.kfId = result.payload.kfId
} else if(this.currentKeyframe.kfName != this.outputs.kfName.value){ //rename } else if(this.currentKeyframe.kfName != this.outputs.kfName.value){ //rename
this.currentKeyframe.kfName = this.outputs.kfName.value this.currentKeyframe.kfName = this.outputs.kfName.value
const result = await this.models.keyframes.rename(this.currentKeyframe) result = await this.models.keyframes.rename(this.currentKeyframe)
console.log(result)
} }
await this.models.keyframes.save(this.currentKeyframe.kfId, this.kfArena.agents)
if(result.success){
await this.models.keyframes.save(this.currentKeyframe.kfId, this.kfArena.agents)
}
} }
} }
+15 -2
View File
@@ -124,9 +124,12 @@ export class kfArena{
} }
addAgent(typeId, aid, properties, values){ addAgent(typeId, aid, properties, values){ console.log('==addAgent==>',typeId, aid, properties, values)
const agentSprite = this.agentSprites.find(item => item.atp_id==typeId) const agentSprite = this.agentSprites.find(item => item.atp_id==typeId)
if(!agentSprite) return if(!agentSprite) {
console.warn(`No sprite for type: ${typeId}`)
return
}
const agentObj = this.agentFromJSON(aid, agentSprite.asp_3d) const agentObj = this.agentFromJSON(aid, agentSprite.asp_3d)
agentObj.position.set(values.position.x, values.position.z, values.position.y ) agentObj.position.set(values.position.x, values.position.z, values.position.y )
@@ -146,6 +149,16 @@ export class kfArena{
if(aid in this.agents) delete(this.agents[aid]) if(aid in this.agents) delete(this.agents[aid])
} }
reloadAgents(agents){
for(const aid in this.agents){
this.removeAgent(aid)
}
console.log('====>', agents)
for(const agent of agents){
this.addAgent(agent.ekfs_atp_id, agent.aid, agent.props, {...agent.gps_values, ...agent.store_values})
}
}
// getAllAgents(){ // getAllAgents(){
// const agents = [] // const agents = []
// scene.traverse(o => o.name && names.push(o.name)) // scene.traverse(o => o.name && names.push(o.name))