Skip to content
Snippets Groups Projects
Commit bb3ba7e6 authored by Benedikt's avatar Benedikt
Browse files

improved MeasEQ render

parent d02a0070
No related branches found
No related tags found
No related merge requests found
Pipeline #52241 passed
......@@ -5,7 +5,7 @@ import JSONEditor from 'jsoneditor';
import 'jsoneditor/dist/jsoneditor.css';
import { UsedMethodsRenderer } from './UsedMethodsRenderer.js';
import { InfluenceConditionsRenderer } from './InfluenceConditionsRenderer.js';
import {MeasuringEquipmentsRenderer} from './MeasuringEquipmentRenderer.js';
const palette = [
'#1f77b4',
'#ff7f0e',
......@@ -114,6 +114,16 @@ export function renderMeasurementResults(measurementResults, language) {
influenceDetails.appendChild(influenceSummary);
influenceDetails.appendChild(influenceRenderer.render());
tabPanel.appendChild(influenceDetails);
// *** NEW: Render Measuring Equipments using the new renderer (collapsible by default) ***
const equipmentsRenderer = new MeasuringEquipmentsRenderer(result['dcc:measuringEquipments'], language);
const equipmentsDetails = document.createElement('details');
equipmentsDetails.open = false;
const equipmentsSummary = document.createElement('summary');
equipmentsSummary.textContent = 'Measuring Equipments';
equipmentsDetails.appendChild(equipmentsSummary);
equipmentsDetails.appendChild(equipmentsRenderer.render());
tabPanel.appendChild(equipmentsDetails);
tabContent.appendChild(tabPanel);
});
......@@ -161,7 +171,8 @@ function renderInfluenceConditions(measurementResult, language) {
return container;
}
// Helper to render a single measurement result (charts, tables, etc.)
// In src/renderers/MeasurementRenderer.js, update the renderSingleMeasurementResult function:
export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
console.debug('renderSingleMeasurementResult called with:', resultObj);
tabPanel.innerHTML = '';
......@@ -227,11 +238,12 @@ export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
}
});
// Build header texts using dsiUnits conversion.
const dataHeaders = dataQuantities.map((q, idx) => {
let headerText = q.getName(language);
let unit = q.getUnit({ oneLine: true, wrapper: 'span' });
if (!headerText.toLowerCase().includes(" in ")) {
headerText = headerText + " in " + unit;
headerText = `${headerText} in ${unit}`;
}
return headerText;
});
......@@ -258,7 +270,8 @@ export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
tabPanel.appendChild(scalingContainer);
const xAxisContainer = document.createElement('div');
xAxisContainer.innerHTML = '<strong>Select X-Axis:</strong> ';
// Change header text for X-axis selector column
xAxisContainer.innerHTML = '<strong>Frequency in Hz (selected X):</strong> ';
indexQuantities.forEach((q, idx) => {
let nameStr = q.getName(language) || ('Index ' + idx);
const radio = document.createElement('input');
......@@ -286,13 +299,12 @@ export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
tolContainer.appendChild(tolLabel);
tabPanel.appendChild(tolContainer);
// Create containers for plots and table.
// Create containers for plots and table, add extra spacing between them.
const subplotsContainer = document.createElement('div');
subplotsContainer.id = 'subplotsContainer';
tabPanel.appendChild(subplotsContainer);
const tableContainer = document.createElement('div');
tableContainer.id = 'tableContainer';
// Add extra spacing between plots and table
tableContainer.style.marginTop = '20px';
tabPanel.appendChild(tableContainer);
......@@ -302,14 +314,15 @@ export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
const selectedIndex = selectedRadio.value;
const xQuantity = indexQuantities[selectedIndex];
const xValues = xQuantity.getValues();
// Get xUnit using dsiUnits conversion with oneLine true
// Get xUnit using dsiUnits conversion with oneLine true.
const xUnit = xQuantity.getUnit({ oneLine: true, wrapper: 'span' });
const XQuantityName = xQuantity.getName(language);
console.debug('Selected X-Axis values:', xValues);
console.debug('X-Axis unit:', xUnit);
const headers = [];
headers.push(XQuantityName+' in ' + xUnit + ' (selected X)');
// Use the new header format for the X-axis column.
headers.push(`${XQuantityName} in ${xUnit} (selected X)`);
const dataValues = [];
const uncertaintiesArray = [];
......@@ -321,7 +334,8 @@ export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
uncertaintiesArray.push(info.uncertainty || []);
conformityArray.push(info.conformity ? info.conformity.getConformityValues() : []);
});
headers.push('Comments');
// Remove the Comments column entirely
// headers.push('Comments');
const tableData = [headers];
for (let i = 0; i < xValues.length; i++) {
......@@ -330,14 +344,13 @@ export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
extraInfo.forEach((info, idx) => {
let cellValue = (dataValues[idx][i] !== undefined) ? dataValues[idx][i] : '';
if (uncertaintiesArray[idx] && uncertaintiesArray[idx][i] !== undefined) {
cellValue = cellValue + ' ± ' + uncertaintiesArray[idx][i];
cellValue = `${cellValue} ± ${uncertaintiesArray[idx][i]}`;
}
row.push(cellValue);
if (info.conformity) {
row.push(conformityArray[idx][i] || '');
}
});
row.push(extraInfo.map(info => info.comment || '').filter(c => c).join(' ; '));
tableData.push(row);
}
renderTable(tableData, computeConformityMapping());
......@@ -346,7 +359,7 @@ export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
dataQuantities.forEach((q, idx) => {
const unit = q.getUnit({ oneLine: false });
if (!unitGroups[unit]) { unitGroups[unit] = []; }
const header = dataHeaders[idx];
const headerText = dataHeaders[idx];
let values = q.getValues();
const uncertainty = uncertaintiesArray[idx];
const conformity = conformityArray[idx];
......@@ -357,7 +370,15 @@ export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
}
return defaultColor;
});
unitGroups[unit].push({ name: header, y: values, uncertainty, conformity, defaultColor, markerColor: markerColorArray, index: idx });
unitGroups[unit].push({
name: headerText,
y: values,
uncertainty,
conformity,
defaultColor,
markerColor: markerColorArray,
index: idx
});
});
subplotsContainer.innerHTML = '';
......@@ -371,7 +392,7 @@ export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
subplotsContainer.appendChild(graphDiv);
plotDivs.push(graphDiv);
const groupTraces = group.map(trace => {
let tooltip = 'X: %{x} ' + xUnit + ' | ' + trace.name + ': %{y}';
let tooltip = `X: %{x} ${xUnit} | ${trace.name}: %{y}`;
if (trace.conformity && trace.conformity.length > 0) {
tooltip += ' | Conformity: %{customdata}';
}
......@@ -436,7 +457,7 @@ export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
let xaxisTitle = '';
if (groupIdx === unitKeys.length - 1) {
let xLabel = 'X: ' + xQuantity.getName(language);
xaxisTitle = '<b>' + xLabel + ' in ' + xUnit + '</b>';
xaxisTitle = `<b>${xLabel} in ${xUnit}</b>`;
}
const logX = tabPanel.querySelector('#logXToggle').checked;
const logY = tabPanel.querySelector('#logYToggle').checked;
......@@ -462,7 +483,6 @@ export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
margin: { t: 20, b: 40 }
};
Plotly.newPlot(graphDiv, allTraces, layout).then(() => {
// Force a resize to ensure full width
setTimeout(() => {
if (graphDiv.offsetWidth > 0 && graphDiv.offsetHeight > 0) {
Plotly.Plots.resize(graphDiv);
......@@ -471,7 +491,7 @@ export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
}
}, 100);
const caption = document.createElement('div');
caption.innerHTML = '<b>' + group[0].name + '</b>';
caption.innerHTML = `<b>${group[0].name}</b>`;
caption.style.textAlign = 'center';
caption.style.marginBottom = '5px';
graphDiv.parentNode.insertBefore(caption, graphDiv);
......@@ -510,7 +530,11 @@ export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
}
} else {
cell.textContent = cellData;
if (tableData[0][cellIndex] && tableData[0][cellIndex].toLowerCase().includes('conformity') && conformityMapping[cellIndex] !== undefined) {
if (
tableData[0][cellIndex] &&
tableData[0][cellIndex].toLowerCase().includes('conformity') &&
conformityMapping[cellIndex] !== undefined
) {
const confKey = cellData.trim().toLowerCase();
if (conformityColors[confKey]) {
cell.style.backgroundColor = conformityColors[confKey];
......@@ -521,8 +545,12 @@ export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
cell.style.border = '1px solid #ccc';
tr.appendChild(cell);
});
tr.addEventListener('mouseover', () => { tr.style.backgroundColor = '#eef'; });
tr.addEventListener('mouseout', () => { tr.style.backgroundColor = ''; });
tr.addEventListener('mouseover', () => {
tr.style.backgroundColor = '#eef';
});
tr.addEventListener('mouseout', () => {
tr.style.backgroundColor = '';
});
table.appendChild(tr);
});
tableContainer.appendChild(table);
......@@ -544,7 +572,9 @@ export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
function highlightTableRow(rowIndex) {
const rows = tabPanel.querySelector('#tableContainer').querySelectorAll('tr');
if (rows[rowIndex]) { rows[rowIndex].style.backgroundColor = '#fee'; }
if (rows[rowIndex]) {
rows[rowIndex].style.backgroundColor = '#fee';
}
}
function clearTableRowHighlights() {
......@@ -554,7 +584,9 @@ export function renderSingleMeasurementResult(resultObj, language, tabPanel) {
updateVisualization();
const radios = tabPanel.querySelectorAll('input[name="xAxisSelect"]');
radios.forEach(radio => { radio.addEventListener('change', updateVisualization); });
radios.forEach(radio => {
radio.addEventListener('change', updateVisualization);
});
tabPanel.querySelector('#logXToggle').addEventListener('change', updateVisualization);
tabPanel.querySelector('#logYToggle').addEventListener('change', updateVisualization);
tabPanel.querySelector('#toleranceToggle').addEventListener('change', () => {
......
// src/renderers/MeasuringEquipmentRenderer.js
import { DCCRealListQuantity } from "../dccQuantity.js";
// src/renderers/MeasuringEquipmentsRenderer.js
import { DCCRealListQuantity } from '../dccQuantity.js';
export class MeasuringEquipmentRenderer {
constructor(equipmentData, language) {
// equipmentData may be a single object or an array of measuringEquipment elements
this.data = Array.isArray(equipmentData)
? equipmentData
: [equipmentData];
export class MeasuringEquipmentsRenderer {
constructor(measuringEquipmentsData, language) {
this.data = measuringEquipmentsData;
this.language = language;
}
render() {
const container = document.createElement("div");
container.innerHTML = `<h3>Measuring Equipment</h3>`;
this.data.forEach((equip) => {
// Create collapsible section for each equipment
const details = document.createElement("details");
details.style.border = "1px solid #ccc";
details.style.padding = "8px";
details.style.marginBottom = "10px";
// Create a container without an extra header (if you prefer to not duplicate the title)
const container = document.createElement('div');
// Optionally, you could add a header here if desired:
// container.innerHTML = `<h3>Measuring Equipments</h3>`;
// Build the summary (collapsed view)
const summary = document.createElement("summary");
summary.style.fontWeight = "bold";
// Equipment name
const equipName = this._getText(equip["dcc:name"]);
let equipments = this.data && this.data['dcc:measuringEquipment'];
if (!equipments) {
container.textContent = 'No measuring equipments data available.';
return container;
}
if (!Array.isArray(equipments)) {
equipments = [equipments];
}
// Reset default browser styles for details and summary
const detailsStyle = 'margin: 0; padding: 0; border: 1px solid #ccc; padding: 8px; margin-bottom: 10px;';
const summaryStyle = 'margin: 0; padding: 0; list-style: none;';
equipments.forEach(equipment => {
// Each equipment is rendered in a collapsible details block.
const details = document.createElement('details');
details.setAttribute('style', detailsStyle);
details.open = false; // collapsed by default
// Create summary for collapsed view
const summary = document.createElement('summary');
summary.setAttribute('style', summaryStyle);
// Equipment name (language‑specific)
const eqName = this._getText(equipment['dcc:name']);
// Manufacturer name (if available)
let manufacturerName = "";
if (equip["dcc:manufacturer"] && equip["dcc:manufacturer"]["dcc:name"]) {
manufacturerName = this._getText(equip["dcc:manufacturer"]["dcc:name"]);
}
const manufacturer = equipment['dcc:manufacturer']
? this._getText(equipment['dcc:manufacturer']['dcc:name'])
: '';
// Model
const model = equip["dcc:model"] ? equip["dcc:model"].trim() : "";
const model = equipment['dcc:model'] ? equipment['dcc:model'] : '';
// First identification (if available)
let firstId = "";
if (
equip["dcc:identifications"] &&
equip["dcc:identifications"]["dcc:identification"]
) {
let ids = equip["dcc:identifications"]["dcc:identification"];
if (!Array.isArray(ids)) {
ids = [ids];
}
const id0 = ids[0];
// Get identification name (small label) and value
const idName = this._getText(id0["dcc:name"]);
const idValue = id0["dcc:value"] ? id0["dcc:value"].trim() : "";
firstId = `<span style="font-size:smaller;">${idName}: ${idValue}</span>`;
let firstId = '';
if (equipment['dcc:identifications'] && equipment['dcc:identifications']['dcc:identification']) {
let ident = equipment['dcc:identifications']['dcc:identification'];
if (!Array.isArray(ident)) { ident = [ident]; }
const first = ident[0];
firstId = `<small>${this._getText(first['dcc:name'])}: ${first['dcc:value']}</small>`;
}
summary.innerHTML = `${equipName}${manufacturerName} ${model} ${firstId}`;
summary.innerHTML = `<strong>${eqName}</strong>${manufacturer} – Model: ${model} ${firstId}`;
details.appendChild(summary);
// Expanded content
const contentDiv = document.createElement("div");
contentDiv.style.marginTop = "8px";
contentDiv.style.fontFamily = "sans-serif";
const contentDiv = document.createElement('div');
contentDiv.style.marginTop = '8px';
contentDiv.style.fontFamily = 'sans-serif';
// Render full identifications table
if (equip["dcc:identifications"] && equip["dcc:identifications"]["dcc:identification"]) {
const ids = Array.isArray(equip["dcc:identifications"]["dcc:identification"])
? equip["dcc:identifications"]["dcc:identification"]
: [equip["dcc:identifications"]["dcc:identification"]];
const idTable = document.createElement("table");
idTable.style.width = "100%";
idTable.style.borderCollapse = "collapse";
// Header row
const idHeaderRow = document.createElement("tr");
["Identification", "Issuer", "Value"].forEach((text) => {
const th = document.createElement("th");
th.textContent = text;
th.style.border = "1px solid #ccc";
th.style.padding = "4px";
idHeaderRow.appendChild(th);
// Render full identifications
if (equipment['dcc:identifications']) {
const identDiv = document.createElement('div');
identDiv.innerHTML = `<h4>Identifications</h4>`;
let ident = equipment['dcc:identifications']['dcc:identification'];
if (!Array.isArray(ident)) { ident = [ident]; }
ident.forEach(id => {
const idName = this._getText(id['dcc:name']);
const idValue = id['dcc:value'] || '';
const issuer = id['dcc:issuer'] || '';
identDiv.innerHTML += `<p><small>${idName} (${issuer}): ${idValue}</small></p>`;
});
idTable.appendChild(idHeaderRow);
// Data rows
ids.forEach((id) => {
const tr = document.createElement("tr");
// Identification name (small label)
const tdName = document.createElement("td");
tdName.style.border = "1px solid #ccc";
tdName.style.padding = "4px";
tdName.style.fontSize = "smaller";
tdName.textContent = this._getText(id["dcc:name"]);
tr.appendChild(tdName);
// Issuer
const tdIssuer = document.createElement("td");
tdIssuer.style.border = "1px solid #ccc";
tdIssuer.style.padding = "4px";
tdIssuer.textContent = id["dcc:issuer"] ? id["dcc:issuer"].trim() : "";
tr.appendChild(tdIssuer);
// Value
const tdValue = document.createElement("td");
tdValue.style.border = "1px solid #ccc";
tdValue.style.padding = "4px";
tdValue.textContent = id["dcc:value"] ? id["dcc:value"].trim() : "";
tr.appendChild(tdValue);
idTable.appendChild(tr);
});
contentDiv.appendChild(idTable);
contentDiv.appendChild(identDiv);
}
// Render measuring equipment quantities table (if available)
// Render measuring equipment quantities as a table if available
if (
equip["dcc:measuringEquipmentQuantities"] &&
equip["dcc:measuringEquipmentQuantities"]["dcc:measuringEquipmentQuantity"]
equipment['dcc:measuringEquipmentQuantities'] &&
equipment['dcc:measuringEquipmentQuantities']['dcc:measuringEquipmentQuantity']
) {
const qtys = Array.isArray(
equip["dcc:measuringEquipmentQuantities"]["dcc:measuringEquipmentQuantity"]
)
? equip["dcc:measuringEquipmentQuantities"]["dcc:measuringEquipmentQuantity"]
: [equip["dcc:measuringEquipmentQuantities"]["dcc:measuringEquipmentQuantity"]];
const qtyTable = document.createElement("table");
qtyTable.style.width = "100%";
qtyTable.style.borderCollapse = "collapse";
// Header row
const qtyHeaderRow = document.createElement("tr");
["Quantity", "Value", "Unit", "Uncertainty"].forEach((text) => {
const th = document.createElement("th");
const qtyData = equipment['dcc:measuringEquipmentQuantities']['dcc:measuringEquipmentQuantity'];
const quantities = Array.isArray(qtyData) ? qtyData : [qtyData];
const table = document.createElement('table');
table.style.width = '100%';
table.style.borderCollapse = 'collapse';
const headerRow = document.createElement('tr');
['Quantity', 'Value'].forEach(text => {
const th = document.createElement('th');
th.textContent = text;
th.style.border = "1px solid #ccc";
th.style.padding = "4px";
qtyHeaderRow.appendChild(th);
th.style.border = '1px solid #ccc';
th.style.padding = '4px';
headerRow.appendChild(th);
});
qtyTable.appendChild(qtyHeaderRow);
// Data rows: use DCCRealListQuantity for each measuringEquipmentQuantity
qtys.forEach((q) => {
const row = document.createElement("tr");
// Quantity name
const tdName = document.createElement("td");
tdName.style.border = "1px solid #ccc";
tdName.style.padding = "4px";
tdName.textContent = this._getText(q["dcc:name"]);
row.appendChild(tdName);
// Value
const tdValue = document.createElement("td");
tdValue.style.border = "1px solid #ccc";
tdValue.style.padding = "4px";
// Create a DCCRealListQuantity instance to extract values, unit, uncertainty
const realQty = new DCCRealListQuantity(q);
const values = realQty.getValues();
tdValue.textContent = values.join(" / ");
row.appendChild(tdValue);
// Unit
const tdUnit = document.createElement("td");
tdUnit.style.border = "1px solid #ccc";
tdUnit.style.padding = "4px";
const rawUnit = q["si:realListXMLList"] && q["si:realListXMLList"]["si:unitXMLList"]
? q["si:realListXMLList"]["si:unitXMLList"].trim()
: "";
if (rawUnit) {
const unitObj = new DSIUnit(rawUnit);
// Here we return plain text instead of HTML markup for the table cell
tdUnit.textContent = unitObj.toString();
}
row.appendChild(tdUnit);
// Uncertainty
const tdUnc = document.createElement("td");
tdUnc.style.border = "1px solid #ccc";
tdUnc.style.padding = "4px";
const uncValues = realQty.getUncertainty();
tdUnc.textContent = uncValues.length ? uncValues.join(" / ") : "";
row.appendChild(tdUnc);
qtyTable.appendChild(row);
table.appendChild(headerRow);
quantities.forEach(q => {
const tr = document.createElement('tr');
const nameCell = document.createElement('td');
nameCell.style.border = '1px solid #ccc';
nameCell.style.padding = '4px';
nameCell.textContent = this._getText(q['dcc:name']);
tr.appendChild(nameCell);
const valueCell = document.createElement('td');
valueCell.style.border = '1px solid #ccc';
valueCell.style.padding = '4px';
// Render value and unit using DCCRealListQuantity
let qtyObj = new DCCRealListQuantity(q);
valueCell.innerHTML = qtyObj.getValues().join(' ') + ' ' + qtyObj.getUnit({ oneLine: true });
tr.appendChild(valueCell);
table.appendChild(tr);
});
contentDiv.appendChild(qtyTable);
contentDiv.appendChild(table);
}
// Append expanded content to details
details.appendChild(contentDiv);
container.appendChild(details);
});
return container;
}
// Helper to extract language-specific text from a node
_getText(node) {
if (!node) return "";
const content = node["dcc:content"];
if (!node) return '';
const content = node['dcc:content'];
if (Array.isArray(content)) {
const match = content.find((item) => item.$ && item.$.lang === this.language) || content[0];
const match = content.find(item => item.$ && item.$.lang === this.language) || content[0];
return match._ || match;
}
return content._ || content;
}
// (Optional) You can add additional helper methods to render other parts of the data
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment