From 6958d90a21e7f22945625307d7cd86124fc09437 Mon Sep 17 00:00:00 2001 From: Benedikt Seeger <benedikt.seeger@ptb.de> Date: Thu, 27 Feb 2025 14:20:30 +0100 Subject: [PATCH] added conformety parsing --- src/dccQuantity.js | 110 ++++++++++++++++++++++++-- src/renderers/MeasurementRenderer.js | 112 ++++++++++++++------------- 2 files changed, 160 insertions(+), 62 deletions(-) diff --git a/src/dccQuantity.js b/src/dccQuantity.js index 8387c51..ec6afdf 100644 --- a/src/dccQuantity.js +++ b/src/dccQuantity.js @@ -20,6 +20,18 @@ export class DCCQuantity { } return content._ || content; } + + getConformity(language) { + if (this.jsonData['dcc:measurementMetaData'] && this.jsonData['dcc:measurementMetaData']['dcc:metaData']) { + let metaData = this.jsonData['dcc:measurementMetaData']['dcc:metaData']; + if (!Array.isArray(metaData)) metaData = [metaData]; + const confMeta = metaData.find(m => m.$ && m.$.refType && m.$.refType.includes('basic_conformity')); + if (confMeta) { + return new DCCConformity(confMeta, language); + } + } + return null; + } } export class DCCRealListQuantity extends DCCQuantity { @@ -71,9 +83,9 @@ export class DCCRealQuantity extends DCCQuantity { getValues() { const realData = this.jsonData['si:real']; if (realData && realData['si:value']) { - return parseFloat(realData['si:value']); + return [parseFloat(realData['si:value'])]; } - return null; + return []; } getUnit() { @@ -85,17 +97,99 @@ export class DCCRealQuantity extends DCCQuantity { } return ''; } + getUncertainty() { - const realList = this.jsonData['si:real']; + const realData = this.jsonData['si:real']; if ( - realList && - realList['si:measurementUncertaintyUnivariate'] && - realList['si:measurementUncertaintyUnivariate']['si:expandedMU'] && - realList['si:measurementUncertaintyUnivariate']['si:expandedMU']['si:valueExpandedMU'] + realData && + realData['si:measurementUncertaintyUnivariate'] && + realData['si:measurementUncertaintyUnivariate']['si:expandedMU'] && + realData['si:measurementUncertaintyUnivariate']['si:expandedMU']['si:valueExpandedMU'] ) { - const errStr = realList['si:measurementUncertaintyUnivariate']['si:expandedMU']['si:valueExpandedMU']; + const errStr = realData['si:measurementUncertaintyUnivariate']['si:expandedMU']['si:valueExpandedMU']; return errStr.trim().split(/\s+/).map(v => parseFloat(v)); } return []; } } + +export class DCCConformity { + constructor(metaDataJson, language) { + this.metaDataJson = metaDataJson; + this.language = language; + } + + getConformityValues() { + const confList = this.metaDataJson['dcc:conformityXMLList']; + if (confList) { + return confList.trim().split(/\s+/); + } + return []; + } + + getLowerLimit() { + const data = this.metaDataJson['dcc:data']; + if (data && data['dcc:quantity']) { + let quantities = data['dcc:quantity']; + if (!Array.isArray(quantities)) quantities = [quantities]; + for (let q of quantities) { + if (q.$ && q.$.refType && q.$.refType.includes('basic_toleranceLimitLower')) { + let lowerValue = null; + let lowerUnit = ''; + if (q['si:realListXMLList']) { + const realList = q['si:realListXMLList']; + if (realList['si:valueXMLList']) { + lowerValue = parseFloat(realList['si:valueXMLList'].trim()); + } + if (realList['si:unitXMLList']) { + const rawUnit = realList['si:unitXMLList'].trim(); + const unit = new DSIUnit(rawUnit); + lowerUnit = unit.toHTML({ oneLine: true }); + } + } + return { value: lowerValue, unit: lowerUnit, name: this.getQuantityName(q) }; + } + } + } + return null; + } + + getUpperLimit() { + const data = this.metaDataJson['dcc:data']; + if (data && data['dcc:quantity']) { + let quantities = data['dcc:quantity']; + if (!Array.isArray(quantities)) quantities = [quantities]; + for (let q of quantities) { + if (q.$ && q.$.refType && q.$.refType.includes('basic_toleranceLimitUpper')) { + let upperValue = null; + let upperUnit = ''; + if (q['si:realListXMLList']) { + const realList = q['si:realListXMLList']; + if (realList['si:valueXMLList']) { + upperValue = parseFloat(realList['si:valueXMLList'].trim()); + } + if (realList['si:unitXMLList']) { + const rawUnit = realList['si:unitXMLList'].trim(); + const unit = new DSIUnit(rawUnit); + upperUnit = unit.toHTML({ oneLine: true }); + } + } + return { value: upperValue, unit: upperUnit, name: this.getQuantityName(q) }; + } + } + } + return null; + } + + getQuantityName(q) { + if (q['dcc:name'] && q['dcc:name']['dcc:content']) { + let content = q['dcc:name']['dcc:content']; + if (Array.isArray(content)) { + const match = content.find(item => item.$ && item.$.lang === this.language) || content[0]; + return match._ || match; + } + return content._ || content; + } + return ''; + } +} diff --git a/src/renderers/MeasurementRenderer.js b/src/renderers/MeasurementRenderer.js index 97430b6..0a63c39 100644 --- a/src/renderers/MeasurementRenderer.js +++ b/src/renderers/MeasurementRenderer.js @@ -27,6 +27,15 @@ const lightPalette = [ '#b3ffff' ]; +const conformityColors = { + pass: '#2ca02c', + fail: '#d62728', + conditionalpass: '#8bc34a', + conditionalfail: '#ff9800', + nopass: '#9e9e9e', + nofail: '#9e9e9e' +}; + export function renderMeasurementResults(measurementResults, language) { console.debug('renderMeasurementResults called with:', measurementResults); const container = document.getElementById('measurementResults'); @@ -42,9 +51,7 @@ export function renderMeasurementResults(measurementResults, language) { console.error("Missing 'dcc:measurementResult' in measurementResults"); return; } - if (!Array.isArray(results)) { - results = [results]; - } + if (!Array.isArray(results)) { results = [results]; } const measurementResult = results[0]; let resultObj = measurementResult['dcc:results'] && measurementResult['dcc:results']['dcc:result']; @@ -52,9 +59,7 @@ export function renderMeasurementResults(measurementResults, language) { console.error("Missing 'dcc:results' or 'dcc:result' in measurementResult:", measurementResult); return; } - if (Array.isArray(resultObj)) { - resultObj = resultObj[0]; - } + if (Array.isArray(resultObj)) { resultObj = resultObj[0]; } let resultName = 'Measurement Result'; if (measurementResult['dcc:name'] && measurementResult['dcc:name']['dcc:content']) { @@ -84,11 +89,11 @@ export function renderMeasurementResults(measurementResults, language) { } if (listData['dcc:measurementMetaData'] && listData['dcc:measurementMetaData']['dcc:metaData']) { let metaData = listData['dcc:measurementMetaData']['dcc:metaData']; - if (!Array.isArray(metaData)) metaData = [metaData]; + if (!Array.isArray(metaData)) { metaData = [metaData]; } metaData.forEach(md => { if (md['dcc:data'] && md['dcc:data']['dcc:quantity']) { let qs = md['dcc:data']['dcc:quantity']; - if (!Array.isArray(qs)) qs = [qs]; + if (!Array.isArray(qs)) { qs = [qs]; } quantityJSONs = quantityJSONs.concat(qs); } }); @@ -96,29 +101,36 @@ export function renderMeasurementResults(measurementResults, language) { const indexQuantities = []; const dataQuantities = []; + // extraInfo: for each data quantity, store { uncertainty, comments: [{ comment, validArray }], conformity } const extraInfo = []; quantityJSONs.forEach(q => { if (q.$ && q.$.refType && q.$.refType.match(/basic_tableIndex/)) { indexQuantities.push(new DCCRealListQuantity(q)); } else { dataQuantities.push(new DCCRealListQuantity(q)); - let uncertainty = (new DCCRealListQuantity(q)).getUncertainty(); - let comment = ''; + const uncertainty = (new DCCRealListQuantity(q)).getUncertainty(); + let comments = []; let conformity = null; if (q['dcc:measurementMetaData'] && q['dcc:measurementMetaData']['dcc:metaData']) { let md = q['dcc:measurementMetaData']['dcc:metaData']; if (!Array.isArray(md)) { md = [md]; } md.forEach(item => { if (item.$ && item.$.refType && item.$.refType.includes('basic_tableRowComment')) { + let commentText = ''; if (item['dcc:description'] && item['dcc:description']['dcc:content']) { let desc = item['dcc:description']['dcc:content']; if (Array.isArray(desc)) { const match = desc.find(d => d.$ && d.$.lang === language) || desc[0]; - comment = match._ || match; + commentText = match._ || match; } else { - comment = desc._ || desc; + commentText = desc._ || desc; } } + let validArray = []; + if (item['dcc:validXMLList']) { + validArray = item['dcc:validXMLList'].trim().split(/\s+/); + } + comments.push({ comment: commentText, valid: validArray }); } if (item.$ && item.$.refType && item.$.refType.includes('basic_conformity')) { if (item['dcc:conformityXMLList']) { @@ -127,12 +139,12 @@ export function renderMeasurementResults(measurementResults, language) { } }); } - extraInfo.push({ uncertainty, comment, conformity }); + extraInfo.push({ uncertainty, comments, conformity }); } }); - // Build headers for data quantities - const dataHeaders = dataQuantities.map(q => { + // Build data headers array for each data quantity + const dataHeaders = dataQuantities.map((q, idx) => { let header = q.getName(language); let unit = q.getUnit(); if (!header.toLowerCase().includes(" in ")) { @@ -141,7 +153,7 @@ export function renderMeasurementResults(measurementResults, language) { return header; }); - // Create log scaling toggles + // Create scaling toggles for log axes const scalingContainer = document.createElement('div'); scalingContainer.innerHTML = '<strong>Scaling:</strong> '; const logXToggle = document.createElement('input'); @@ -170,7 +182,7 @@ export function renderMeasurementResults(measurementResults, language) { radio.type = 'radio'; radio.name = 'xAxisSelect'; radio.value = idx; - if (idx === 0) radio.checked = true; + if (idx === 0) { radio.checked = true; } const label = document.createElement('label'); label.textContent = nameStr; label.style.marginRight = '10px'; @@ -199,10 +211,7 @@ export function renderMeasurementResults(measurementResults, language) { function updateVisualization() { const selectedRadio = document.querySelector('input[name="xAxisSelect"]:checked'); - if (!selectedRadio) { - console.error('No X-Axis selection found.'); - return; - } + if (!selectedRadio) { console.error('No X-Axis selection found.'); return; } const selectedIndex = selectedRadio.value; const xQuantity = indexQuantities[selectedIndex]; const xValues = xQuantity.getValues(); @@ -211,20 +220,18 @@ export function renderMeasurementResults(measurementResults, language) { console.debug('X-Axis unit:', xUnit); const headers = []; - const xHeader = 'X-Axis (selected) (' + xUnit + ')'; - headers.push(xHeader); + headers.push('X-Axis (selected) (' + xUnit + ')'); const dataValues = []; const uncertaintiesArray = []; const conformityArray = []; - dataQuantities.forEach((q, idx) => { + extraInfo.forEach((info, idx) => { headers.push(dataHeaders[idx]); - if (extraInfo[idx] && extraInfo[idx].conformity) { - headers.push('Conformity'); - } - dataValues.push(q.getValues()); - uncertaintiesArray.push(extraInfo[idx] ? extraInfo[idx].uncertainty : []); - conformityArray.push(extraInfo[idx] ? extraInfo[idx].conformity : []); + // Only include Conformity header if conformity exists for this quantity + if (info.conformity) { headers.push('Conformity'); } + dataValues.push(dataQuantities[idx].getValues()); + uncertaintiesArray.push(info.uncertainty || []); + conformityArray.push(info.conformity || []); }); headers.push('Comments'); @@ -232,20 +239,25 @@ export function renderMeasurementResults(measurementResults, language) { for (let i = 0; i < xValues.length; i++) { const row = []; row.push(xValues[i]); - dataValues.forEach((values, idx) => { - let cellValue = values[i] !== undefined ? values[i] : ''; + 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]; } row.push(cellValue); - if (extraInfo[idx] && extraInfo[idx].conformity && extraInfo[idx].conformity[i]) { - row.push(extraInfo[idx].conformity[i]); - } else if (extraInfo[idx] && extraInfo[idx].conformity) { - row.push(''); + if (info.conformity) { + row.push(info.conformity[i] || ''); } }); - let globalComment = extraInfo.map(e => e.comment).filter(c => c).join(' ; '); - row.push(globalComment); + // For comments, combine all comments valid at this row from all quantities + let rowComments = extraInfo.map(info => { + if (info.comments) { + // info.comments is an array of { comment, valid } objects + return info.comments.filter(cObj => cObj.valid[i] === 'true').map(cObj => cObj.comment).join(' ; '); + } + return ''; + }).filter(c => c).join(' | '); + row.push(rowComments); tableData.push(row); } renderTable(tableData); @@ -253,9 +265,7 @@ export function renderMeasurementResults(measurementResults, language) { const unitGroups = {}; dataQuantities.forEach((q, idx) => { const unit = q.getUnit(); - if (!unitGroups[unit]) { - unitGroups[unit] = []; - } + if (!unitGroups[unit]) { unitGroups[unit] = []; } const header = dataHeaders[idx]; let values = q.getValues(); const uncertainty = uncertaintiesArray[idx]; @@ -291,9 +301,7 @@ export function renderMeasurementResults(measurementResults, language) { y: trace.y, error_y: { type: 'data', - array: (trace.uncertainty && trace.uncertainty.length === xValues.length) - ? trace.uncertainty - : new Array(xValues.length).fill(0), + array: (trace.uncertainty && trace.uncertainty.length === xValues.length) ? trace.uncertainty : new Array(xValues.length).fill(0), visible: true, color: trace.defaultColor }, @@ -303,9 +311,7 @@ export function renderMeasurementResults(measurementResults, language) { marker: { color: trace.markerColor }, line: { color: trace.defaultColor }, hovertemplate: tooltip, - customdata: (trace.conformity && trace.conformity.length === xValues.length) - ? trace.conformity - : new Array(xValues.length).fill('') + customdata: (trace.conformity && trace.conformity.length === xValues.length) ? trace.conformity : new Array(xValues.length).fill('') }; }); let xaxisTitle = ''; @@ -366,7 +372,9 @@ export function renderMeasurementResults(measurementResults, language) { if (rowIndex === 0) { cell.innerHTML = cellData; if (cellData !== 'Comments' && cellIndex > 0) { - const qtyIndex = Math.floor((cellIndex - 1) / 2); + // Use correct header mapping: assume each quantity occupies either 1 (if no conformity) or 2 columns. + // We'll compute the index based on dataHeaders length. + const qtyIndex = cellIndex % 2 === 1 ? Math.floor(cellIndex / 2) : Math.floor((cellIndex - 1) / 2); cell.style.backgroundColor = lightPalette[qtyIndex % lightPalette.length]; } } else { @@ -397,12 +405,8 @@ export function renderMeasurementResults(measurementResults, language) { updateVisualization(); const radios = document.querySelectorAll('input[name="xAxisSelect"]'); - radios.forEach(radio => { - radio.addEventListener('change', updateVisualization); - }); + radios.forEach(radio => { radio.addEventListener('change', updateVisualization); }); document.getElementById('logXToggle').addEventListener('change', updateVisualization); document.getElementById('logYToggle').addEventListener('change', updateVisualization); - toleranceToggle.addEventListener('change', () => { - console.log('Tolerance toggle:', toleranceToggle.checked); - }); + toleranceToggle.addEventListener('change', () => { console.log('Tolerance toggle:', toleranceToggle.checked); }); } -- GitLab