73 lines
2.0 KiB
TypeScript
73 lines
2.0 KiB
TypeScript
/**
|
|
* Find `.circuit-embed` divs (generated by backend from ```circuit fences)
|
|
* and replace them with live CircuitJS iframes. Uses IntersectionObserver
|
|
* for lazy loading so multiple embeds don't all load at once.
|
|
*/
|
|
|
|
function loadCircuitEmbed(div: HTMLElement) {
|
|
const width = div.dataset.width || '100%';
|
|
const height = div.dataset.height || '400px';
|
|
const dataEl = div.querySelector('.circuit-data');
|
|
const circuitData = dataEl?.textContent?.trim() || '';
|
|
|
|
const wrapper = document.createElement('div');
|
|
wrapper.className = 'circuit-embed-wrapper';
|
|
wrapper.style.width = width;
|
|
wrapper.style.height = height;
|
|
|
|
const iframe = document.createElement('iframe');
|
|
iframe.src = '/circuitjs1/circuitjs.html';
|
|
iframe.style.width = '100%';
|
|
iframe.style.height = '100%';
|
|
iframe.style.border = 'none';
|
|
iframe.title = 'Circuit Simulator';
|
|
|
|
const loadCircuit = (api: any) => {
|
|
if (!circuitData) return;
|
|
try {
|
|
api.importCircuit(circuitData, false);
|
|
api.setSimRunning(true);
|
|
api.updateCircuit();
|
|
} catch (e) {
|
|
console.error('Circuit embed load error:', e);
|
|
}
|
|
const loadingEl = div.querySelector('.circuit-embed-loading');
|
|
if (loadingEl) loadingEl.remove();
|
|
};
|
|
|
|
iframe.onload = () => {
|
|
const win = iframe.contentWindow as any;
|
|
|
|
win.oncircuitjsloaded = (api: any) => loadCircuit(api);
|
|
|
|
// Fallback if callback doesn't fire
|
|
setTimeout(() => {
|
|
const api = win?.CircuitJS1;
|
|
if (api) loadCircuit(api);
|
|
}, 3000);
|
|
};
|
|
|
|
wrapper.appendChild(iframe);
|
|
div.appendChild(wrapper);
|
|
div.dataset.rendered = 'true';
|
|
}
|
|
|
|
export function renderCircuitEmbeds(container: HTMLElement) {
|
|
const embeds = container.querySelectorAll('.circuit-embed:not([data-rendered])');
|
|
if (embeds.length === 0) return;
|
|
|
|
const observer = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach((entry) => {
|
|
if (entry.isIntersecting) {
|
|
loadCircuitEmbed(entry.target as HTMLElement);
|
|
observer.unobserve(entry.target);
|
|
}
|
|
});
|
|
},
|
|
{ rootMargin: '200px' }
|
|
);
|
|
|
|
embeds.forEach((el) => observer.observe(el));
|
|
}
|