Implement Vega-Lite rendering with error handling and dynamic library loading

This commit is contained in:
2025-10-13 01:28:58 +03:00
parent 50e0221726
commit ffeb893809
3 changed files with 99 additions and 22 deletions

View File

@@ -83,14 +83,7 @@
Preview
</div>
<div class="panel-content">
<div class="preview-placeholder">
<div class="placeholder">
Vega-Lite visualization will render here
</div>
<div style="margin-top: 8px; font-size: 12px; color: #adb5bd;">
Live preview • Auto-refresh • Error display
</div>
</div>
<div id="vega-preview" style="height: 100%; width: 100%; overflow: auto;"></div>
</div>
</div>
</div>
@@ -98,6 +91,7 @@
<script>
let editor; // Global editor instance
let renderTimeout; // For debouncing
// Sample Vega-Lite specification
const sampleSpec = {
@@ -122,6 +116,74 @@
}
};
// 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();
const spec = JSON.parse(specText);
// 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
});
} catch (error) {
// Handle rendering errors gracefully
previewContainer.innerHTML = `
<div style="padding: 20px; color: #d32f2f; font-size: 12px; font-family: monospace;">
<strong>Rendering Error:</strong><br>
${error.message}
<br><br>
<em>Check your JSON syntax and Vega-Lite specification.</em>
</div>
`;
}
}
// Debounced render function
function debouncedRender() {
clearTimeout(renderTimeout);
renderTimeout = setTimeout(renderVisualization, 1500); // 500ms delay
}
// Load Vega libraries dynamically with UMD builds
function loadVegaLibraries() {
return new Promise((resolve, reject) => {
// Temporarily disable AMD define to avoid conflicts
const originalDefine = window.define;
window.define = undefined;
// Load Vega
const vegaScript = document.createElement('script');
vegaScript.src = 'https://unpkg.com/vega@5/build/vega.min.js';
vegaScript.onload = () => {
// Load Vega-Lite
const vegaLiteScript = document.createElement('script');
vegaLiteScript.src = 'https://unpkg.com/vega-lite@5/build/vega-lite.min.js';
vegaLiteScript.onload = () => {
// Load Vega-Embed
const vegaEmbedScript = document.createElement('script');
vegaEmbedScript.src = 'https://unpkg.com/vega-embed@6/build/vega-embed.min.js';
vegaEmbedScript.onload = () => {
// Restore AMD define
window.define = originalDefine;
resolve();
};
vegaEmbedScript.onerror = reject;
document.head.appendChild(vegaEmbedScript);
};
vegaLiteScript.onerror = reject;
document.head.appendChild(vegaLiteScript);
};
vegaScript.onerror = reject;
document.head.appendChild(vegaScript);
});
}
document.addEventListener('DOMContentLoaded', function () {
// Initialize Monaco Editor
require.config({ paths: { vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.47.0/min/vs' } });
@@ -131,9 +193,7 @@
try {
const response = await fetch('https://vega.github.io/schema/vega-lite/v5.json');
vegaLiteSchema = await response.json();
console.log('Vega-Lite schema loaded successfully');
} catch (error) {
console.error('Failed to load Vega-Lite schema:', error);
vegaLiteSchema = null;
}
@@ -149,6 +209,9 @@
});
}
// Load Vega libraries before creating editor
await loadVegaLibraries();
// Create the editor with improved configuration
editor = monaco.editor.create(document.getElementById('monaco-editor'), {
value: JSON.stringify(sampleSpec, null, 2),
@@ -163,7 +226,13 @@
formatOnType: true
});
console.log('Monaco Editor initialized with enhanced Vega-Lite schema support');
// Add debounced auto-render on editor change
editor.onDidChangeModelContent(() => {
debouncedRender();
});
// Initial render
renderVisualization();
});
// Basic toggle functionality
@@ -202,7 +271,6 @@
const headerLinks = document.querySelectorAll('.header-link');
headerLinks.forEach(link => {
link.addEventListener('click', function () {
console.log('Header link clicked:', this.textContent);
// TODO: Implement actual functionality in future phases
});
});