Add distance float position handling with backward compatibility #1
@@ -11,7 +11,25 @@ class PhysicalPositionMenu {
|
|||||||
{ value: 'downstream', label: '→ Downstream' , icon: '→' }
|
{ value: 'downstream', label: '→ Downstream' , icon: '→' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
// Distance contexts for each position
|
||||||
|
distanceContexts: {
|
||||||
|
upstream: {
|
||||||
|
description: 'Distance from parent inlet',
|
||||||
|
placeholder: 'e.g., 2.5 (meters before parent)',
|
||||||
|
helpText: 'How far upstream from the parent equipment'
|
||||||
|
},
|
||||||
|
downstream: {
|
||||||
|
description: 'Distance from parent outlet',
|
||||||
|
placeholder: 'e.g., 3.0 (meters after parent)',
|
||||||
|
helpText: 'How far downstream from the parent equipment'
|
||||||
|
},
|
||||||
|
atEquipment: {
|
||||||
|
description: 'Distance from parent start',
|
||||||
|
placeholder: 'e.g., 1.2 (meters from start)',
|
||||||
|
helpText: 'Position within the parent equipment boundaries'
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,6 +44,24 @@ class PhysicalPositionMenu {
|
|||||||
<!-- optgroups will be injected -->
|
<!-- optgroups will be injected -->
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Distance section -->
|
||||||
|
<div class="form-row">
|
||||||
|
<label> </label>
|
||||||
|
<input type="checkbox" id="node-input-hasDistance" style="display:inline-block; width:auto; margin-right:5px;">
|
||||||
|
<label for="node-input-hasDistance" style="width:auto;">Specify 1D Distance</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="distance-section" class="form-row" style="display:none;">
|
||||||
|
<label for="node-input-distance"><i class="fa fa-ruler"></i>Distance</label>
|
||||||
|
<div style="display:flex; align-items:center; width:70%;">
|
||||||
|
<input type="number" id="node-input-distance" step="0.1" min="0" style="width:60%;" placeholder="0.0">
|
||||||
|
<span style="margin-left:5px; margin-right:5px;">meters</span>
|
||||||
|
</div>
|
||||||
|
<div id="distance-help" class="form-tips" style="margin-left:105px; font-size:11px; color:#666;">
|
||||||
|
Select a position to see distance context
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -52,22 +88,40 @@ class PhysicalPositionMenu {
|
|||||||
window.EVOLV.nodes.${nodeName}.positionMenu.loadData = function(node) {
|
window.EVOLV.nodes.${nodeName}.positionMenu.loadData = function(node) {
|
||||||
const data = window.EVOLV.nodes.${nodeName}.menuData.position;
|
const data = window.EVOLV.nodes.${nodeName}.menuData.position;
|
||||||
const sel = document.getElementById('node-input-positionVsParent');
|
const sel = document.getElementById('node-input-positionVsParent');
|
||||||
if (!sel) return;
|
const hasDistanceCheck = document.getElementById('node-input-hasDistance');
|
||||||
sel.innerHTML = '';
|
const distanceInput = document.getElementById('node-input-distance');
|
||||||
(data.positionGroups||[]).forEach(grp => {
|
const distanceSection = document.getElementById('distance-section');
|
||||||
const optg = document.createElement('optgroup');
|
|
||||||
optg.label = grp.group;
|
//Load position options
|
||||||
grp.options.forEach(o=>{
|
if (sel) {
|
||||||
const opt = document.createElement('option');
|
sel.innerHTML = '';
|
||||||
opt.value = o.value;
|
(data.positionGroups||[]).forEach(grp => {
|
||||||
opt.textContent = o.label;
|
const optg = document.createElement('optgroup');
|
||||||
opt.setAttribute('data-icon', o.icon);
|
optg.label = grp.group;
|
||||||
optg.appendChild(opt);
|
grp.options.forEach(o=>{
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = o.value;
|
||||||
|
opt.textContent = o.label;
|
||||||
|
opt.setAttribute('data-icon', o.icon);
|
||||||
|
optg.appendChild(opt);
|
||||||
|
});
|
||||||
|
sel.appendChild(optg);
|
||||||
});
|
});
|
||||||
sel.appendChild(optg);
|
sel.value = node.positionVsParent || 'atEquipment';
|
||||||
});
|
}
|
||||||
// default to “atEquipment” if not set
|
|
||||||
sel.value = node.positionVsParent || 'atEquipment';
|
//Load distance values
|
||||||
|
if (hasDistanceCheck) {
|
||||||
|
hasDistanceCheck.checked = node.hasDistance || false;
|
||||||
|
distanceSection.style.display = hasDistanceCheck.checked ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distanceInput) {
|
||||||
|
distanceInput.value = node.distance || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update distance context for current position
|
||||||
|
this.updateDistanceContext(node.positionVsParent || 'atEquipment', data.distanceContexts);
|
||||||
};
|
};
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -77,24 +131,86 @@ class PhysicalPositionMenu {
|
|||||||
return `
|
return `
|
||||||
// PhysicalPosition events for ${nodeName}
|
// PhysicalPosition events for ${nodeName}
|
||||||
window.EVOLV.nodes.${nodeName}.positionMenu.wireEvents = function(node) {
|
window.EVOLV.nodes.${nodeName}.positionMenu.wireEvents = function(node) {
|
||||||
// no dynamic behavior
|
const positionSel = document.getElementById('node-input-positionVsParent');
|
||||||
|
const hasDistanceCheck = document.getElementById('node-input-hasDistance');
|
||||||
|
const distanceSection = document.getElementById('distance-section');
|
||||||
|
const data = window.EVOLV.nodes.${nodeName}.menuData.position;
|
||||||
|
|
||||||
|
// Toggle distance section visibility
|
||||||
|
if (hasDistanceCheck && distanceSection) {
|
||||||
|
hasDistanceCheck.addEventListener('change', function() {
|
||||||
|
distanceSection.style.display = this.checked ? 'block' : 'none';
|
||||||
|
|
||||||
|
// Clear distance if unchecked
|
||||||
|
if (!this.checked) {
|
||||||
|
const distanceInput = document.getElementById('node-input-distance');
|
||||||
|
if (distanceInput) {
|
||||||
|
distanceInput.value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update distance context when position changes
|
||||||
|
if (positionSel) {
|
||||||
|
positionSel.addEventListener('change', function() {
|
||||||
|
const position = this.value;
|
||||||
|
window.EVOLV.nodes.${nodeName}.positionMenu.updateDistanceContext(position, data.distanceContexts);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function to update distance context
|
||||||
|
window.EVOLV.nodes.${nodeName}.positionMenu.updateDistanceContext = function(position, contexts) {
|
||||||
|
const distanceInput = document.getElementById('node-input-distance');
|
||||||
|
const distanceHelp = document.getElementById('distance-help');
|
||||||
|
|
||||||
|
const context = contexts && contexts[position];
|
||||||
|
|
||||||
|
if (context && distanceInput && distanceHelp) {
|
||||||
|
distanceInput.placeholder = context.placeholder || '0.0';
|
||||||
|
distanceHelp.textContent = context.helpText || 'Enter distance in meters';
|
||||||
|
}
|
||||||
};
|
};
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6) Save-logic injector
|
// 6) Save-logic injector
|
||||||
getSaveInjectionCode(nodeName) {
|
getSaveInjectionCode(nodeName) {
|
||||||
return `
|
return `
|
||||||
// PhysicalPosition Save injection for ${nodeName}
|
// PhysicalPosition Save injection for ${nodeName}
|
||||||
window.EVOLV.nodes.${nodeName}.positionMenu.saveEditor = function(node) {
|
window.EVOLV.nodes.${nodeName}.positionMenu.saveEditor = function(node) {
|
||||||
const sel = document.getElementById('node-input-positionVsParent');
|
const sel = document.getElementById('node-input-positionVsParent');
|
||||||
node.positionVsParent = sel? sel.value : 'atEquipment';
|
const hasDistanceCheck = document.getElementById('node-input-hasDistance');
|
||||||
node.positionLabel = sel? sel.options[sel.selectedIndex].textContent : 'At Equipment';
|
const distanceInput = document.getElementById('node-input-distance');
|
||||||
node.positionIcon = sel? sel.options[sel.selectedIndex].getAttribute('data-icon') : 'fa fa-cog';
|
|
||||||
return true;
|
// Save existing position data
|
||||||
};
|
node.positionVsParent = sel ? sel.value : 'atEquipment';
|
||||||
`;
|
node.positionLabel = sel ? sel.options[sel.selectedIndex].textContent : 'At Equipment';
|
||||||
}
|
node.positionIcon = sel ? sel.options[sel.selectedIndex].getAttribute('data-icon') : 'fa fa-cog';
|
||||||
|
|
||||||
|
// Save distance data (NEW)
|
||||||
|
node.hasDistance = hasDistanceCheck ? hasDistanceCheck.checked : false;
|
||||||
|
|
||||||
|
if (node.hasDistance && distanceInput && distanceInput.value) {
|
||||||
|
node.distance = parseFloat(distanceInput.value) || 0;
|
||||||
|
node.distanceUnit = 'm'; // Fixed to meters for now
|
||||||
|
|
||||||
|
// Generate distance description based on position
|
||||||
|
const contexts = window.EVOLV.nodes.${nodeName}.menuData.position.distanceContexts;
|
||||||
|
const context = contexts && contexts[node.positionVsParent];
|
||||||
|
node.distanceDescription = context ? context.description : 'Distance from parent';
|
||||||
|
} else {
|
||||||
|
// Clear distance data if not specified
|
||||||
|
delete node.distance;
|
||||||
|
delete node.distanceUnit;
|
||||||
|
delete node.distanceDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
// 7) Compose everything into one client bundle
|
// 7) Compose everything into one client bundle
|
||||||
getClientInitCode(nodeName) {
|
getClientInitCode(nodeName) {
|
||||||
|
|||||||
Reference in New Issue
Block a user