Source code for uniqc.visualization.circuit_render.html
"""HTML wrappers: static (tooltips only) and interactive (click-to-inspect)."""
from __future__ import annotations
import json
from .labels import tooltip
from .model import DrawCircuit
from .options import RenderOptions
from .svg import render_svg
__all__ = ["render_html"]
_PAGE_CSS = """
body{margin:0;font:14px -apple-system,'Segoe UI','PingFang SC',sans-serif;background:#f6f7f9;color:#1c2430}
.wrap{max-width:1180px;margin:0 auto;padding:24px 20px 48px}
h1{font-size:19px;margin:0 0 4px}
.meta{font:12px ui-monospace,monospace;color:#8a93a3;margin-bottom:16px}
.stage{background:#fff;border:1px solid #e3e7ec;border-radius:12px;padding:16px;overflow:auto}
.stage.dark{background:#0b1220;border-color:#1e293b}
.detail{position:sticky;bottom:12px;margin-top:12px;background:#0f172a;color:#c9d5ea;border-radius:10px;
padding:10px 14px;font:12px ui-monospace,monospace;display:none;white-space:pre-wrap}
"""
_INTERACTIVE_JS = """
document.querySelector('.stage').addEventListener('click', function(e){
var g = e.target.closest('g.op'); if(!g) return;
var ops = JSON.parse(document.getElementById('__ops').textContent);
var op = ops[+g.getAttribute('data-i')];
var d = document.querySelector('.detail');
d.style.display = 'block';
d.textContent = JSON.stringify(op, null, 2);
});
"""
def _op_payload(draw: DrawCircuit) -> list[dict]:
payload = []
for op in draw.ops:
payload.append(
{
"op": op.op,
"qubits": list(op.qubits),
"cbits": list(op.cbits),
"params": [str(p) for p in op.params],
"dagger": op.dagger,
"controls": list(op.controls),
**({"name": op.name} if op.name else {}),
**({"cond": op.cond} if op.cond else {}),
"text": tooltip(op),
}
)
return payload
[docs]
def render_html(draw: DrawCircuit, opts: RenderOptions, *, interactive: bool = False) -> str:
"""Render a self-contained HTML document (static or interactive)."""
svg, meta = render_svg(draw, opts)
title = "Quantum circuit (interactive)" if interactive else "Quantum circuit"
detail = ""
script = ""
if interactive:
ops_json = json.dumps(_op_payload(draw), ensure_ascii=False)
detail = '<div class="detail"></div>'
script = f'<script type="application/json" id="__ops">{ops_json}</script><script>{_INTERACTIVE_JS}</script>'
dark = " dark" if opts.theme == "dark" else ""
return f"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{title}</title>
<style>{_PAGE_CSS}</style>
</head>
<body>
<div class="wrap">
<h1>{title}</h1>
<div class="meta">uniqc · style={opts.style} · theme={opts.theme} · {meta["n_cols"]} columns, folded into {meta["bands"]} band(s)</div>
<div class="stage{dark}">{svg}</div>
{detail}
</div>
{script}
</body>
</html>
"""