import Viz from './viz.es'; const toNumber = (i) => Number(i); const gv = new Viz({ workerURL: 'lib/lite.render.js' }); export default class Layout { constructor() { this.src = 'digraph { node [shape="rectangle"];\n'; } addNode(graph, node) { if (node.dom.className === 'hidden') return; const id = node.data.id; this.src += ` "${id}" [fixedsize=true; width=${node.dom.offsetWidth / 72}; height=${node.dom.offsetHeight / 72}];\n`; for (const reply of node.data.replies) { if (node.collapsed && graph[reply.id].collapsed) continue; this.src += ` "${id}" -> "${reply.id}";\n`; } } async render(canvas, setPosition, setSize) { this.src += '}'; const info = await gv.renderJSONObject(this.src, { format: 'json0' }); const [_x, _y, width, height] = info.bb.split(',').map(toNumber); setSize(width, height); for (const object of info.objects) { const [x, y] = object.pos.split(',').map(toNumber); setPosition(object.name, x, height - y); } const ctx = canvas.getContext('2d'); ctx.lineWidth = 4; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.strokeStyle = '#696969'; ctx.fillStyle = '#696969'; for (const edge of info.edges) { const pos = edge.pos.slice(2); const points = pos.split(' ').map(p => { const [x, y] = p.split(','); return [toNumber(x), height - toNumber(y)]; }); ctx.beginPath(); ctx.moveTo(...points[1]); for (let i = 4; i < points.length; i += 3) { const [ax, ay] = points[i - 2]; const [bx, by] = points[i - 1]; const [x, y] = points[i]; ctx.bezierCurveTo(ax, ay, bx, by, x, y); } ctx.stroke(); const [lx, ly] = points[points.length - 1]; const [tx, ty] = points[0]; const [dx, dy] = [tx - lx, ty - ly]; const [hx, hy] = [dy*0.7, dx*-0.7]; ctx.beginPath(); ctx.moveTo(lx + dx*0.8, ly + dy*0.8); ctx.lineTo(lx - dx*0.5 + hx, ly - dy*0.5 + hy); ctx.lineTo(lx - dx*0.5 - hx, ly - dy*0.5 - hy); ctx.fill(); } } }