{"spec_id":"marimekko-basic","library":"muix","language":"javascript","code":"// anyplot.ai\n// marimekko-basic: Basic Marimekko Chart\n// Library: muix 7.29.1 | JavaScript 22.23.1\n// Quality: 94/100 | Created: 2026-07-24\n//# anyplot-orientation: landscape\n// anyplot.ai\n// marimekko-basic: Basic Marimekko Chart\n// Library: muix 7.29.1 | JavaScript 22.23.1\n// Quality: pending | Created: 2026-07-24\n\nimport * as React from \"react\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { ChartContainer } from \"@mui/x-charts/ChartContainer\";\nimport { ChartsYAxis } from \"@mui/x-charts/ChartsYAxis\";\nimport { ChartsText } from \"@mui/x-charts/ChartsText\";\nimport { useXScale, useYScale, useDrawingArea } from \"@mui/x-charts/hooks\";\n\nconst t = window.ANYPLOT_TOKENS;\nconst FONT = \"system-ui, -apple-system, sans-serif\";\nconst X_AXIS_ID = \"region-axis\";\nconst Y_AXIS_ID = \"share-axis\";\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// Quarterly revenue ($M) by store region (column width) and product line\n// (segment height within each column).\nconst regions = [\"North\", \"South\", \"East\", \"West\", \"Central\"];\nconst products = [\"Electronics\", \"Apparel\", \"Home Goods\", \"Grocery\"];\nconst revenueByRegion = [\n  [42, 18, 15, 25], // North\n  [20, 22, 10, 8], // South\n  [55, 30, 25, 40], // East\n  [15, 12, 8, 5], // West\n  [30, 25, 20, 15], // Central\n];\n\nconst columnTotals = revenueByRegion.map((row) =>\n  row.reduce((sum, v) => sum + v, 0),\n);\nconst grandTotal = columnTotals.reduce((sum, v) => sum + v, 0);\nconst columnStarts = columnTotals.reduce((acc, total, i) => {\n  acc.push(i === 0 ? 0 : acc[i - 1] + columnTotals[i - 1]);\n  return acc;\n}, []);\n// The single standout column (largest revenue total) gets a subtle visual\n// accent so the reader sees the headline insight immediately instead of\n// having to compare all five totals themselves.\nconst leaderTotal = Math.max(...columnTotals);\nconst leaderIndex = columnTotals.indexOf(leaderTotal);\n\n// MUI X has no built-in mekko/mosaic series, so the tiles are drawn as plain\n// SVG rects positioned with the scales ChartContainer already computed from\n// the declared xAxis/yAxis config — the community-package way to compose a\n// chart type the library doesn't ship a dedicated component for.\nfunction MekkoTiles() {\n  const xScale = useXScale(X_AXIS_ID);\n  const yScale = useYScale(Y_AXIS_ID);\n  const drawing = useDrawingArea();\n  const theme = useTheme();\n\n  return (\n    <g>\n      <ChartsText\n        x={drawing.left - 76}\n        y={drawing.top + drawing.height / 2}\n        text=\"Share of Regional Revenue\"\n        fill={theme.palette.text.primary}\n        style={{\n          fontSize: 15,\n          textAnchor: \"middle\",\n          dominantBaseline: \"auto\",\n          angle: -90,\n        }}\n      />\n      {[0.25, 0.5, 0.75].map((share) => (\n        <line\n          key={share}\n          x1={drawing.left}\n          x2={drawing.left + drawing.width}\n          y1={yScale(share)}\n          y2={yScale(share)}\n          stroke={t.grid}\n          strokeWidth={1}\n          strokeOpacity={0.45}\n        />\n      ))}\n      {regions.map((region, colIndex) => {\n        const colStart = columnStarts[colIndex];\n        const colTotal = columnTotals[colIndex];\n        const x0 = xScale(colStart);\n        const x1 = xScale(colStart + colTotal);\n        const colWidth = x1 - x0;\n        const isLeader = colIndex === leaderIndex;\n        let cumShare = 0;\n\n        return (\n          <g key={region}>\n            {revenueByRegion[colIndex].map((value, rowIndex) => {\n              const shareBottom = cumShare;\n              const shareTop = cumShare + value / colTotal;\n              cumShare = shareTop;\n              const yTop = yScale(shareTop);\n              const yBottom = yScale(shareBottom);\n              const segHeight = yBottom - yTop;\n              const showLabel = colWidth > 70 && segHeight > 46;\n\n              return (\n                <g key={products[rowIndex]}>\n                  <rect\n                    x={x0 + 1.5}\n                    y={yTop}\n                    width={Math.max(colWidth - 3, 0)}\n                    height={Math.max(segHeight, 0)}\n                    rx={2}\n                    fill={t.palette[rowIndex]}\n                    stroke={t.pageBg}\n                    strokeWidth={2}\n                  />\n                  {showLabel && (\n                    <ChartsText\n                      x={x0 + colWidth / 2}\n                      y={yTop + segHeight / 2}\n                      text={`$${value}M`}\n                      fill={t.pageBg}\n                      style={{\n                        fontSize: 15,\n                        fontWeight: 600,\n                        textAnchor: \"middle\",\n                        dominantBaseline: \"central\",\n                      }}\n                    />\n                  )}\n                </g>\n              );\n            })}\n\n            {isLeader && (\n              <rect\n                x={x0 - 1}\n                y={drawing.top - 3}\n                width={colWidth + 2}\n                height={drawing.height + 6}\n                rx={4}\n                fill=\"none\"\n                stroke={theme.palette.text.primary}\n                strokeWidth={1.5}\n                strokeOpacity={0.55}\n              />\n            )}\n\n            <ChartsText\n              x={x0 + colWidth / 2}\n              y={drawing.top - 14}\n              text={`$${colTotal}M`}\n              fill={\n                isLeader\n                  ? theme.palette.text.primary\n                  : theme.palette.text.secondary\n              }\n              style={{\n                fontSize: isLeader ? 16 : 14,\n                fontWeight: isLeader ? 700 : 400,\n                textAnchor: \"middle\",\n                dominantBaseline: \"auto\",\n              }}\n            />\n\n            <ChartsText\n              x={x0 + colWidth / 2}\n              y={drawing.top + drawing.height + 24}\n              text={region}\n              fill={theme.palette.text.primary}\n              style={{\n                fontSize: 16,\n                fontWeight: isLeader ? 700 : 400,\n                textAnchor: \"middle\",\n                dominantBaseline: \"hanging\",\n              }}\n            />\n          </g>\n        );\n      })}\n    </g>\n  );\n}\n\nexport default function Chart() {\n  const theme = useTheme();\n  const { width, height } = window.ANYPLOT_SIZE;\n  const TITLE_H = 56;\n  const LEGEND_H = 44;\n  const CHART_H = height - TITLE_H - LEGEND_H;\n\n  return (\n    <Box\n      sx={{\n        width,\n        height,\n        bgcolor: t.pageBg,\n        display: \"flex\",\n        flexDirection: \"column\",\n        boxSizing: \"border-box\",\n        pt: \"18px\",\n      }}\n    >\n      <Typography\n        sx={{\n          color: t.ink,\n          fontSize: 22,\n          fontWeight: 500,\n          textAlign: \"center\",\n          fontFamily: FONT,\n          lineHeight: 1,\n          mb: \"4px\",\n        }}\n      >\n        Retail Revenue by Region &amp; Product Line · marimekko-basic ·\n        javascript · muix · anyplot.ai\n      </Typography>\n\n      <Box\n        sx={{\n          height: LEGEND_H,\n          display: \"flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n          gap: 3,\n        }}\n      >\n        {products.map((product, i) => (\n          <Box\n            key={product}\n            sx={{ display: \"flex\", alignItems: \"center\", gap: \"8px\" }}\n          >\n            <Box\n              sx={{\n                width: 14,\n                height: 14,\n                borderRadius: \"3px\",\n                bgcolor: t.palette[i],\n              }}\n            />\n            <Typography\n              sx={{\n                fontSize: 14,\n                color: theme.palette.text.secondary,\n                fontFamily: FONT,\n              }}\n            >\n              {product}\n            </Typography>\n          </Box>\n        ))}\n      </Box>\n\n      <ChartContainer\n        width={width}\n        height={CHART_H}\n        series={[]}\n        margin={{ top: 40, right: 32, bottom: 48, left: 100 }}\n        xAxis={[\n          { id: X_AXIS_ID, scaleType: \"linear\", min: 0, max: grandTotal },\n        ]}\n        yAxis={[{ id: Y_AXIS_ID, scaleType: \"linear\", min: 0, max: 1 }]}\n      >\n        <ChartsYAxis\n          axisId={Y_AXIS_ID}\n          valueFormatter={(value) => `${Math.round(value * 100)}%`}\n          tickNumber={5}\n          tickLabelStyle={{ fontSize: 13, fill: t.inkSoft, fontFamily: FONT }}\n        />\n        <MekkoTiles />\n      </ChartContainer>\n    </Box>\n  );\n}\n"}