Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Hierarchy render by canvas</title>
  <style>
    canvas {
      width: 800px;
      height: 800px;
    }
  </style>
</head>
<body>
  <canvas width="1600" height="1600"></canvas>
  <script src="https://d3js.org/d3-hierarchy.v1.min.js"></script>
</body>
</html>
 
const dataSource = 'https://s5.ssl.qhres2.com/static/b0695e2dd30daa64.json';
/* globals d3 */
(async function () {
  const data = await (await fetch(dataSource)).json();
  const regions = d3.hierarchy(data)
    .sum(d => 1)
    .sort((a, b) => b.value - a.value);
  const pack = d3.pack()
    .size([1600, 1600])
    .padding(3);
  const root = pack(regions);
  const canvas = document.querySelector('canvas');
  const context = canvas.getContext('2d');
  const TAU = 2 * Math.PI;
  function draw(ctx, node, { fillStyle = 'rgba(0, 0, 0, 0.2)', textColor = 'white' } = {}) {
    const children = node.children;
    const { x, y, r } = node;
    ctx.fillStyle = fillStyle;
    ctx.beginPath();
    ctx.arc(x, y, r, 0, TAU);
    ctx.fill();
    if (children) {
      for (let i = 0; i < children.length; i++) {
        draw(context, children[i]);
      }
    } else {
      const name = node.data.name;
      ctx.fillStyle = textColor;
      ctx.font = '1.5rem Arial';
      ctx.textAlign = 'center';
      ctx.fillText(name, x, y);
    }
  }
  const redraw = () => {
    context.clearRect(0, 0, 1600, 1600)
    draw(context, root)
  }
  function isInCircle(node, mx, my) {
    const { children, data, x, y, r } = node
    if (children) {
      children.find((v) => isInCircle(v, mx, my))
    } else if ((mx - x) * (mx - x) + (my - y) * (my - y) < r * r) {
      redraw()
      draw(context, node, { fillStyle: 'rgba(0, 128, 0, 0.1)' })
      return data
    }
  }
  function bindMouseEvent() {
    canvas.onmousemove = (e) => {
      let { x, y } = e
      //! 注意画布宽高、样式宽高的比例
      x = x * 2
      y = y * 2
      const current = isInCircle(root, x, y)
      if (current) {
        console.log('In Circle', current)
      }
    }
  }
  draw(context, root)
  bindMouseEvent()
}());
Output 300px

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
liuguanyupro
0viewers