From e498004c99f5212762df298010f0321eface36ff Mon Sep 17 00:00:00 2001
From: Alexander Polyankin <alexander.polyankin@metabase.com>
Date: Thu, 26 Aug 2021 18:26:27 +0300
Subject: [PATCH] Add simple static categorical bar (#17600)

---
 .../metabase/internal/pages/StaticVizPage.jsx | 23 +++++-
 .../metabase/static-viz/categorical/bar.js    | 74 +++++++++++++++++++
 .../metabase/static-viz/categorical/index.js  |  5 +-
 frontend/src/metabase/static-viz/index.js     | 11 ++-
 4 files changed, 106 insertions(+), 7 deletions(-)
 create mode 100644 frontend/src/metabase/static-viz/categorical/bar.js

diff --git a/frontend/src/metabase/internal/pages/StaticVizPage.jsx b/frontend/src/metabase/internal/pages/StaticVizPage.jsx
index bde75c497ea..d86f2fe05ce 100644
--- a/frontend/src/metabase/internal/pages/StaticVizPage.jsx
+++ b/frontend/src/metabase/internal/pages/StaticVizPage.jsx
@@ -34,7 +34,7 @@ export default function StaticVizPage() {
                 },
               }),
             }}
-          ></Box>
+          />
         </Box>
         <Box py={3}>
           <Subhead>Line chart with timeseries data</Subhead>
@@ -55,7 +55,24 @@ export default function StaticVizPage() {
                 },
               }),
             }}
-          ></Box>
+          />
+        </Box>
+        <Box py={3}>
+          <Subhead>Bar chart showing categorical data</Subhead>
+          <Box
+            dangerouslySetInnerHTML={{
+              __html: RenderChart("categorical/bar", {
+                data: [["donut", 20], ["cronut", 31]],
+                accessors: {
+                  x: row => row[0],
+                  y: row => row[1],
+                },
+                labels: {
+                  bottom: "Category",
+                },
+              }),
+            }}
+          />
         </Box>
         <Box py={3}>
           <Subhead>Donut chart showing categorical data</Subhead>
@@ -73,7 +90,7 @@ export default function StaticVizPage() {
                 },
               }),
             }}
-          ></Box>
+          />
         </Box>
       </Box>
     </Box>
diff --git a/frontend/src/metabase/static-viz/categorical/bar.js b/frontend/src/metabase/static-viz/categorical/bar.js
new file mode 100644
index 00000000000..5b0145472d7
--- /dev/null
+++ b/frontend/src/metabase/static-viz/categorical/bar.js
@@ -0,0 +1,74 @@
+/* eslint-disable react/prop-types */
+import React from "react";
+import { t } from "ttag";
+import { Bar } from "@visx/shape";
+import { AxisLeft, AxisBottom } from "@visx/axis";
+import { scaleBand, scaleLinear } from "@visx/scale";
+import { bottomAxisTickStyles, leftAxisTickStyles } from "../utils.js";
+import { GridRows } from "@visx/grid";
+
+export default function CategoricalBar(
+  { data, yScaleType = scaleLinear, accessors, labels },
+  layout,
+) {
+  const leftMargin = 55;
+  const xAxisScale = scaleBand({
+    domain: data.map(accessors.x),
+    range: [leftMargin, layout.xMax],
+    round: true,
+    padding: 0.2,
+  });
+
+  const yAxisScale = yScaleType({
+    domain: [0, Math.max(...data.map(accessors.y))],
+    range: [layout.yMax, 0],
+    nice: true,
+  });
+
+  return (
+    <svg width={layout.width} height={layout.height}>
+      <GridRows
+        scale={yAxisScale}
+        width={layout.xMax - leftMargin}
+        left={leftMargin}
+        strokeDasharray="4"
+      />
+      {data.map(d => {
+        const barWidth = xAxisScale.bandwidth();
+        const barHeight = layout.yMax - yAxisScale(accessors.y(d));
+        const x = xAxisScale(accessors.x(d));
+        const y = layout.yMax - barHeight;
+        return (
+          <Bar
+            key={`bar-${x}`}
+            width={barWidth}
+            height={barHeight}
+            x={x}
+            y={y}
+            fill="#509ee3"
+          />
+        );
+      })}
+      <AxisLeft
+        hideTicks
+        hideAxisLine
+        tickFormat={d => {
+          return String(d);
+        }}
+        scale={yAxisScale}
+        label={labels.left || t`Count`}
+        left={leftMargin}
+        tickLabelProps={() => leftAxisTickStyles(layout)}
+      />
+      <AxisBottom
+        hideTicks={false}
+        numTicks={5}
+        top={layout.yMax}
+        scale={xAxisScale}
+        stroke={layout.colors.axis.stroke}
+        label={labels.bottom || t`Category`}
+        tickLabelProps={() => bottomAxisTickStyles(layout)}
+      />
+    </svg>
+  );
+}
diff --git a/frontend/src/metabase/static-viz/categorical/index.js b/frontend/src/metabase/static-viz/categorical/index.js
index 14562178cf6..8777f0d0ad5 100644
--- a/frontend/src/metabase/static-viz/categorical/index.js
+++ b/frontend/src/metabase/static-viz/categorical/index.js
@@ -1,3 +1,4 @@
-import Donut from "./donut.js";
+import CategoricalBar from "./bar.js";
+import CategoricalDonut from "./donut.js";
 
-export { Donut };
+export { CategoricalBar, CategoricalDonut };
diff --git a/frontend/src/metabase/static-viz/index.js b/frontend/src/metabase/static-viz/index.js
index a5166be810d..9e594d69534 100644
--- a/frontend/src/metabase/static-viz/index.js
+++ b/frontend/src/metabase/static-viz/index.js
@@ -1,7 +1,10 @@
 import ReactDOMServer from "react-dom/server";
 
 import { TimeseriesBar, TimeseriesLine } from "metabase/static-viz/timeseries/";
-import { Donut } from "metabase/static-viz/categorical/";
+import {
+  CategoricalBar,
+  CategoricalDonut,
+} from "metabase/static-viz/categorical/";
 
 const DEFAULTS = {
   width: 540,
@@ -24,6 +27,7 @@ const DEFAULTS = {
 
 const TIMESERIES_BAR = "timeseries/bar";
 const TIMESERIES_LINE = "timeseries/line";
+const CATEGORICAL_BAR = "categorical/bar";
 const CATEGORICAL_DONUT = "categorical/donut";
 
 export function RenderChart(type, logic, layout = DEFAULTS) {
@@ -39,8 +43,11 @@ export function RenderChart(type, logic, layout = DEFAULTS) {
     case TIMESERIES_LINE:
       chart = TimeseriesLine(logic, { ...layout, xMax, yMax });
       break;
+    case CATEGORICAL_BAR:
+      chart = CategoricalBar(logic, { ...layout, xMax, yMax });
+      break;
     case CATEGORICAL_DONUT:
-      chart = Donut(logic, { ...layout, height: 540, xMax, yMax });
+      chart = CategoricalDonut(logic, { ...layout, height: 540, xMax, yMax });
       break;
   }
 
-- 
GitLab