diff --git a/bin/build-mb/src/build.clj b/bin/build-mb/src/build.clj index d0830ed3941794cf630452b2ad5e8424b3e54735..34744a9a15e2c2f7b7d943495bb47a28fbeb2e97 100644 --- a/bin/build-mb/src/build.clj +++ b/bin/build-mb/src/build.clj @@ -44,6 +44,14 @@ "NODE_ENV" "production" "MB_EDITION" mb-edition}} "./node_modules/.bin/webpack" "--bail")) + ;; related to the above TODO -- not sure why `yarn build-static-viz` fails here + (u/step "Build static viz" + (u/sh {:dir u/project-root-directory + :env {"PATH" (env/env :path) + "HOME" (env/env :user-home) + "NODE_ENV" "production" + "MB_EDITION" mb-edition}} + "./node_modules/.bin/webpack" "--bail" "--config" "webpack.static-viz.config.js")) (u/announce "Frontend built successfully.")))) (def uberjar-filename (u/filename u/project-root-directory "target" "uberjar" "metabase.jar")) diff --git a/frontend/src/metabase/static-viz/categorical/donut.js b/frontend/src/metabase/static-viz/categorical/donut.js new file mode 100644 index 0000000000000000000000000000000000000000..c6901ff4bebfbfd73330203494ed743e9059cb70 --- /dev/null +++ b/frontend/src/metabase/static-viz/categorical/donut.js @@ -0,0 +1,64 @@ +/* eslint-disable react/prop-types */ +import React from "react"; +import { Pie } from "@visx/shape"; +import { scaleOrdinal } from "@visx/scale"; +import { Group } from "@visx/group"; + +export default function Donut({ data, accessors }, layout) { + const scale = scaleOrdinal({ + domain: data.map(accessors.dimension), + range: [ + "#509ee3", + "#A989C5", + "#7172AD", + "#EF8C8C", + "#F2A86F", + "#88BF4D", + "#F9D45C", + "#98D9D9", + ], + }); + + const innerWidth = layout.width - layout.margin.left - layout.margin.right; + const innerHeight = layout.height - layout.margin.top - layout.margin.bottom; + const radius = Math.min(innerWidth, innerHeight) / 2; + const centerY = innerHeight / 2; + const centerX = innerWidth / 2; + + const donutThickness = 100; + + const top = centerY + layout.margin.top; + const left = centerX + layout.margin.left; + + const pieSortValues = (a, b) => b - a; + + return ( + <svg width={layout.width} height={layout.height}> + <Group top={top} left={left}> + <Pie + data={data} + pieValue={accessors.metric} + pieSortValues={pieSortValues} + outerRadius={radius} + innerRadius={radius - donutThickness} + cornerRadius={2} + padAngle={0.001} + > + {pie => { + return pie.arcs.map((arc, index) => { + const arcPath = pie.path(arc); + return ( + <g key={`arc-${index}`}> + <path + d={arcPath} + fill={scale(accessors.dimension(arc.data))} + /> + </g> + ); + }); + }} + </Pie> + </Group> + </svg> + ); +} diff --git a/frontend/src/metabase/static-viz/categorical/index.js b/frontend/src/metabase/static-viz/categorical/index.js new file mode 100644 index 0000000000000000000000000000000000000000..14562178cf64f1828b46a08fbe4b93a252f95cd2 --- /dev/null +++ b/frontend/src/metabase/static-viz/categorical/index.js @@ -0,0 +1,3 @@ +import Donut from "./donut.js"; + +export { Donut }; diff --git a/frontend/src/metabase/static-viz/index.js b/frontend/src/metabase/static-viz/index.js new file mode 100644 index 0000000000000000000000000000000000000000..a5166be810d79d641bd691522f271a36dd4cc686 --- /dev/null +++ b/frontend/src/metabase/static-viz/index.js @@ -0,0 +1,48 @@ +import ReactDOMServer from "react-dom/server"; + +import { TimeseriesBar, TimeseriesLine } from "metabase/static-viz/timeseries/"; +import { Donut } from "metabase/static-viz/categorical/"; + +const DEFAULTS = { + width: 540, + height: 300, + margin: { + top: 20, + right: 20, + bottom: 20, + left: 20, + }, + colors: { + axis: { + stroke: "#b8bbc3", + label: { + fill: "#949aab", + }, + }, + }, +}; + +const TIMESERIES_BAR = "timeseries/bar"; +const TIMESERIES_LINE = "timeseries/line"; +const CATEGORICAL_DONUT = "categorical/donut"; + +export function RenderChart(type, logic, layout = DEFAULTS) { + // TODO - rename as innerWidth / innerHeight + const xMax = layout.width - layout.margin.left - layout.margin.right; + const yMax = layout.height - layout.margin.top - layout.margin.bottom; + + let chart; + switch (type) { + case TIMESERIES_BAR: + chart = TimeseriesBar(logic, { ...layout, xMax, yMax }); + break; + case TIMESERIES_LINE: + chart = TimeseriesLine(logic, { ...layout, xMax, yMax }); + break; + case CATEGORICAL_DONUT: + chart = Donut(logic, { ...layout, height: 540, xMax, yMax }); + break; + } + + return ReactDOMServer.renderToStaticMarkup(chart); +} diff --git a/frontend/src/metabase/static-viz/timeseries/bar.js b/frontend/src/metabase/static-viz/timeseries/bar.js new file mode 100644 index 0000000000000000000000000000000000000000..da163f784a3f7ca3dd14708d2821a2313f954ec7 --- /dev/null +++ b/frontend/src/metabase/static-viz/timeseries/bar.js @@ -0,0 +1,82 @@ +/* eslint-disable react/prop-types */ +import React from "react"; +import { Bar } from "@visx/shape"; +import { AxisLeft, AxisBottom } from "@visx/axis"; +import { scaleBand, scaleLinear, scaleOrdinal } from "@visx/scale"; +import { bottomAxisTickStyles, leftAxisTickStyles } from "../utils.js"; +import { GridRows } from "@visx/grid"; + +export default function TimeseriesBar( + { data, yScaleType = scaleLinear, accessors }, + layout, +) { + let multiScale, categories; + const xAxisScale = scaleBand({ + domain: data.map(accessors.x), + range: [40, layout.xMax], + round: true, + padding: 0.2, + }); + + const yAxisScale = yScaleType({ + domain: [0, Math.max(...data.map(accessors.y))], + range: [layout.yMax, 0], + nice: true, + }); + + if (accessors.multi) { + categories = data.map(accessors.multi); + // eslint-disable-next-line no-unused-vars + multiScale = scaleOrdinal({ + domain: categories, + range: ["blue", "yellow", "green", "red"], + }); + } + + return ( + <svg width={layout.width} height={layout.height}> + <GridRows + scale={yAxisScale} + width={layout.width} + left={40} + 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" + ></Bar> + ); + })} + <AxisLeft + hideTicks + hideAxisLine + tickFormat={d => { + return String(d); + }} + scale={yAxisScale} + label={"Count"} + left={40} + tickLabelProps={() => leftAxisTickStyles(layout)} + /> + <AxisBottom + hideTicks + top={layout.yMax} + tickFormat={d => new Date(d).toLocaleDateString("en")} + scale={xAxisScale} + stroke={layout.colors.axis.stroke} + label={"Time"} + tickLabelProps={() => bottomAxisTickStyles(layout)} + /> + </svg> + ); +} diff --git a/frontend/src/metabase/static-viz/timeseries/index.js b/frontend/src/metabase/static-viz/timeseries/index.js new file mode 100644 index 0000000000000000000000000000000000000000..4d44fa9864a5a88f5acd86b81d3f5cec5ca0e231 --- /dev/null +++ b/frontend/src/metabase/static-viz/timeseries/index.js @@ -0,0 +1,4 @@ +import TimeseriesBar from "./bar.js"; +import TimeseriesLine from "./line.js"; + +export { TimeseriesBar, TimeseriesLine }; diff --git a/frontend/src/metabase/static-viz/timeseries/line.js b/frontend/src/metabase/static-viz/timeseries/line.js new file mode 100644 index 0000000000000000000000000000000000000000..e329639ae62a22525633b021cc61ff2aca65d1c9 --- /dev/null +++ b/frontend/src/metabase/static-viz/timeseries/line.js @@ -0,0 +1,88 @@ +/* eslint-disable react/prop-types */ +import React from "react"; +import { LinePath } from "@visx/shape"; +import { AxisLeft, AxisBottom } from "@visx/axis"; +import { scaleLinear, scaleOrdinal, scaleTime } from "@visx/scale"; +import { bottomAxisTickStyles, leftAxisTickStyles } from "../utils"; +import { GridRows } from "@visx/grid"; + +export default function TimeseriesLine( + { data, yScaleType = scaleLinear, accessors }, + layout, +) { + let multiScale, categories; + + const xAxisScale = scaleTime({ + domain: [ + Math.min(...data.map(accessors.x)), + Math.max(...data.map(accessors.x)), + ], + range: [40, layout.xMax], + }); + // Y scale + const yAxisScale = yScaleType({ + domain: [0, Math.max(...data.map(accessors.y))], + range: [layout.yMax, 0], + nice: true, + }); + + if (accessors.multi) { + multiScale = scaleOrdinal({ + domain: data.map(accessors.multi), + range: ["#509ee3", "#EF8C8C", "#88BF4D", "#98D9D9", "#7173AD"], + }); + categories = data.map(accessors.multi); + } + + return ( + <svg width={layout.width} height={layout.height}> + <GridRows + scale={yAxisScale} + width={layout.width} + left={40} + strokeDasharray="4" + /> + {multiScale ? ( + categories.map(c => { + return ( + <LinePath + key={`series-${c}`} + data={data.filter(d => { + return accessors.multi(d) === c; + })} + stroke={multiScale(accessors.multi(c))} + x={d => xAxisScale(accessors.x(d))} + y={d => yAxisScale(accessors.y(d))} + /> + ); + }) + ) : ( + <LinePath + data={data} + stroke={"#509ee3"} + strokeWidth={2} + x={d => xAxisScale(accessors.x(d))} + y={d => yAxisScale(accessors.y(d))} + /> + )} + <AxisLeft + label={"Count"} + hideTicks + hideAxisLine + tickFormat={d => String(d)} + scale={yAxisScale} + left={40} + tickLabelProps={() => leftAxisTickStyles(layout)} + /> + <AxisBottom + label={"Time"} + hideTicks + top={layout.yMax} + stroke={layout.colors.axis.stroke} + tickFormat={d => new Date(d).toLocaleDateString("en")} + scale={xAxisScale} + tickLabelProps={() => bottomAxisTickStyles(layout)} + /> + </svg> + ); +} diff --git a/frontend/src/metabase/static-viz/utils.js b/frontend/src/metabase/static-viz/utils.js new file mode 100644 index 0000000000000000000000000000000000000000..d9a7b3aba9ce27fef9a7535f4ba918d88f7bf38e --- /dev/null +++ b/frontend/src/metabase/static-viz/utils.js @@ -0,0 +1,17 @@ +export function leftAxisTickStyles(layout) { + return { + fontFamily: "Lato, sans-serif", + fill: layout.colors.axis.label.fill, + fontSize: 11, + textAnchor: "end", + }; +} + +export function bottomAxisTickStyles(layout) { + return { + fontFamily: "Lato, sans-serif", + fill: layout.colors.axis.label.fill, + fontSize: 11, + textAnchor: "middle", + }; +} diff --git a/package.json b/package.json index 09c29bf9404f07741a92578fe262501628c0c995..03f7a2d497955f6390e6923904c8e7f6733c66f1 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,11 @@ "yarn": ">=1.12.3" }, "dependencies": { + "@visx/axis": "1.8.0", + "@visx/grid": "1.16.0", + "@visx/group": "1.7.0", + "@visx/scale": "1.7.0", + "@visx/shape": "1.8.0", "ace-builds": "^1.4.7", "arg": "^5.0.0", "chevrotain": "^6.5.0", @@ -189,6 +194,7 @@ "build-hot": "yarn concurrently -n 'cljs,js' 'yarn build-hot:cljs' 'yarn build-hot:js'", "build-stats": "yarn && webpack --json > stats.json", "build-shared": "yarn && webpack --config webpack.shared.config.js", + "build-static-viz": "yarn && webpack --config webpack.static-viz.config.js", "start": "yarn build && lein ring server", "precommit": "lint-staged", "preinstall": "echo $npm_execpath | grep -q yarn || echo '\\033[0;33mSorry, npm is not supported. Please use Yarn (https://yarnpkg.com/).\\033[0m'", diff --git a/webpack.static-viz.config.js b/webpack.static-viz.config.js new file mode 100644 index 0000000000000000000000000000000000000000..4cd05103511ac4687d13ef22c2eef90d02bf0d4d --- /dev/null +++ b/webpack.static-viz.config.js @@ -0,0 +1,56 @@ +const SRC_PATH = __dirname + "/frontend/src/metabase"; +const BUILD_PATH = __dirname + "/resources/frontend_client"; + +const BABEL_CONFIG = { + cacheDirectory: process.env.BABEL_DISABLE_CACHE ? null : ".babel_cache", +}; + +module.exports = { + mode: "production", + context: SRC_PATH, + + entry: { + "lib-static-viz": { + import: "./static-viz/index.js", + library: { + name: "StaticViz", + type: "var", + }, + }, + }, + + output: { + path: BUILD_PATH + "/app/dist", + filename: "[name].bundle.js", + }, + + module: { + rules: [ + { + test: /\.(js|jsx)$/, + exclude: /node_modules/, + use: [{ loader: "babel-loader", options: BABEL_CONFIG }], + }, + { + test: /\.(js|jsx)$/, + exclude: /node_modules/, + use: [ + { + loader: "eslint-loader", + options: { + rulePaths: [__dirname + "/frontend/lint/eslint-rules"], + }, + }, + ], + }, + ], + }, + resolve: { + extensions: [".webpack.js", ".web.js", ".js", ".jsx"], + alias: { + metabase: SRC_PATH, + }, + }, + +} + diff --git a/yarn.lock b/yarn.lock index b442edf9371737bc57a562e2545fd94feb639bcd..67352f6610b492ae8f57fe4339bccaf8a898e7f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1148,6 +1148,54 @@ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.0.tgz#14264692a9d6e2fa4db3df5e56e94b5e25647ac0" integrity sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A== +"@types/classnames@^2.2.9": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.3.1.tgz#3c2467aa0f1a93f1f021e3b9bcf938bd5dfdc0dd" + integrity sha512-zeOWb0JGBoVmlQoznvqXbE0tEC/HONsnoUNH19Hc96NFsTAwTXbTqb8FMYkru1F/iqp7a18Ws3nWJvtA1sHD1A== + dependencies: + classnames "*" + +"@types/d3-color@^1": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-1.4.2.tgz#944f281d04a0f06e134ea96adbb68303515b2784" + integrity sha512-fYtiVLBYy7VQX+Kx7wU/uOIkGQn8aAEY8oWMoyja3N4dLd8Yf6XgSIR/4yWvMuveNOH5VShnqCgRqqh/UNanBA== + +"@types/d3-interpolate@^1.3.1": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-1.4.2.tgz#88902a205f682773a517612299a44699285eed7b" + integrity sha512-ylycts6llFf8yAEs1tXzx2loxxzDZHseuhPokrqKprTQSTcD3JbJI1omZP1rphsELZO3Q+of3ff0ZS7+O6yVzg== + dependencies: + "@types/d3-color" "^1" + +"@types/d3-path@^1", "@types/d3-path@^1.0.8": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-1.0.9.tgz#73526b150d14cd96e701597cbf346cfd1fd4a58c" + integrity sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ== + +"@types/d3-scale@^3.2.1", "@types/d3-scale@^3.3.0": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-3.3.2.tgz#18c94e90f4f1c6b1ee14a70f14bfca2bd1c61d06" + integrity sha512-gGqr7x1ost9px3FvIfUMi5XA/F/yAf4UkUDtdQhpH92XCT0Oa7zkkRzY61gPVJq+DxpHn/btouw5ohWkbBsCzQ== + dependencies: + "@types/d3-time" "^2" + +"@types/d3-shape@^1.3.1": + version "1.3.8" + resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-1.3.8.tgz#c3c15ec7436b4ce24e38de517586850f1fea8e89" + integrity sha512-gqfnMz6Fd5H6GOLYixOZP/xlrMtJms9BaS+6oWxTKHNqPGZ93BkWWupQSCYm6YHqx6h9wjRupuJb90bun6ZaYg== + dependencies: + "@types/d3-path" "^1" + +"@types/d3-time@^1.0.10": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-1.1.1.tgz#6cf3a4242c3bbac00440dfb8ba7884f16bedfcbf" + integrity sha512-ULX7LoqXTCYtM+tLYOaeAJK7IwCT+4Gxlm2MaH0ErKLi07R5lh8NHCAyWcDkCCmx1AfRcBEV6H9QE9R25uP7jw== + +"@types/d3-time@^2", "@types/d3-time@^2.0.0": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-2.1.1.tgz#743fdc821c81f86537cbfece07093ac39b4bc342" + integrity sha512-9MVYlmIgmRR31C5b4FVSWtuMmBHh2mOWQYfl7XAYOa8dsnb7iEmUmRSWSFgXFtkjxO65d7hTUHQC+RhR/9IWFg== + "@types/eslint-scope@^3.7.0": version "3.7.0" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.0.tgz#4792816e31119ebd506902a482caec4951fabd86" @@ -1241,6 +1289,11 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.162.tgz#65d78c397e0d883f44afbf1f7ba9867022411470" integrity sha512-alvcho1kRUnnD1Gcl4J+hK0eencvzq9rmzvFPRmP5rPHx9VVsJj6bKLTATPVf9ktgv4ujzh7T+XWKp+jhuODig== +"@types/lodash@^4.14.146", "@types/lodash@^4.14.160": + version "4.14.171" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.171.tgz#f01b3a5fe3499e34b622c362a46a609fdb23573b" + integrity sha512-7eQ2xYLLI/LsicL2nejW9Wyko3lcpN6O/z0ZLHrEQsg280zIdCv1t/0m6UtBjUHokCGBQ3gYTbHzDkZ1xOBwwg== + "@types/mdast@^3.0.0": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.4.tgz#8ee6b5200751b6cadb9a043ca39612693ad6cb9e" @@ -1273,6 +1326,20 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== +"@types/prop-types@*": + version "15.7.4" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" + integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== + +"@types/react@*": + version "17.0.14" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.14.tgz#f0629761ca02945c4e8fea99b8177f4c5c61fb0f" + integrity sha512-0WwKHUbWuQWOce61UexYuWTGuGY/8JvtUe/dtQ6lR4sZ3UiylHotJeWpf3ArP9+DSGUoLY3wbU59VyMrJps5VQ== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + "@types/redux@^3.6.0": version "3.6.0" resolved "https://registry.yarnpkg.com/@types/redux/-/redux-3.6.0.tgz#f1ebe1e5411518072e4fdfca5c76e16e74c1399a" @@ -1280,6 +1347,11 @@ dependencies: redux "*" +"@types/scheduler@*": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + "@types/sinonjs__fake-timers@^6.0.1": version "6.0.2" resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz#3a84cf5ec3249439015e14049bd3161419bf9eae" @@ -1329,6 +1401,134 @@ dependencies: "@types/yargs-parser" "*" +"@visx/axis@1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@visx/axis/-/axis-1.8.0.tgz#6be994af9188fe889dce6dd7c61889b0ffb7a2dd" + integrity sha512-DSjtYiP0Hi5m4f2x8bCQQsdEg0hwa0XdeOjRpExCRdZQfYHMo1pLrRAATgRpy7TU49394V522IVGKMi5BicpmQ== + dependencies: + "@types/classnames" "^2.2.9" + "@types/react" "*" + "@visx/group" "1.7.0" + "@visx/point" "1.7.0" + "@visx/scale" "1.7.0" + "@visx/shape" "1.8.0" + "@visx/text" "1.7.0" + classnames "^2.2.5" + prop-types "^15.6.0" + +"@visx/curve@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@visx/curve/-/curve-1.7.0.tgz#b8c8ae902de469ae43014c78ed9bfda8aed8137c" + integrity sha512-n0/SHM4YXjke+aEinhHFZPLMxWu3jbqtvqzfGJyibX8OmbDjavk9P+MHfGokUcw0xHy6Ch3YTuwbYuvVw5ny9A== + dependencies: + "@types/d3-shape" "^1.3.1" + d3-shape "^1.0.6" + +"@visx/grid@1.16.0": + version "1.16.0" + resolved "https://registry.yarnpkg.com/@visx/grid/-/grid-1.16.0.tgz#49eda6ee73cccc6ca559a6a847e2af97c38fc17a" + integrity sha512-WxAZ2K9itSbO/uz/6gcK8npE/doTrUz2CKBvvwKOUWjKiHkbmyk8SvNNf2yT6rMaSJ1Qxw63oUn3+j50QpcXKA== + dependencies: + "@types/classnames" "^2.2.9" + "@types/react" "*" + "@visx/curve" "1.7.0" + "@visx/group" "1.7.0" + "@visx/point" "1.7.0" + "@visx/scale" "1.14.0" + "@visx/shape" "1.16.0" + classnames "^2.2.5" + prop-types "^15.6.2" + +"@visx/group@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@visx/group/-/group-1.7.0.tgz#e0ef2efbe00ef05326215d65b3d8a2b114df4f35" + integrity sha512-rzSXtV0+MHUyK+rwhVSV4qaHdzGi3Me3PRFXJSIAKVfoJIZczOkudUOLy34WvSrRlVyoFvGL7k9U5g8wHyY3nw== + dependencies: + "@types/classnames" "^2.2.9" + "@types/react" "*" + classnames "^2.2.5" + prop-types "^15.6.2" + +"@visx/point@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@visx/point/-/point-1.7.0.tgz#1df3c3425eae464f498473bcdda2fcae05c8ecbe" + integrity sha512-oaoY/HXYHhmpkkeKI4rBPmFtjHWtxSrIhZCVm1ipPoyQp3voJ8L6JD5eUIVmmaUCdUGUGwL1lFLnJiQ2p1Vlwg== + +"@visx/scale@1.14.0": + version "1.14.0" + resolved "https://registry.yarnpkg.com/@visx/scale/-/scale-1.14.0.tgz#622d274ec4f5e608de29d06cd6071892bb1e7587" + integrity sha512-ovbtEOF/d76uGMJ5UZlxdS3t2T8I6md+aIwOXBaq0HdjaCLbe7HLlMyHJKjak/sqBxLAiCGVnechTUpSkfgSQw== + dependencies: + "@types/d3-interpolate" "^1.3.1" + "@types/d3-scale" "^3.3.0" + "@types/d3-time" "^2.0.0" + d3-interpolate "^1.4.0" + d3-scale "^3.3.0" + d3-time "^2.1.1" + +"@visx/scale@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@visx/scale/-/scale-1.7.0.tgz#c46daade4492edb9eaec36fd3c87dc776960d6af" + integrity sha512-JjAAaUPaFT6aCYTN7ILhZHk/ECg1CQ2zJZKGBbsW/HFor0mEfT/H8eSOFqI3f/DGA3eSvgmxHHBbJxyD6dB/sg== + dependencies: + "@types/d3-interpolate" "^1.3.1" + "@types/d3-scale" "^3.2.1" + "@types/d3-time" "^1.0.10" + d3-interpolate "^1.4.0" + d3-scale "^3.2.3" + d3-time "^1.1.0" + +"@visx/shape@1.16.0": + version "1.16.0" + resolved "https://registry.yarnpkg.com/@visx/shape/-/shape-1.16.0.tgz#e53182e98009ac5554d39ee1af647cc78a0e6669" + integrity sha512-+itAegbZiKegzDpBMRd/XQ13bR/YXzR7VcovQLzPE7GQqszq+efrrzNyjjnRLRBL9bZcCmp60aYSiDMOQVX0Tw== + dependencies: + "@types/classnames" "^2.2.9" + "@types/d3-path" "^1.0.8" + "@types/d3-shape" "^1.3.1" + "@types/lodash" "^4.14.146" + "@types/react" "*" + "@visx/curve" "1.7.0" + "@visx/group" "1.7.0" + "@visx/scale" "1.14.0" + classnames "^2.2.5" + d3-path "^1.0.5" + d3-shape "^1.2.0" + lodash "^4.17.15" + prop-types "^15.5.10" + +"@visx/shape@1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@visx/shape/-/shape-1.8.0.tgz#e9e1d584011aabd142bf8501edf1da4b5f29dee3" + integrity sha512-EclCdmgfkqoAiGWsJ652dZzQIdPGKDuOkCa1qnwqPuFMjL19nSlLvI0n/yH45kWcPa5etz9iZ50LQ+6YMgvYSQ== + dependencies: + "@types/classnames" "^2.2.9" + "@types/d3-path" "^1.0.8" + "@types/d3-shape" "^1.3.1" + "@types/lodash" "^4.14.146" + "@types/react" "*" + "@visx/curve" "1.7.0" + "@visx/group" "1.7.0" + "@visx/scale" "1.7.0" + classnames "^2.2.5" + d3-path "^1.0.5" + d3-shape "^1.2.0" + lodash "^4.17.15" + prop-types "^15.5.10" + +"@visx/text@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@visx/text/-/text-1.7.0.tgz#530dfd85426fa87c3a43ae1d96e3148a14e7c864" + integrity sha512-zygMV2xSXfHHt3BLmWakTcQCk971n3vrY6iKyLEry3IyYdJy91ueKIU8OSMaKjrX0HrlT/QVP3B5QVt9knsRzg== + dependencies: + "@types/classnames" "^2.2.9" + "@types/lodash" "^4.14.160" + "@types/react" "*" + classnames "^2.2.5" + lodash "^4.17.20" + prop-types "^15.7.2" + reduce-css-calc "^1.3.0" + "@webassemblyjs/ast@1.11.0": version "1.11.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.0.tgz#a5aa679efdc9e51707a4207139da57920555961f" @@ -3602,7 +3802,7 @@ classlist-polyfill@^1.2.0: resolved "https://registry.yarnpkg.com/classlist-polyfill/-/classlist-polyfill-1.2.0.tgz#935bc2dfd9458a876b279617514638bcaa964a2e" integrity sha1-k1vC39lFiodrJ5YXUUY4vKqWSi4= -classnames@2.3.1: +classnames@*, classnames@2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== @@ -4482,6 +4682,13 @@ cypress@*, cypress@6.8.0, cypress@^6.8.0: url "^0.11.0" yauzl "^2.10.0" +d3-array@2, d3-array@^2.3.0: + version "2.12.1" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-2.12.1.tgz#e20b41aafcdffdf5d50928004ececf815a465e81" + integrity sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ== + dependencies: + internmap "^1.0.0" + d3-array@^1.2.0: version "1.2.4" resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f" @@ -4497,18 +4704,40 @@ d3-color@1: resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.1.tgz#c52002bf8846ada4424d55d97982fef26eb3bc8a" integrity sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q== +"d3-color@1 - 2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-2.0.0.tgz#8d625cab42ed9b8f601a1760a389f7ea9189d62e" + integrity sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ== + d3-format@1: version "1.4.5" resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.5.tgz#374f2ba1320e3717eb74a9356c67daee17a7edb4" integrity sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ== -d3-interpolate@1: +"d3-format@1 - 2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-2.0.0.tgz#a10bcc0f986c372b729ba447382413aabf5b0767" + integrity sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA== + +d3-interpolate@1, d3-interpolate@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.4.0.tgz#526e79e2d80daa383f9e0c1c1c7dcc0f0583e987" integrity sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA== dependencies: d3-color "1" +"d3-interpolate@1.2.0 - 2": + version "2.0.1" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-2.0.1.tgz#98be499cfb8a3b94d4ff616900501a64abc91163" + integrity sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ== + dependencies: + d3-color "1 - 2" + +d3-path@1, d3-path@^1.0.5: + version "1.0.9" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf" + integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg== + d3-scale@^2.1.0: version "2.2.2" resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-2.2.2.tgz#4e880e0b2745acaaddd3ede26a9e908a9e17b81f" @@ -4521,6 +4750,24 @@ d3-scale@^2.1.0: d3-time "1" d3-time-format "2" +d3-scale@^3.2.3, d3-scale@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-3.3.0.tgz#28c600b29f47e5b9cd2df9749c206727966203f3" + integrity sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ== + dependencies: + d3-array "^2.3.0" + d3-format "1 - 2" + d3-interpolate "1.2.0 - 2" + d3-time "^2.1.1" + d3-time-format "2 - 3" + +d3-shape@^1.0.6, d3-shape@^1.2.0: + version "1.3.7" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7" + integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw== + dependencies: + d3-path "1" + d3-time-format@2: version "2.3.0" resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.3.0.tgz#107bdc028667788a8924ba040faf1fbccd5a7850" @@ -4528,11 +4775,25 @@ d3-time-format@2: dependencies: d3-time "1" -d3-time@1: +"d3-time-format@2 - 3": + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-3.0.0.tgz#df8056c83659e01f20ac5da5fdeae7c08d5f1bb6" + integrity sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag== + dependencies: + d3-time "1 - 2" + +d3-time@1, d3-time@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.1.0.tgz#b1e19d307dae9c900b7e5b25ffc5dcc249a8a0f1" integrity sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA== +"d3-time@1 - 2", d3-time@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-2.1.1.tgz#e9d8a8a88691f4548e68ca085e5ff956724a6682" + integrity sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ== + dependencies: + d3-array "2" + d3@^3, d3@^3.5.17: version "3.5.17" resolved "https://registry.yarnpkg.com/d3/-/d3-3.5.17.tgz#bc46748004378b21a360c9fc7cf5231790762fb8" @@ -7058,6 +7319,11 @@ internal-slot@^1.0.3: has "^1.0.3" side-channel "^1.0.4" +internmap@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95" + integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw== + interpret@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" @@ -8697,7 +8963,7 @@ lodash@^4.0.0, lodash@^4.0.1, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.17.11, l resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== -lodash@^4.17.20: +lodash@^4.17.15, lodash@^4.17.20: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -11583,7 +11849,7 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" -reduce-css-calc@^1.2.6, reduce-css-calc@^1.2.7: +reduce-css-calc@^1.2.6, reduce-css-calc@^1.2.7, reduce-css-calc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" integrity sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=