{"spec_id":"bar-horizontal","library":"d3","language":"javascript","code":"// anyplot.ai\n// bar-horizontal: Horizontal Bar Chart\n// Library: d3 7.9.0 | JavaScript 22.23.1\n// Quality: 88/100 | Created: 2026-08-05\n\nconst t = window.ANYPLOT_TOKENS;\nconst { width, height } = window.ANYPLOT_SIZE;\nconst margin = { top: 110, right: 140, bottom: 90, left: 260 };\nconst iw = width - margin.left - margin.right;\nconst ih = height - margin.top - margin.bottom;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// Most-starred open-source frameworks on GitHub, sorted ascending so the\n// largest bar lands at the top when rendered with a reversed band scale.\n// Raw star counts (not pre-scaled) — the SI-prefix formatter below derives\n// the \"k\" display units directly from the real magnitude.\nconst data = [\n  { language: \"Vue\", stars: 46900 },\n  { language: \"Bootstrap\", stars: 59100 },\n  { language: \"TensorFlow\", stars: 68300 },\n  { language: \"React\", stars: 79400 },\n  { language: \"Flutter\", stars: 89900 },\n  { language: \"VS Code\", stars: 98700 },\n  { language: \"Node.js\", stars: 108200 },\n  { language: \"freeCodeCamp\", stars: 118500 },\n].sort((a, b) => a.stars - b.stars);\n\n// SI-prefix formatter (d3-format) — auto-derives \"k\" units from magnitude\n// instead of a hardcoded `${d}M` multiplier.\nconst siFormat = d3.format(\"~s\");\nconst valueFormat = d3.format(\".3~s\");\nconst maxStars = d3.max(data, (d) => d.stars);\n\n// Value-driven opacity ramp — the top-ranked bar reads at full strength while\n// lower-ranked bars recede slightly, adding hierarchy beyond sort order alone.\nconst opacity = d3.scaleLinear().domain([d3.min(data, (d) => d.stars), maxStars]).range([0.62, 1]);\n\n// --- SVG mount ---------------------------------------------------------------\nconst svg = d3.select(\"#container\").append(\"svg\").attr(\"width\", width).attr(\"height\", height);\nconst g = svg.append(\"g\").attr(\"transform\", `translate(${margin.left},${margin.top})`);\n\n// --- Scales -------------------------------------------------------------------\nconst x = d3.scaleLinear().domain([0, d3.max(data, (d) => d.stars)]).nice().range([0, iw]);\nconst y = d3.scaleBand().domain(data.map((d) => d.language)).range([ih, 0]).padding(0.28);\n\n// --- Gridlines (x-axis only, per horizontal-bar convention) -------------------\ng.append(\"g\")\n  .attr(\"class\", \"grid\")\n  .call(d3.axisBottom(x).tickSize(ih).tickFormat(\"\"))\n  .attr(\"transform\", `translate(0,0)`)\n  .call((sel) => sel.select(\".domain\").remove())\n  .selectAll(\"line\")\n  .attr(\"stroke\", t.grid);\n\n// --- Axes -----------------------------------------------------------------\nconst xAxis = g\n  .append(\"g\")\n  .attr(\"transform\", `translate(0,${ih})`)\n  .call(d3.axisBottom(x).ticks(6).tickFormat(siFormat).tickSizeOuter(0));\nconst yAxis = g.append(\"g\").call(d3.axisLeft(y).tickSizeOuter(0));\n\nfor (const ax of [xAxis, yAxis]) {\n  ax.selectAll(\"text\").attr(\"fill\", t.inkSoft).style(\"font-size\", \"16px\");\n  ax.selectAll(\"line\").attr(\"stroke\", t.inkSoft);\n  ax.select(\".domain\").attr(\"stroke\", t.inkSoft);\n}\nyAxis.selectAll(\"line\").remove();\n\n// --- Bars -----------------------------------------------------------------\ng.selectAll(\"rect.bar\")\n  .data(data)\n  .join(\"rect\")\n  .attr(\"class\", \"bar\")\n  .attr(\"x\", 0)\n  .attr(\"y\", (d) => y(d.language))\n  .attr(\"width\", (d) => x(d.stars))\n  .attr(\"height\", y.bandwidth())\n  .attr(\"rx\", 3)\n  .attr(\"ry\", 3)\n  .attr(\"fill\", t.palette[0])\n  .attr(\"fill-opacity\", (d) => opacity(d.stars));\n\n// --- Value labels at bar ends ------------------------------------------------\ng.selectAll(\"text.value\")\n  .data(data)\n  .join(\"text\")\n  .attr(\"class\", \"value\")\n  .attr(\"x\", (d) => x(d.stars) + 14)\n  .attr(\"y\", (d) => y(d.language) + y.bandwidth() / 2)\n  .attr(\"dy\", \"0.35em\")\n  .attr(\"fill\", t.ink)\n  .style(\"font-size\", \"16px\")\n  .style(\"font-weight\", (d) => (d.stars === maxStars ? \"700\" : \"500\"))\n  .text((d) => `${valueFormat(d.stars)}`);\n\n// --- Axis label ---------------------------------------------------------------\nsvg\n  .append(\"text\")\n  .attr(\"x\", margin.left + iw / 2)\n  .attr(\"y\", height - 26)\n  .attr(\"text-anchor\", \"middle\")\n  .attr(\"fill\", t.inkSoft)\n  .style(\"font-size\", \"18px\")\n  .text(\"GitHub Stars\");\n\n// --- Title ------------------------------------------------------------------\nsvg\n  .append(\"text\")\n  .attr(\"x\", width / 2)\n  .attr(\"y\", 56)\n  .attr(\"text-anchor\", \"middle\")\n  .attr(\"fill\", t.ink)\n  .style(\"font-size\", \"30px\")\n  .style(\"font-weight\", \"600\")\n  .text(\"bar-horizontal · javascript · d3 · anyplot.ai\");\n"}