UNPKG

bresenham-zingl

Version:

Bresenham rasterisation algorithms by Alois Zingl

175 lines (151 loc) 3.61 kB
import * as bresenham from "./"; const screenWidth = document.documentElement.clientWidth; const screenHeight = document.documentElement.clientHeight; const pxRatio = window.devicePixelRatio; const canvas = document.getElementById("canvas") as HTMLCanvasElement; const ctx = canvas.getContext("2d")!; const w = (canvas.width = screenWidth * devicePixelRatio); const h = (canvas.height = screenHeight * devicePixelRatio); canvas.style.width = screenWidth + "px"; canvas.style.height = screenHeight + "px"; function scaleGraphToFitBounds(G, bounds, margin) { var min = Math.min, max = Math.max; bounds[0] += margin; bounds[1] += margin; bounds[2] -= margin; bounds[3] -= margin; var bbox = getBounds(G); var cx = (bounds[0] + bounds[2]) / 2, cy = (bounds[1] + bounds[3]) / 2, gcx = (bbox[0] + bbox[2]) / 2, gcy = (bbox[1] + bbox[3]) / 2; var tx = cx - gcx, ty = cy - gcy; var scale = min( (bounds[2] - bounds[0]) / (bbox[2] - bbox[0]), (bounds[3] - bounds[1]) / (bbox[3] - bbox[1]) ); G.nodes.forEach(function (n) { n.x = cx + (n.x + tx - cx) * scale; n.y = cy + (n.y + ty - cy) * scale; }); return G; } function getBounds(g) { return g.nodes.reduce( (b, n) => { b[0] = Math.min(b[0], n.x); b[1] = Math.min(b[1], n.y); b[2] = Math.max(b[2], n.x); b[3] = Math.max(b[3], n.y); return b; }, [Infinity, Infinity, -Infinity, -Infinity] ); } var data, nodesMap; var tw = 2, thw = tw / 2; function setPixel(x, y, a) { ctx.fillRect(x - thw, y - thw, tw, tw); } function setPixelAA(x, y, a) { ctx.fillRect(x - thw, y - thw, tw, tw); } const getQuadraticControlPoint = ( x1, y1, x2, y2, cx = 2, cy = 1.5, dest = { x: 0, y: 0 } ) => { dest.x = (x1 + x2) / cx + (y2 - y1) / cy; dest.y = (y1 + y2) / cx + (x1 - x2) / cy; return dest; }; function render() { console.time("render"); ctx.clearRect(0, 0, w, h); const { nodes, edges } = data; // edges ctx.beginPath(); ctx.strokeStyle = "#707070"; ctx.fillStyle = "#707070"; edges.forEach((e) => { const s = nodesMap[e.source], t = nodesMap[e.target]; ctx.moveTo(s.x, s.y); if (e.curvature === 0) { ctx.lineTo(t.x, t.y); } else { const cp = getQuadraticControlPoint(s.x, s.y, t.x, t.y); bresenham.quadBezierAA( ~~s.x, ~~s.y, ~~cp.x, ~~cp.y, ~~t.x, ~~t.y, setPixelAA ); //ctx.quadraticCurveTo(cp.x, cp.y, t.x, t.y); } }); // ctx.stroke(); // ctx.closePath(); // nodes; ctx.beginPath(); ctx.fillStyle = "orange"; ctx.strokeStyle = "#333333"; ctx.lineWidth = 1; nodes.forEach((n) => { ctx.moveTo(n.x + n.r, n.y); ctx.arc(n.x, n.y, n.r, 0, 2 * Math.PI, false); }); //ctx.stroke(); ctx.fill(); ctx.beginPath(); ctx.fillStyle = "#333333"; nodes.forEach((n) => { ctx.moveTo(n.x + n.r, n.y); bresenham.circle(n.x, n.y, n.r, setPixel); ctx.arc(n.x, n.y, n.r, 0, 2 * Math.PI, false); }); const m = w / 5; console.log(w / 4); bresenham.cubicBezierAA( 0 + m, 400, 0 + m, 0, w - m, 0, w - m, 400, setPixelAA ); bresenham.cubicBezierAA( 0 + m, h - 400, 0 + m, h, w - m, h, w - m, h - 400, setPixelAA ); console.timeEnd("render"); } (async () => { const json = await fetch("./src/data.json").then((r) => r.json()); data = scaleGraphToFitBounds(json, [0, 0, w, h], 50); nodesMap = data.nodes.reduce((a, n) => { a[n.id] = n; return a; }, {}); render(); })();