From 4947515d6133ddbd0489c395024f4c1ddf7a499c Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 19 Aug 2023 08:52:57 -0700 Subject: Chapter 1: Introduction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cliff Click Co-authored-by: Thalia Archibald Co-authored-by: hadha Co-authored-by: XmiliaH <45106915+XmiliaH@users.noreply.github.com> Co-authored-by: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> Co-authored-by: Jun Kawasaki --- graph/render_docs.py | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 graph/render_docs.py (limited to 'graph/render_docs.py') diff --git a/graph/render_docs.py b/graph/render_docs.py new file mode 100644 index 00000000..a0c5ec26 --- /dev/null +++ b/graph/render_docs.py @@ -0,0 +1,71 @@ +"""Render documentation snapshots with the same layout and SVG export as make view. + +Requires Python Playwright and an installed browser; not needed to build chapters. +Example: python graph/render_docs.py --browser msedge chapter01/docs/01-graph.json +""" +import argparse +from functools import partial +from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer +import json +from pathlib import Path +from threading import Thread +from playwright.sync_api import sync_playwright + + +class QuietHandler(SimpleHTTPRequestHandler): + def log_message(self, *args): + pass + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--browser', default='chromium', choices=['chromium', 'msedge', 'chrome', 'firefox']) + parser.add_argument('snapshots', nargs='+', type=Path) + args = parser.parse_args() + web = Path(__file__).resolve().parent / 'web' + server = ThreadingHTTPServer(('127.0.0.1', 0), partial(QuietHandler, directory=str(web))) + Thread(target=server.serve_forever, daemon=True).start() + try: + with sync_playwright() as pw: + engine = pw.firefox if args.browser == 'firefox' else pw.chromium + options = {'channel': args.browser} if args.browser in ('msedge', 'chrome') else {} + browser = engine.launch(headless=True, **options) + page = browser.new_page(reduced_motion='reduce') + # No connection to a compiler or to the user's live viewer session. + page.route_web_socket('**', lambda ws: ws.on_message(lambda message: None)) + page.goto(f'http://127.0.0.1:{server.server_port}/index.html') + page.wait_for_function('rendererReady') + page.evaluate('''() => { + layout = new GraphLayout(); + document.getElementById("assocs").checked = true; + document.getElementById("near").checked = false; + }''') + for source in args.snapshots: + snap = json.loads(source.read_text(encoding='utf-8')) + page.evaluate('''async snap => { + const evt = {kind: "PHASE", phase: "Documentation", near: [], temps: []}; + const scene = await layout.run(snap, evt); + renderer.show(snap, scene, evt); + renderer.select(0); + }''', snap) + # Capture the normal export's Blob without bulk browser downloads. + svg = page.evaluate('''async () => { + const create = URL.createObjectURL, click = HTMLAnchorElement.prototype.click; + let blob; + URL.createObjectURL = value => { blob = value; return create(value); }; + HTMLAnchorElement.prototype.click = () => {}; + try { renderer.save(1); } + finally { URL.createObjectURL = create; HTMLAnchorElement.prototype.click = click; } + return await blob.text(); + }''') + target = source.with_suffix('.svg') + target.write_text(svg + '\n', encoding='utf-8', newline='\n') + print(target) + browser.close() + finally: + server.shutdown() + server.server_close() + + +if __name__ == '__main__': + main() -- cgit v1.2.3