Skip to content

艹木林森 (Wood) ​

A tree written with the characters 森, 林, 木 and 艹, from a forest to grass: each branch is a row of characters, and splits into two smaller branches with the next character. The branches are nested SVG groups made recursively with cm.svg.

js
const cols = 25;
const rows = 18;
const font = 25;
const maxDepth = 4;
const context = cm.context2d();
context.font = `${font}px sans-serif`;
const cell = context.measureText("森").width;
const width = cell * cols;
const height = cell * rows;
const chs = ["森", "林", "木", "艹"];
const fontSize = d3.scaleLinear([0, maxDepth], [font, 9]);
const degree = (x) => (x * 180) / Math.PI;

function branch(length, angle, depth) {
  if (depth >= maxDepth) return null;
  return cm.svg`<g ${{transform: `rotate(${degree(angle)})`}}>
    <text ${{
      data: d3.range(Math.round(length)),
      transform: (d) => `translate(${d * cell}, 0) rotate(90)`,
      font_size: fontSize(depth),
    }}>${chs[depth]}</text>
    <g ${{transform: `translate(${length * cell}, 0)`}}>
      ${[branch(length * 0.8, Math.PI / 6, depth + 1), branch(length * 0.8, -Math.PI / 6, depth + 1)]}
    </g>
  </g>`;
}

const svg = cm.svg`<svg ${{width, height, viewBox: [0, 0, width, height], font_family: "sans-serif", text_anchor: "middle", dominant_baseline: "central"}}>
  <g ${{transform: `translate(${width / 2}, ${height - cell / 2}) rotate(-90)`}}>
    ${branch(6, 0, 0)}
  </g>
</svg>`;

document.body.append(svg);