{"spec_id":"lollipop-basic","library":"muix","language":"javascript","code":"// anyplot.ai\n// lollipop-basic: Basic Lollipop Chart\n// Library: muix 7.29.1 | JavaScript 22.23.0\n// Quality: 90/100 | Created: 2026-07-01\n//# anyplot-orientation: landscape\n// anyplot.ai\n// lollipop-basic: Basic Lollipop Chart\n// Library: MUI X Charts | React | Node 22\n// License: @mui/x-charts — MIT (community). Pro/Premium are out of scope.\n// Quality: pending | Created: 2026-07-01\n\nimport { ChartContainer } from \"@mui/x-charts/ChartContainer\";\nimport { ChartsXAxis } from \"@mui/x-charts/ChartsXAxis\";\nimport { ChartsYAxis } from \"@mui/x-charts/ChartsYAxis\";\nimport { ChartsGrid } from \"@mui/x-charts/ChartsGrid\";\nimport { useXScale, useYScale } from \"@mui/x-charts\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\n\nconst t = window.ANYPLOT_TOKENS;\n\n// Annual book sales by genre (millions of units), sorted highest to lowest\nconst genres = [\n  \"Children's\",\n  \"Romance\",\n  \"Thriller\",\n  \"Mystery\",\n  \"Fantasy\",\n  \"Sci-Fi\",\n  \"Self-Help\",\n  \"Business\",\n  \"Cooking\",\n  \"Biography\",\n  \"History\",\n  \"Literary Fiction\",\n];\nconst salesData = [22.1, 18.7, 16.3, 15.2, 14.8, 12.4, 11.2, 10.5, 9.8, 8.9, 7.6, 6.4];\nconst MAX_VAL = Math.max(...salesData);\n\n// Must be rendered inside ChartContainer to access its scale context\nfunction LollipopPlot() {\n  const xScale = useXScale();\n  const yScale = useYScale();\n\n  // Wait until band scale is fully resolved\n  if (!xScale || !yScale || typeof yScale.bandwidth !== \"function\") return null;\n\n  return (\n    <g>\n      {salesData.map((val, i) => {\n        const genre = genres[i];\n        const x0 = +xScale(0);\n        const x1 = +xScale(val);\n        const bandTop = yScale(genre);\n        if (bandTop == null || !isFinite(+bandTop)) return null;\n        const cy = +bandTop + yScale.bandwidth() / 2;\n\n        // Highlight top 3 genres; de-emphasise the rest for visual hierarchy\n        const opacity = i < 3 ? 1.0 : 0.6;\n\n        return (\n          <g key={genre} opacity={opacity}>\n            <line\n              x1={x0} y1={cy}\n              x2={x1} y2={cy}\n              stroke={t.palette[0]}\n              strokeWidth={3}\n              strokeLinecap=\"round\"\n            />\n            <circle cx={x1} cy={cy} r={11} fill={t.palette[0]} />\n            <text\n              x={x1 + 15}\n              y={cy + 4}\n              fill={t.inkSoft}\n              fontSize={12}\n              fontFamily=\"sans-serif\"\n            >\n              {val.toFixed(1)}\n            </text>\n          </g>\n        );\n      })}\n    </g>\n  );\n}\n\nconst TITLE = \"lollipop-basic · javascript · muix · anyplot.ai\";\nconst TITLE_HEIGHT = 70;\nconst MARGIN = { top: 10, right: 85, bottom: 62, left: 168 };\n\nexport default function Chart() {\n  const chartWidth = window.ANYPLOT_SIZE.width;\n  const chartHeight = window.ANYPLOT_SIZE.height - TITLE_HEIGHT;\n\n  return (\n    <Box\n      sx={{\n        width: chartWidth,\n        height: window.ANYPLOT_SIZE.height,\n        display: \"flex\",\n        flexDirection: \"column\",\n      }}\n    >\n      <Box\n        sx={{\n          height: TITLE_HEIGHT,\n          display: \"flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n          flexShrink: 0,\n        }}\n      >\n        <Typography sx={{ color: t.ink, fontSize: 22, fontWeight: 500 }}>\n          {TITLE}\n        </Typography>\n      </Box>\n\n      <ChartContainer\n        skipAnimation\n        width={chartWidth}\n        height={chartHeight}\n        margin={MARGIN}\n        series={[{\n          type: \"bar\",\n          data: salesData,\n          layout: \"horizontal\",\n        }]}\n        xAxis={[{\n          scaleType: \"linear\",\n          min: 0,\n          max: MAX_VAL * 1.1,\n          label: \"Annual Sales (millions of units)\",\n          labelStyle: { fontSize: 15, fill: t.ink },\n          tickLabelStyle: { fontSize: 13, fill: t.inkSoft },\n        }]}\n        yAxis={[{\n          scaleType: \"band\",\n          data: genres,\n          tickLabelStyle: { fontSize: 14, fill: t.inkSoft },\n        }]}\n        sx={{\n          \"& .MuiChartsGrid-line\": { stroke: t.grid, strokeOpacity: 0.5 },\n        }}\n      >\n        <ChartsGrid vertical />\n        <LollipopPlot />\n        <ChartsYAxis />\n        <ChartsXAxis />\n      </ChartContainer>\n    </Box>\n  );\n}\n"}