diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..87a1a69e3a720cf6d0cd3b77b782d3728c63e687 --- /dev/null +++ b/README.md @@ -0,0 +1,113 @@ + +# DCC Viewer JavaScript + +A lightweight JavaScript/HTML application for displaying Digital Calibration Certificates (DCC) from XML files. The application parses a DCC XML file, renders administrative data and measurement results interactively (including charts and tables), and supports multiple languages based on the certificate’s data. + +## Project Structure + +``` +├── data +│ ├── 1DTableDataWithRenderingComments.xml # Example XML file with table rendering comments +│ └── sin_acceleration_example_dcc_WithExampleConformatyStatment.xml # Example DCC XML file +├── dcc-viewer # (Optional) Output directory for built package +├── index.html # Main HTML file +├── package.json # NPM package file +├── readME.md # This file +├── src +│ ├── app.js # Main application module (initializes the app, loads XML, renders UI) +│ ├── dccQuantity.js # Module for parsing DCC quantities and conformity data +│ ├── main.js # Entry point – initializes app after DOM loads and loads test XML (for development) +│ ├── renderers +│ │ ├── AdminRenderer.js # Renders administrative data (using a JSON tree viewer) +│ │ ├── MeasurementRenderer.js # Renders measurement results in a tabbed layout with charts, tables, etc. +│ │ └── SelectRenderer.js # (Optional) For selecting which renderer to use for a given XML section +│ └── styles.css # Application styling +└── vite.config.js # Vite configuration file +``` + +## Features + +- **Multi-Language Support:** + Automatically extracts available languages from the XML's administrative data and builds a dynamic language dropdown. + +- **Interactive Measurement Rendering:** + Measurement results are rendered in a tabbed layout, with interactive charts (using Plotly) and tables that update with scaling options and tolerance markings. + +- **Expandable Sections:** + Used methods and influence conditions are rendered in collapsible sections using JSONEditor. + +## Installation + +1. **Clone the Repository:** + + ```bash + git clone <repository_url> + cd dccviewertypescript + ``` + +2. **Install Dependencies:** + + ```bash + npm install + ``` + +## Development + +This project uses [Vite](https://vitejs.dev/) for development. + +1. **Start the Development Server:** + + ```bash + npm run dev + ``` + + This will start the server (usually on `http://localhost:5173/`). The app uses `src/main.js` as its entry point. + +2. **View Example:** + + For testing purposes, the development version loads a sample XML file from the `data` directory. You can change the XML in `main.js` if needed. + +## Building & Packaging + +1. **Build for Production:** + + ```bash + npm run build + ``` + + This command uses Vite to build a production version of your application. The output is typically placed in a `dist` directory. + +2. **Packaging as an NPM Module:** + + - Remove the test XML file loading from your module (it's now handled in `main.js`). + - Publish your module to npm (or use it locally) so that the consuming project can call your exported `init(xmlStr, options)` function to load and render a DCC XML file. + +## Usage in a Standalone HTML File + +If you want to use the module in a simple HTML file, you can create an HTML file like this: + +```html +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8" /> + <title>DCC Viewer</title> + <link rel="stylesheet" href="dist/styles.css" /> +</head> +<body> + <div id="app"></div> + <script type="module"> + import { init } from './dist/app.js'; + // Replace the following XML string with your own XML data. + fetch('path/to/your/dcc.xml') + .then(response => response.text()) + .then(xmlStr => { + init(xmlStr, { containerId: 'app', language: 'en' }); + }); + </script> +</body> +</html> +``` + +This example shows how to initialize the app by passing an XML string and configuration options (such as the container ID and language). +## License \ No newline at end of file diff --git a/src/app.js b/src/app.js index 6a2a9c99993dfb7c6110199345c980a4133f4555..96acbfc587901931f5c95d6a3aaed109fa629aab 100644 --- a/src/app.js +++ b/src/app.js @@ -1,69 +1,75 @@ import { parseString } from 'xml2js'; - -// Import our interactive measurement renderer import { renderMeasurementResults } from './renderers/MeasurementRenderer.js'; import { renderAdminData } from './renderers/AdminRenderer.js'; -// Global configuration -const selectableLanguages = ['en', 'de', 'fr', 'es']; -let selectedLanguage = 'en'; -let dccData = null; +export function init(xmlStr, options = {}) { + const containerId = options.containerId || 'app'; + const appContainer = document.getElementById(containerId); + if (!appContainer) { + console.error('No container found with id', containerId); + return; + } + appContainer.innerHTML = ''; -export function initApp() { - const appContainer = document.getElementById('app'); + // Parse the XML string first + parseString(xmlStr, { explicitArray: false }, (err, result) => { + if (err) { + console.error('Error parsing XML:', err); + return; + } + const dccData = result; + const cert = dccData['dcc:digitalCalibrationCertificate']; + if (!cert) { + console.error("No dcc:digitalCalibrationCertificate found in XML"); + return; + } - // Create language selection dropdown - const langSelect = document.createElement('select'); - selectableLanguages.forEach(lang => { - const option = document.createElement('option'); - option.value = lang; - option.textContent = lang; - if (lang === selectedLanguage) option.selected = true; - langSelect.appendChild(option); - }); - langSelect.addEventListener('change', (e) => { - selectedLanguage = e.target.value; - renderAll(); - }); - appContainer.appendChild(langSelect); + // Extract available languages from the administrative data coreData section + let languages = []; + if (cert['dcc:administrativeData'] && cert['dcc:administrativeData']['dcc:coreData']) { + const coreData = cert['dcc:administrativeData']['dcc:coreData']; + let langs = coreData['dcc:usedLangCodeISO639_1']; + if (langs) { + if (!Array.isArray(langs)) { langs = [langs]; } + languages = langs; + } + } - // Create containers for admin data and measurement results - const adminContainer = document.createElement('div'); - adminContainer.id = 'adminData'; - appContainer.appendChild(adminContainer); + // Use provided default language if available and present, else use the first available or fallback to 'en' + let selectedLanguage = (options.language && languages.includes(options.language)) + ? options.language + : (languages.length ? languages[0] : 'en'); - const measContainer = document.createElement('div'); - measContainer.id = 'measurementResults'; - appContainer.appendChild(measContainer); + // Build a dynamic language dropdown based on the extracted languages + const langSelect = document.createElement('select'); + languages.forEach(lang => { + const option = document.createElement('option'); + option.value = lang; + option.textContent = lang; + if (lang === selectedLanguage) option.selected = true; + langSelect.appendChild(option); + }); + // When the language is changed, reinitialize the app with the same XML but new language. + langSelect.addEventListener('change', (e) => { + init(xmlStr, { containerId, language: e.target.value }); + }); + appContainer.appendChild(langSelect); - // Load the XML file from the data folder - fetch('/data/sin_acceleration_example_dcc_WithExampleConformatyStatment.xml') - .then(response => response.text()) - .then(xmlText => { - parseString(xmlText, { explicitArray: false }, (err, result) => { - if (err) { - console.error('Error parsing XML:', err); - return; - } - dccData = result; - renderAll(); - }); - }) - .catch(err => console.error('Error loading XML file:', err)); -} + // Create containers for admin data and measurement results + const adminContainer = document.createElement('div'); + adminContainer.id = 'adminData'; + appContainer.appendChild(adminContainer); -function renderAll() { - // Clear containers - document.getElementById('adminData').innerHTML = ''; - document.getElementById('measurementResults').innerHTML = ''; + const measContainer = document.createElement('div'); + measContainer.id = 'measurementResults'; + appContainer.appendChild(measContainer); - if (dccData && dccData['dcc:digitalCalibrationCertificate']) { - const cert = dccData['dcc:digitalCalibrationCertificate']; + // Render admin and measurement data if available if (cert['dcc:administrativeData']) { renderAdminData(cert['dcc:administrativeData'], selectedLanguage); } if (cert['dcc:measurementResults']) { renderMeasurementResults(cert['dcc:measurementResults'], selectedLanguage); } - } + }); } diff --git a/src/main.js b/src/main.js index 06d04af16033e0cae1ebd2a0aca739a4eb1fb965..8c2f1c64a6114127d0a49a88541d3b091b5720e3 100644 --- a/src/main.js +++ b/src/main.js @@ -1,6 +1,12 @@ -import { initApp } from './app.js'; +import { init } from './app.js'; -// Initialize after DOM loads +// Initialize the app once the DOM is loaded. +// In production you can supply your own XML string to init(). document.addEventListener('DOMContentLoaded', () => { - initApp(); + fetch('/data/sin_acceleration_example_dcc_WithExampleConformatyStatment.xml') + .then(response => response.text()) + .then(xmlText => { + init(xmlText, { containerId: 'app', language: 'en' }); + }) + .catch(err => console.error('Error loading XML file:', err)); });