// Track preview fit mode let previewFitMode = 'default'; // 'default', 'width', or 'full' // Apply fit mode to spec dimensions function applyPreviewFitMode(spec, fitMode) { if (!spec || typeof spec !== 'object') return spec; // Clone to avoid mutation const modifiedSpec = JSON.parse(JSON.stringify(spec)); if (fitMode === 'width') { // Fit to width - get preview pane width const previewPane = document.getElementById('vega-preview'); if (previewPane) { const containerWidth = previewPane.offsetWidth; modifiedSpec.width = containerWidth - 10; // 10px padding for scroll // Keep original aspect ratio by not setting height } } else if (fitMode === 'full') { // Fit to full pane - get both dimensions const previewPane = document.getElementById('vega-preview'); if (previewPane) { modifiedSpec.width = previewPane.offsetWidth - 10; // 10px padding modifiedSpec.height = previewPane.offsetHeight - 10; // 10px padding } } // 'default' mode leaves original dimensions untouched return modifiedSpec; } // Resolve dataset references in a spec async function resolveDatasetReferences(spec) { // If spec has data.name, look it up if (spec.data && spec.data.name && typeof spec.data.name === 'string') { const datasetName = spec.data.name; const dataset = await DatasetStorage.getDatasetByName(datasetName); if (dataset) { // Replace data reference with actual data in the format Vega-Lite expects if (dataset.source === 'url') { // For URL sources, pass the URL and format spec.data = { url: dataset.data, format: { type: dataset.format } }; } else { // For inline sources if (dataset.format === 'json') { spec.data = { values: dataset.data }; } else if (dataset.format === 'csv') { spec.data = { values: dataset.data, format: { type: 'csv' } }; } else if (dataset.format === 'tsv') { spec.data = { values: dataset.data, format: { type: 'tsv' } }; } else if (dataset.format === 'topojson') { spec.data = { values: dataset.data, format: { type: 'topojson' } }; } } } else { throw new Error(`Dataset "${datasetName}" not found`); } } // Recursively resolve in layers (for layered specs) if (spec.layer && Array.isArray(spec.layer)) { for (let layer of spec.layer) { await resolveDatasetReferences(layer); } } // Recursively resolve in concat/hconcat/vconcat if (spec.concat && Array.isArray(spec.concat)) { for (let view of spec.concat) { await resolveDatasetReferences(view); } } if (spec.hconcat && Array.isArray(spec.hconcat)) { for (let view of spec.hconcat) { await resolveDatasetReferences(view); } } if (spec.vconcat && Array.isArray(spec.vconcat)) { for (let view of spec.vconcat) { await resolveDatasetReferences(view); } } // Recursively resolve in facet if (spec.spec) { await resolveDatasetReferences(spec.spec); } return spec; } // Render function that takes spec from editor async function renderVisualization() { const previewContainer = document.getElementById('vega-preview'); try { // Get current content from editor const specText = editor.getValue(); let spec = JSON.parse(specText); // Resolve dataset references spec = await resolveDatasetReferences(spec); // Apply preview fit mode spec = applyPreviewFitMode(spec, previewFitMode); // Render with Vega-Embed (use global variable) await window.vegaEmbed('#vega-preview', spec, { actions: false, // Hide action menu for cleaner look renderer: 'svg' // Use SVG for better quality }); // Hide overlay after successful render hidePreviewOverlay(); } catch (error) { // Handle rendering errors gracefully previewContainer.innerHTML = `