Hand-gezeichnetes 3-D-Tortendiagramm (mlcrough Renderer-API)

Treibt die `mlcrough`-Engine-Extension über Engine.getMlcrough() an. Das User-Skript berechnet pro Slice einen Side-Wall- und einen Top-Lid-Pfad und reicht beide an `.path()` — Side zuerst (Painter's Algorithm), Top zuletzt. `flatten` steuert die Y-Stauchung, `thickness` die Tiefe der Seitenwand. Der hervorgehobene Slice ist radial herausgezogen.

Hand-drawn 3-D pie chart
Hand-drawn 3-D pie chart — Hand-gezeichnetes 3-D-Tortendiagramm (mlcrough Renderer-API)
JavaScript
// Hand-drawn 3-D pie chart via Engine.getMlcrough().
// demo_rough_piechart3d.js
//!NOIMAGE
//!OUTPUT: OUTPUT
//!PARAM: WIDTH:integer=640,min=300,max=1200
//!PARAM: HEIGHT:integer=520,min=300,max=1200
//!PARAM: FLATTEN:number=0.6,min=0.2,max=1,step=0.05
//!PARAM: THICKNESS:number=25,min=5,max=80,step=1
//!PARAM: SCALE:number=2,min=1,max=4,step=0.5

const r = Engine.getMlcrough({
  width: WIDTH, height: HEIGHT, background: "#f8f9fa",
});

const data = [
  { label: "Cloud",  value: 45, color: "#3498db" },
  { label: "Edge",   value: 25, color: "#e67e22", highlight: true },
  { label: "Legacy", value: 30, color: "#95a5a6" },
];

const cx = WIDTH / 2;
const cy = HEIGHT * 0.44;
const radius = Math.min(WIDTH, HEIGHT) * 0.36;
const total = data.reduce((s, d) => s + d.value, 0);
let start = 0;

data.forEach(d => {
  const slice = (d.value / total) * 2 * Math.PI;
  const end = start + slice;
  const mid = start + slice / 2;
  const off = d.highlight ? 15 : 0;
  const x = cx + Math.cos(mid) * off;
  const y = cy + Math.sin(mid) * off * FLATTEN;

  const x1 = x + Math.cos(start) * radius;
  const y1 = y + Math.sin(start) * radius * FLATTEN;
  const x2 = x + Math.cos(end) * radius;
  const y2 = y + Math.sin(end) * radius * FLATTEN;
  const la = slice > Math.PI ? 1 : 0;

  // Side wall (drawn first — behind the lid).
  r.path(
    `M ${x1} ${y1} A ${radius} ${radius * FLATTEN} 0 ${la} 1 ${x2} ${y2} ` +
    `L ${x2} ${y2 + THICKNESS} A ${radius} ${radius * FLATTEN} 0 ${la} 0 ${x1} ${y1 + THICKNESS} Z`,
    { fill: "rgba(0,0,0,0.18)", fillStyle: "solid", stroke: "rgba(0,0,0,0.55)" },
  );

  // Top lid.
  r.path(
    `M ${x} ${y} L ${x1} ${y1} A ${radius} ${radius * FLATTEN} 0 ${la} 1 ${x2} ${y2} Z`,
    { fill: d.color, fillStyle: "multi-hachure", hachureAngle: 45, hachureGap: 5 },
  );

  // Label.
  const tr = radius * 0.6;
  const tx = x + Math.cos(mid) * tr;
  const ty = y + Math.sin(mid) * tr * FLATTEN;
  r.raw(`<text x="${tx}" y="${ty}" text-anchor="middle" dominant-baseline="middle" font-family="sans-serif" font-size="16" font-weight="bold" fill="#fff" stroke="#000" stroke-width="0.6" paint-order="stroke">${d.label}</text>`);

  start = end;
});

r.toImage(SCALE).save(OUTPUT);

// © 2026 Michael Lechner · mlc OpticScript · https://mlcgo.eu · Elastic License 2.0