document.addEventListener('DOMContentLoaded', function() { console.log('Visualization integration initializing...'); // Check if THREE.js is already loaded, if not, load it if (typeof THREE === 'undefined') { loadScript('https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js', function() { // Load OrbitControls after THREE is loaded loadScript('/static/js/OrbitControls.js', initVisualizations); }); } else { // If THREE is already loaded, just make sure OrbitControls is loaded if (typeof THREE.OrbitControls === 'undefined') { loadScript('/static/js/OrbitControls.js', initVisualizations); } else { initVisualizations(); } } function initVisualizations() { // Initialize visualizations once dependencies are loaded console.log('Dependencies loaded, initializing visualizations...'); // Load our visualization adapter loadScript('/static/js/visualization_adapter.js', function() { console.log('Visualization adapter loaded successfully'); }); // Connect to plugin visualizations if needed if (typeof QuantumVisualizer !== 'undefined') { console.log('QuantumVisualizer found, connecting...'); // Override the init method if needed const originalInit = QuantumVisualizer.init; QuantumVisualizer.init = function(pluginKey, resultData) { console.log(`Initializing visualization for plugin: ${pluginKey}`); // Call original init originalInit.call(this, pluginKey, resultData); // Additional initialization for quantum state visualization if (['teleport', 'handshake', 'auth'].includes(pluginKey)) { // Check if the quantum state viz needs initialization const stateViz = document.getElementById('quantum-state-viz'); if (stateViz && stateViz.childNodes.length === 0) { console.log('Initializing quantum state visualization'); initBlochSphere(stateViz); } } // Future: Additional plugin-specific visualization handling }; } } function initBlochSphere(container) { if (!container) return; try { if (typeof THREE === 'undefined') { throw new Error('THREE.js library not available'); } console.log('Creating Bloch sphere visualization'); // Scene setup const scene = new THREE.Scene(); scene.background = new THREE.Color('#141424'); // Camera setup const width = container.clientWidth || 300; const height = container.clientHeight || 300; const camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 1000); camera.position.set(0, 0, 2.5); // Renderer setup const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(width, height); container.appendChild(renderer.domElement); // Add sphere, axes, and state vector addBlochComponents(scene); // Add orbit controls if available let controls = null; if (typeof THREE.OrbitControls !== 'undefined') { controls = new THREE.OrbitControls(camera, renderer.domElement); controls.enableDamping = true; controls.dampingFactor = 0.05; } // Animation loop function animate() { requestAnimationFrame(animate); if (controls) { controls.update(); } else { // Auto-rotation fallback scene.rotation.y += 0.005; } renderer.render(scene, camera); } animate(); // Handle window/container resizing window.addEventListener('resize', function() { if (container.clientWidth > 0 && container.clientHeight > 0) { camera.aspect = container.clientWidth / container.clientHeight; camera.updateProjectionMatrix(); renderer.setSize(container.clientWidth, container.clientHeight); } }); // Expose a method to update state vector container.updateStateVector = function(theta, phi) { const stateVector = scene.getObjectByName('stateVector'); if (stateVector) { const x = Math.sin(theta) * Math.cos(phi); const y = Math.sin(theta) * Math.sin(phi); const z = Math.cos(theta); const direction = new THREE.Vector3(x, y, z); stateVector.setDirection(direction); } }; // Default to |+⟩ state container.updateStateVector(Math.PI/2, 0); } catch (e) { console.error('Error initializing Bloch sphere:', e); container.innerHTML = `
Error: ${e.message}
`; } } function addBlochComponents(scene) { // Add sphere const sphereGeometry = new THREE.SphereGeometry(1, 32, 32); const sphereMaterial = new THREE.MeshBasicMaterial({ color: '#2a2a4a', transparent: true, opacity: 0.3, wireframe: true }); const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); scene.add(sphere); // Add axes const axisLength = 1.2; const axisWidth = 2; // X-axis (red) const xAxisGeometry = new THREE.BufferGeometry().setFromPoints([ new THREE.Vector3(-axisLength, 0, 0), new THREE.Vector3(axisLength, 0, 0) ]); const xAxisMaterial = new THREE.LineBasicMaterial({ color: 0xff0000, linewidth: axisWidth }); const xAxis = new THREE.Line(xAxisGeometry, xAxisMaterial); scene.add(xAxis); // Y-axis (green) const yAxisGeometry = new THREE.BufferGeometry().setFromPoints([ new THREE.Vector3(0, -axisLength, 0), new THREE.Vector3(0, axisLength, 0) ]); const yAxisMaterial = new THREE.LineBasicMaterial({ color: 0x00ff00, linewidth: axisWidth }); const yAxis = new THREE.Line(yAxisGeometry, yAxisMaterial); scene.add(yAxis); // Z-axis (blue) const zAxisGeometry = new THREE.BufferGeometry().setFromPoints([ new THREE.Vector3(0, 0, -axisLength), new THREE.Vector3(0, 0, axisLength) ]); const zAxisMaterial = new THREE.LineBasicMaterial({ color: 0x0000ff, linewidth: axisWidth }); const zAxis = new THREE.Line(zAxisGeometry, zAxisMaterial); scene.add(zAxis); // Add state vector const arrowDir = new THREE.Vector3(0, 0, 1); const arrowOrigin = new THREE.Vector3(0, 0, 0); const arrowLength = 1; const arrowColor = 0xff3366; const headLength = 0.2; const headWidth = 0.1; const stateVector = new THREE.ArrowHelper( arrowDir, arrowOrigin, arrowLength, arrowColor, headLength, headWidth ); stateVector.name = 'stateVector'; scene.add(stateVector); // Add equator circle const circleGeometry = new THREE.CircleGeometry(1, 32); circleGeometry.rotateX(Math.PI / 2); const circleMaterial = new THREE.MeshBasicMaterial({ color: '#4a4a8a', transparent: true, opacity: 0.3, side: THREE.DoubleSide }); const circle = new THREE.Mesh(circleGeometry, circleMaterial); scene.add(circle); // Add state labels addStateLabel(scene, '|0⟩', 0, 0, 1.3); addStateLabel(scene, '|1⟩', 0, 0, -1.3); addStateLabel(scene, '|+⟩', 1.3, 0, 0); addStateLabel(scene, '|-⟩', -1.3, 0, 0); addStateLabel(scene, '|i+⟩', 0, 1.3, 0); addStateLabel(scene, '|i-⟩', 0, -1.3, 0); } function addStateLabel(scene, text, x, y, z) { // Create canvas for text rendering const canvas = document.createElement('canvas'); canvas.width = 128; canvas.height = 64; const ctx = canvas.getContext('2d'); ctx.fillStyle = '#ffffff'; ctx.font = 'bold 24px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(text, 64, 32); // Create texture from canvas const texture = new THREE.CanvasTexture(canvas); // Create sprite material with the texture const material = new THREE.SpriteMaterial({ map: texture, transparent: true }); // Create sprite and position it const sprite = new THREE.Sprite(material); sprite.position.set(x, y, z); sprite.scale.set(0.5, 0.25, 1); scene.add(sprite); return sprite; } // Initialize circuit visualizer if needed function initCircuitVisualizer() { const container = document.getElementById('circuit-demo-container'); if (!container) return; console.log('Initializing circuit visualizer'); container.innerHTML = ''; // Clear container // Create SVG element const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('width', '100%'); svg.setAttribute('height', '100%'); svg.setAttribute('viewBox', '0 0 800 400'); container.appendChild(svg); // Define circuit const circuit = { qubits: ['q0', 'q1', 'q2'], gates: [ { type: 'H', qubit: 0, time: 0 }, { type: 'H', qubit: 1, time: 0 }, { type: 'CNOT', control: 1, target: 2, time: 1 }, { type: 'CNOT', control: 0, target: 1, time: 2 }, { type: 'H', qubit: 0, time: 3 }, { type: 'M', qubit: 0, time: 4 }, { type: 'M', qubit: 1, time: 4 }, { type: 'X', qubit: 2, time: 5, condition: [0, 1] }, { type: 'Z', qubit: 2, time: 6, condition: [0] } ] }; // Configuration const config = { qubitSpacing: 70, gateSpacing: 80, labelWidth: 60, padding: 40 }; // Draw circuit drawCircuit(svg, circuit, config); } function drawCircuit(svg, circuit, config) { const { qubitSpacing, gateSpacing, labelWidth, padding } = config; // Calculate circuit dimensions const maxTime = Math.max(...circuit.gates.map(g => g.time)) + 1; const width = labelWidth + (maxTime * gateSpacing) + (2 * padding); const height = (circuit.qubits.length * qubitSpacing) + (2 * padding); svg.setAttribute('viewBox', `0 0 ${width} ${height}`); // Draw qubit lines circuit.qubits.forEach((qubit, i) => { const y = padding + (i * qubitSpacing); // Draw qubit label const label = document.createElementNS('http://www.w3.org/2000/svg', 'text'); label.setAttribute('x', padding); label.setAttribute('y', y + 5); label.setAttribute('fill', '#ffffff'); label.setAttribute('text-anchor', 'start'); label.setAttribute('dominant-baseline', 'middle'); label.textContent = qubit; svg.appendChild(label); // Draw qubit line const line = document.createElementNS('http://www.w3.org/2000/svg', 'line'); line.setAttribute('x1', labelWidth); line.setAttribute('y1', y); line.setAttribute('x2', width - padding); line.setAttribute('y2', y); line.setAttribute('stroke', '#888888'); line.setAttribute('stroke-width', 2); svg.appendChild(line); }); // Draw gates circuit.gates.forEach(gate => { const x = labelWidth + (gate.time * gateSpacing) + padding; if (gate.type === 'CNOT') { drawCnotGate(svg, x, gate.control, gate.target, padding, qubitSpacing); } else if (gate.type === 'M') { drawMeasurementGate(svg, x, gate.qubit, padding, qubitSpacing); } else { // Single-qubit gate drawSingleQubitGate(svg, x, gate.qubit, gate.type, padding, qubitSpacing, gate.condition); } }); } function drawSingleQubitGate(svg, x, qubitIndex, gateType, padding, qubitSpacing, conditions) { const y = padding + (qubitIndex * qubitSpacing); const size = 30; // Determine gate color based on type let color; switch (gateType) { case 'H': color = '#3498db'; break; // Blue case 'X': color = '#e74c3c'; break; // Red case 'Y': color = '#2ecc71'; break; // Green case 'Z': color = '#f39c12'; break; // Orange default: color = '#9b59b6'; break; // Purple } // Draw control lines if this gate is conditional if (conditions) { conditions.forEach(controlQubit => { const controlY = padding + (controlQubit * qubitSpacing); drawControlLine(svg, x, y, controlY); }); } // Draw gate const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); rect.setAttribute('x', x - size/2); rect.setAttribute('y', y - size/2); rect.setAttribute('width', size); rect.setAttribute('height', size); rect.setAttribute('fill', color); rect.setAttribute('stroke', '#444444'); rect.setAttribute('stroke-width', 2); rect.setAttribute('rx', 4); svg.appendChild(rect); // Add gate label const text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); text.setAttribute('x', x); text.setAttribute('y', y); text.setAttribute('fill', '#ffffff'); text.setAttribute('text-anchor', 'middle'); text.setAttribute('dominant-baseline', 'middle'); text.textContent = gateType; svg.appendChild(text); } function drawCnotGate(svg, x, controlIndex, targetIndex, padding, qubitSpacing) { const controlY = padding + (controlIndex * qubitSpacing); const targetY = padding + (targetIndex * qubitSpacing); const radius = 15; // Draw vertical line connecting control and target const line = document.createElementNS('http://www.w3.org/2000/svg', 'line'); line.setAttribute('x1', x); line.setAttribute('y1', controlY); line.setAttribute('x2', x); line.setAttribute('y2', targetY); line.setAttribute('stroke', '#e74c3c'); line.setAttribute('stroke-width', 2); svg.appendChild(line); // Draw control point const controlPoint = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); controlPoint.setAttribute('cx', x); controlPoint.setAttribute('cy', controlY); controlPoint.setAttribute('r', 5); controlPoint.setAttribute('fill', '#e74c3c'); svg.appendChild(controlPoint); // Draw target circle const targetCircle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); targetCircle.setAttribute('cx', x); targetCircle.setAttribute('cy', targetY); targetCircle.setAttribute('r', radius); targetCircle.setAttribute('fill', 'none'); targetCircle.setAttribute('stroke', '#e74c3c'); targetCircle.setAttribute('stroke-width', 2); svg.appendChild(targetCircle); // Draw the "+" in the target const vLine = document.createElementNS('http://www.w3.org/2000/svg', 'line'); vLine.setAttribute('x1', x); vLine.setAttribute('y1', targetY - radius); vLine.setAttribute('x2', x); vLine.setAttribute('y2', targetY + radius); vLine.setAttribute('stroke', '#e74c3c'); vLine.setAttribute('stroke-width', 2); svg.appendChild(vLine); const hLine = document.createElementNS('http://www.w3.org/2000/svg', 'line'); hLine.setAttribute('x1', x - radius); hLine.setAttribute('y1', targetY); hLine.setAttribute('x2', x + radius); hLine.setAttribute('y2', targetY); hLine.setAttribute('stroke', '#e74c3c'); hLine.setAttribute('stroke-width', 2); svg.appendChild(hLine); } function drawMeasurementGate(svg, x, qubitIndex, padding, qubitSpacing) { const y = padding + (qubitIndex * qubitSpacing); const size = 30; // Draw measurement box const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); rect.setAttribute('x', x - size/2); rect.setAttribute('y', y - size/2); rect.setAttribute('width', size); rect.setAttribute('height', size); rect.setAttribute('fill', '#2ecc71'); rect.setAttribute('stroke', '#444444'); rect.setAttribute('stroke-width', 2); rect.setAttribute('rx', 4); svg.appendChild(rect); // Add M label const text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); text.setAttribute('x', x); text.setAttribute('y', y); text.setAttribute('fill', '#ffffff'); text.setAttribute('text-anchor', 'middle'); text.setAttribute('dominant-baseline', 'middle'); text.textContent = 'M'; svg.appendChild(text); } function drawControlLine(svg, x, targetY, controlY) { // Draw line from control to target const line = document.createElementNS('http://www.w3.org/2000/svg', 'line'); line.setAttribute('x1', x); line.setAttribute('y1', controlY); line.setAttribute('x2', x); line.setAttribute('y2', targetY); line.setAttribute('stroke', '#888888'); line.setAttribute('stroke-width', 2); line.setAttribute('stroke-dasharray', '5,5'); svg.appendChild(line); // Add control point const controlPoint = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); controlPoint.setAttribute('cx', x); controlPoint.setAttribute('cy', controlY); controlPoint.setAttribute('r', 4); controlPoint.setAttribute('fill', '#888888'); svg.appendChild(controlPoint); } function loadScript(url, callback) { const script = document.createElement('script'); script.src = url; script.onload = function() { console.log(`Loaded script: ${url}`); if (callback) callback(); }; script.onerror = function() { console.error(`Failed to load script: ${url}`); }; document.head.appendChild(script); } });