Skip to content
Snippets Groups Projects
Unverified Commit 5d91c0e9 authored by Alexander Lesnenko's avatar Alexander Lesnenko Committed by GitHub
Browse files

Revert "Clean up old static charts (#19653)" (#19688)

This reverts commit 5fdeed90.
parent eba5b71f
No related branches found
No related tags found
No related merge requests found
Showing
with 1277 additions and 1 deletion
......@@ -17,7 +17,181 @@ export default function StaticVizPage() {
/static-viz/ and see the effects. You might need to hard refresh to
see updates.
</Text>
<Box py={3}>
<Subhead>Line chart with timeseries data</Subhead>
<StaticChart
type="timeseries/line"
options={{
data: [
["2020-01-10", 10],
["2020-06-10", 60],
["2020-12-10", 80],
],
accessors: {
x: row => new Date(row[0]).valueOf(),
y: row => row[1],
},
labels: {
left: "Count",
bottom: "Created At",
},
}}
/>
</Box>
<Box py={3}>
<Subhead>Area chart with timeseries data</Subhead>
<StaticChart
type="timeseries/area"
options={{
data: [
["2020-01-10", 10],
["2020-06-10", 60],
["2020-12-10", 80],
],
accessors: {
x: row => new Date(row[0]).valueOf(),
y: row => row[1],
},
settings: {
x: {
date_style: "MMM",
},
},
labels: {
left: "Count",
bottom: "Created At",
},
colors: {
brand: "#88BF4D",
},
}}
/>
</Box>
<Box py={3}>
<Subhead>Bar chart with timeseries data</Subhead>
<StaticChart
type="timeseries/bar"
options={{
data: [
["2020-10-21", 20],
["2020-10-22", 30],
["2020-10-23", 25],
["2020-10-24", 10],
["2020-10-25", 15],
],
accessors: {
x: row => new Date(row[0]).valueOf(),
y: row => row[1],
},
settings: {
x: {
date_style: "MM/DD/YYYY",
},
y: {
number_style: "currency",
currency: "USD",
currency_style: "symbol",
decimals: 0,
},
},
labels: {
left: "Price",
bottom: "Created At",
},
}}
/>
</Box>
<Box py={3}>
<Subhead>Line chart with categorical data</Subhead>
<StaticChart
type="categorical/line"
options={{
data: [
["Alden Sparks", 70],
["Areli Guerra", 30],
["Arturo Hopkins", 80],
["Beatrice Lane", 120],
["Brylee Davenport", 100],
["Cali Nixon", 60],
["Dane Terrell", 150],
["Deshawn Rollins", 40],
["Isabell Bright", 70],
["Kaya Rowe", 20],
["Roderick Herman", 50],
["Ruth Dougherty", 75],
],
accessors: {
x: row => row[0],
y: row => row[1],
},
labels: {
left: "Tasks",
bottom: "People",
},
}}
/>
</Box>
<Box py={3}>
<Subhead>Area chart with categorical data</Subhead>
<StaticChart
type="categorical/area"
options={{
data: [
["Alden Sparks", 70],
["Areli Guerra", 30],
["Arturo Hopkins", 80],
["Beatrice Lane", 120],
["Brylee Davenport", 100],
["Cali Nixon", 60],
["Dane Terrell", 150],
["Deshawn Rollins", 40],
["Isabell Bright", 70],
["Kaya Rowe", 20],
["Roderick Herman", 50],
["Ruth Dougherty", 75],
],
accessors: {
x: row => row[0],
y: row => row[1],
},
labels: {
left: "Tasks",
bottom: "People",
},
}}
/>
</Box>
<Box py={3}>
<Subhead>Bar chart with categorical data</Subhead>
<StaticChart
type="categorical/bar"
options={{
data: [
["Alden Sparks", 70],
["Areli Guerra", 30],
["Arturo Hopkins", 80],
["Beatrice Lane", 120],
["Brylee Davenport", 100],
["Cali Nixon", 60],
["Dane Terrell", 150],
["Deshawn Rollins", 40],
["Isabell Bright", 70],
["Kaya Rowe", 20],
["Roderick Herman", 50],
["Ruth Dougherty", 75],
],
accessors: {
x: row => row[0],
y: row => row[1],
},
labels: {
left: "Tasks",
bottom: "People",
},
}}
/>
</Box>
<Box py={3}>
<Subhead>Donut chart with categorical data</Subhead>
<StaticChart
......
import React from "react";
import PropTypes from "prop-types";
import { AxisBottom, AxisLeft } from "@visx/axis";
import { GridRows } from "@visx/grid";
import { scaleBand, scaleLinear } from "@visx/scale";
import { AreaClosed, LinePath } from "@visx/shape";
import { Text } from "@visx/text";
import {
getXTickWidth,
getXTickLabelProps,
getYTickLabelProps,
getYTickWidth,
getRotatedXTickHeight,
getLabelProps,
} from "../../lib/axes";
import { formatNumber } from "../../lib/numbers";
import { truncateText } from "../../lib/text";
const propTypes = {
data: PropTypes.array.isRequired,
accessors: PropTypes.shape({
x: PropTypes.func.isRequired,
y: PropTypes.func.isRequired,
}).isRequired,
settings: PropTypes.shape({
x: PropTypes.object,
y: PropTypes.object,
colors: PropTypes.object,
}),
labels: PropTypes.shape({
left: PropTypes.string,
bottom: PropTypes.string,
}),
};
const layout = {
width: 540,
height: 300,
margin: {
top: 0,
left: 55,
right: 40,
bottom: 40,
},
font: {
size: 11,
family: "Lato, sans-serif",
},
colors: {
brand: "#509ee3",
textLight: "#b8bbc3",
textMedium: "#949aab",
},
barPadding: 0.2,
labelFontWeight: 700,
labelPadding: 12,
maxTickWidth: 100,
areaOpacity: 0.2,
strokeDasharray: "4",
};
const CategoricalAreaChart = ({ data, accessors, settings, labels }) => {
const colors = settings?.colors;
const isVertical = data.length > 10;
const xTickWidth = getXTickWidth(
data,
accessors,
layout.maxTickWidth,
layout.font.size,
);
const xTickHeight = getRotatedXTickHeight(xTickWidth);
const yTickWidth = getYTickWidth(data, accessors, settings, layout.font.size);
const xLabelOffset = xTickHeight + layout.labelPadding + layout.font.size;
const yLabelOffset = yTickWidth + layout.labelPadding;
const xMin = yLabelOffset + layout.font.size * 1.5;
const xMax = layout.width - layout.margin.right;
const yMin = isVertical ? xLabelOffset : layout.margin.bottom;
const yMax = layout.height - yMin;
const innerWidth = xMax - xMin;
const textBaseline = Math.floor(layout.font.size / 2);
const leftLabel = labels?.left;
const bottomLabel = !isVertical ? labels?.bottom : undefined;
const palette = { ...layout.colors, ...colors };
const xScale = scaleBand({
domain: data.map(accessors.x),
range: [xMin, xMax],
round: true,
padding: layout.barPadding,
});
const yScale = scaleLinear({
domain: [0, Math.max(...data.map(accessors.y))],
range: [yMax, 0],
nice: true,
});
const getXTickProps = ({ x, y, formattedValue, ...props }) => {
const textWidth = isVertical ? xTickWidth : xScale.bandwidth();
const truncatedText = truncateText(
formattedValue,
textWidth,
layout.font.size,
);
const transform = isVertical
? `rotate(45, ${x} ${y}) translate(-${textBaseline} 0)`
: undefined;
return { ...props, x, y, transform, children: truncatedText };
};
return (
<svg width={layout.width} height={layout.height}>
<GridRows
scale={yScale}
left={xMin}
width={innerWidth}
strokeDasharray={layout.strokeDasharray}
/>
<AreaClosed
data={data}
yScale={yScale}
fill={palette.brand}
opacity={layout.areaOpacity}
x={d => xScale(accessors.x(d)) + xScale.bandwidth() / 2}
y={d => yScale(accessors.y(d))}
/>
<AxisLeft
scale={yScale}
left={xMin}
label={leftLabel}
labelOffset={yLabelOffset}
hideTicks
hideAxisLine
labelProps={getLabelProps(layout)}
tickFormat={value => formatNumber(value, settings?.y)}
tickLabelProps={() => getYTickLabelProps(layout)}
/>
<LinePath
data={data}
stroke={palette.brand}
strokeWidth={layout.strokeWidth}
x={d => xScale(accessors.x(d)) + xScale.bandwidth() / 2}
y={d => yScale(accessors.y(d))}
/>
<AxisBottom
scale={xScale}
top={yMax}
label={bottomLabel}
numTicks={data.length}
stroke={palette.textLight}
tickStroke={palette.textLight}
labelProps={getLabelProps(layout)}
tickComponent={props => <Text {...getXTickProps(props)} />}
tickLabelProps={() => getXTickLabelProps(layout, isVertical)}
/>
</svg>
);
};
CategoricalAreaChart.propTypes = propTypes;
export default CategoricalAreaChart;
export { default } from "./CategoricalAreaChart";
import React from "react";
import PropTypes from "prop-types";
import { AxisBottom, AxisLeft } from "@visx/axis";
import { GridRows } from "@visx/grid";
import { scaleBand, scaleLinear } from "@visx/scale";
import { Bar } from "@visx/shape";
import { Text } from "@visx/text";
import {
getXTickWidth,
getXTickLabelProps,
getYTickLabelProps,
getYTickWidth,
getRotatedXTickHeight,
getLabelProps,
} from "../../lib/axes";
import { formatNumber } from "../../lib/numbers";
import { truncateText } from "../../lib/text";
const propTypes = {
data: PropTypes.array.isRequired,
accessors: PropTypes.shape({
x: PropTypes.func.isRequired,
y: PropTypes.func.isRequired,
}).isRequired,
settings: PropTypes.shape({
x: PropTypes.object,
y: PropTypes.object,
colors: PropTypes.object,
}),
labels: PropTypes.shape({
left: PropTypes.string,
bottom: PropTypes.string,
}),
};
const layout = {
width: 540,
height: 300,
margin: {
top: 0,
left: 55,
right: 40,
bottom: 40,
},
font: {
size: 11,
family: "Lato, sans-serif",
},
colors: {
brand: "#509ee3",
textLight: "#b8bbc3",
textMedium: "#949aab",
},
barPadding: 0.2,
labelFontWeight: 700,
labelPadding: 12,
maxTickWidth: 100,
strokeDasharray: "4",
};
const CategoricalBarChart = ({ data, accessors, settings, labels }) => {
const colors = settings?.colors;
const isVertical = data.length > 10;
const xTickWidth = getXTickWidth(
data,
accessors,
layout.maxTickWidth,
layout.font.size,
);
const xTickHeight = getRotatedXTickHeight(xTickWidth);
const yTickWidth = getYTickWidth(data, accessors, settings, layout.font.size);
const xLabelOffset = xTickHeight + layout.labelPadding + layout.font.size;
const yLabelOffset = yTickWidth + layout.labelPadding;
const xMin = yLabelOffset + layout.font.size * 1.5;
const xMax = layout.width - layout.margin.right;
const yMin = isVertical ? xLabelOffset : layout.margin.bottom;
const yMax = layout.height - yMin;
const innerWidth = xMax - xMin;
const innerHeight = yMax - layout.margin.top;
const textBaseline = Math.floor(layout.font.size / 2);
const leftLabel = labels?.left;
const bottomLabel = !isVertical ? labels?.bottom : undefined;
const palette = { ...layout.colors, ...colors };
const xScale = scaleBand({
domain: data.map(accessors.x),
range: [xMin, xMax],
round: true,
padding: layout.barPadding,
});
const yScale = scaleLinear({
domain: [0, Math.max(...data.map(accessors.y))],
range: [yMax, 0],
nice: true,
});
const getBarProps = d => {
const width = xScale.bandwidth();
const height = innerHeight - yScale(accessors.y(d));
const x = xScale(accessors.x(d));
const y = yMax - height;
return { x, y, width, height, fill: palette.brand };
};
const getXTickProps = ({ x, y, formattedValue, ...props }) => {
const textWidth = isVertical ? xTickWidth : xScale.bandwidth();
const truncatedText = truncateText(
formattedValue,
textWidth,
layout.font.size,
);
const transform = isVertical
? `rotate(45, ${x} ${y}) translate(-${textBaseline} 0)`
: undefined;
return { ...props, x, y, transform, children: truncatedText };
};
return (
<svg width={layout.width} height={layout.height}>
<GridRows
scale={yScale}
left={xMin}
width={innerWidth}
strokeDasharray={layout.strokeDasharray}
/>
{data.map((d, index) => (
<Bar key={index} {...getBarProps(d)} />
))}
<AxisLeft
scale={yScale}
left={xMin}
label={leftLabel}
labelOffset={yLabelOffset}
hideTicks
hideAxisLine
labelProps={getLabelProps(layout)}
tickFormat={value => formatNumber(value, settings?.y)}
tickLabelProps={() => getYTickLabelProps(layout)}
/>
<AxisBottom
scale={xScale}
top={yMax}
label={bottomLabel}
numTicks={data.length}
stroke={palette.textLight}
tickStroke={palette.textLight}
labelProps={getLabelProps(layout)}
tickComponent={props => <Text {...getXTickProps(props)} />}
tickLabelProps={() => getXTickLabelProps(layout, isVertical)}
/>
</svg>
);
};
CategoricalBarChart.propTypes = propTypes;
export default CategoricalBarChart;
export { default } from "./CategoricalBarChart";
import React from "react";
import PropTypes from "prop-types";
import { AxisBottom, AxisLeft } from "@visx/axis";
import { GridRows } from "@visx/grid";
import { scaleBand, scaleLinear } from "@visx/scale";
import { LinePath } from "@visx/shape";
import { Text } from "@visx/text";
import {
getXTickWidth,
getXTickLabelProps,
getYTickLabelProps,
getYTickWidth,
getRotatedXTickHeight,
getLabelProps,
} from "../../lib/axes";
import { formatNumber } from "../../lib/numbers";
import { truncateText } from "../../lib/text";
const propTypes = {
data: PropTypes.array.isRequired,
accessors: PropTypes.shape({
x: PropTypes.func.isRequired,
y: PropTypes.func.isRequired,
}).isRequired,
settings: PropTypes.shape({
x: PropTypes.object,
y: PropTypes.object,
colors: PropTypes.object,
}),
labels: PropTypes.shape({
left: PropTypes.string,
bottom: PropTypes.string,
}),
};
const layout = {
width: 540,
height: 300,
margin: {
top: 0,
left: 55,
right: 40,
bottom: 40,
},
font: {
size: 11,
family: "Lato, sans-serif",
},
colors: {
brand: "#509ee3",
textLight: "#b8bbc3",
textMedium: "#949aab",
},
barPadding: 0.2,
labelFontWeight: 700,
labelPadding: 12,
maxTickWidth: 100,
strokeDasharray: "4",
};
const CategoricalLineChart = ({ data, accessors, settings, labels }) => {
const colors = settings?.colors;
const isVertical = data.length > 10;
const xTickWidth = getXTickWidth(
data,
accessors,
layout.maxTickWidth,
layout.font.size,
);
const xTickHeight = getRotatedXTickHeight(xTickWidth);
const yTickWidth = getYTickWidth(data, accessors, settings, layout.font.size);
const xLabelOffset = xTickHeight + layout.labelPadding + layout.font.size;
const yLabelOffset = yTickWidth + layout.labelPadding;
const xMin = yLabelOffset + layout.font.size * 1.5;
const xMax = layout.width - layout.margin.right;
const yMin = isVertical ? xLabelOffset : layout.margin.bottom;
const yMax = layout.height - yMin;
const innerWidth = xMax - xMin;
const textBaseline = Math.floor(layout.font.size / 2);
const leftLabel = labels?.left;
const bottomLabel = !isVertical ? labels?.bottom : undefined;
const palette = { ...layout.colors, ...colors };
const xScale = scaleBand({
domain: data.map(accessors.x),
range: [xMin, xMax],
round: true,
padding: layout.barPadding,
});
const yScale = scaleLinear({
domain: [0, Math.max(...data.map(accessors.y))],
range: [yMax, 0],
nice: true,
});
const getXTickProps = ({ x, y, formattedValue, ...props }) => {
const textWidth = isVertical ? xTickWidth : xScale.bandwidth();
const truncatedText = truncateText(
formattedValue,
textWidth,
layout.font.size,
);
const transform = isVertical
? `rotate(45, ${x} ${y}) translate(-${textBaseline} 0)`
: undefined;
return { ...props, x, y, transform, children: truncatedText };
};
return (
<svg width={layout.width} height={layout.height}>
<GridRows
scale={yScale}
left={xMin}
width={innerWidth}
strokeDasharray={layout.strokeDasharray}
/>
<LinePath
data={data}
stroke={palette.brand}
strokeWidth={layout.strokeWidth}
x={d => xScale(accessors.x(d)) + xScale.bandwidth() / 2}
y={d => yScale(accessors.y(d))}
/>
<AxisLeft
scale={yScale}
left={xMin}
label={leftLabel}
labelOffset={yLabelOffset}
hideTicks
hideAxisLine
labelProps={getLabelProps(layout)}
tickFormat={value => formatNumber(value, settings?.y)}
tickLabelProps={() => getYTickLabelProps(layout)}
/>
<AxisBottom
scale={xScale}
top={yMax}
label={bottomLabel}
numTicks={data.length}
stroke={palette.textLight}
tickStroke={palette.textLight}
labelProps={getLabelProps(layout)}
tickComponent={props => <Text {...getXTickProps(props)} />}
tickLabelProps={() => getXTickLabelProps(layout, isVertical)}
/>
</svg>
);
};
CategoricalLineChart.propTypes = propTypes;
export default CategoricalLineChart;
export { default } from "./CategoricalLineChart";
import React from "react";
import PropTypes from "prop-types";
import { scaleLinear, scaleTime } from "@visx/scale";
import { GridRows } from "@visx/grid";
import { AxisBottom, AxisLeft } from "@visx/axis";
import { AreaClosed, LinePath } from "@visx/shape";
import {
getLabelProps,
getXTickLabelProps,
getYTickLabelProps,
getYTickWidth,
} from "../../lib/axes";
import { formatDate } from "../../lib/dates";
import { formatNumber } from "../../lib/numbers";
import { sortTimeSeries } from "../../lib/sort";
const propTypes = {
data: PropTypes.array.isRequired,
accessors: PropTypes.shape({
x: PropTypes.func,
y: PropTypes.func,
}).isRequired,
settings: PropTypes.shape({
x: PropTypes.object,
y: PropTypes.object,
colors: PropTypes.object,
}),
labels: PropTypes.shape({
left: PropTypes.string,
bottom: PropTypes.string,
}),
};
const layout = {
width: 540,
height: 300,
margin: {
top: 0,
left: 55,
right: 40,
bottom: 40,
},
font: {
size: 11,
family: "Lato, sans-serif",
},
colors: {
brand: "#509ee3",
brandLight: "#DDECFA",
textLight: "#b8bbc3",
textMedium: "#949aab",
},
numTicks: 5,
strokeWidth: 2,
labelFontWeight: 700,
labelPadding: 12,
areaOpacity: 0.2,
strokeDasharray: "4",
};
const TimeSeriesAreaChart = ({ data, accessors, settings, labels }) => {
data = sortTimeSeries(data);
const colors = settings?.colors;
const yTickWidth = getYTickWidth(data, accessors, settings, layout.font.size);
const yLabelOffset = yTickWidth + layout.labelPadding;
const xMin = yLabelOffset + layout.font.size * 1.5;
const xMax = layout.width - layout.margin.right;
const yMax = layout.height - layout.margin.bottom;
const innerWidth = xMax - xMin;
const leftLabel = labels?.left;
const bottomLabel = labels?.bottom;
const palette = { ...layout.colors, ...colors };
const xScale = scaleTime({
domain: [
Math.min(...data.map(accessors.x)),
Math.max(...data.map(accessors.x)),
],
range: [xMin, xMax],
});
const yScale = scaleLinear({
domain: [0, Math.max(...data.map(accessors.y))],
range: [yMax, 0],
nice: true,
});
return (
<svg width={layout.width} height={layout.height}>
<GridRows
scale={yScale}
left={xMin}
width={innerWidth}
strokeDasharray={layout.strokeDasharray}
/>
<AreaClosed
data={data}
yScale={yScale}
fill={palette.brand}
opacity={layout.areaOpacity}
x={d => xScale(accessors.x(d))}
y={d => yScale(accessors.y(d))}
/>
<LinePath
data={data}
stroke={palette.brand}
strokeWidth={layout.strokeWidth}
x={d => xScale(accessors.x(d))}
y={d => yScale(accessors.y(d))}
/>
<AxisLeft
scale={yScale}
left={xMin}
label={leftLabel}
labelOffset={yLabelOffset}
hideTicks
hideAxisLine
labelProps={getLabelProps(layout)}
tickFormat={value => formatNumber(value, settings?.y)}
tickLabelProps={() => getYTickLabelProps(layout)}
/>
<AxisBottom
scale={xScale}
top={yMax}
label={bottomLabel}
numTicks={layout.numTicks}
stroke={palette.textLight}
tickStroke={palette.textLight}
labelProps={getLabelProps(layout)}
tickFormat={value => formatDate(value, settings?.x)}
tickLabelProps={() => getXTickLabelProps(layout)}
/>
</svg>
);
};
TimeSeriesAreaChart.propTypes = propTypes;
export default TimeSeriesAreaChart;
export { default } from "./TimeSeriesAreaChart";
import React from "react";
import PropTypes from "prop-types";
import { AxisBottom, AxisLeft } from "@visx/axis";
import { GridRows } from "@visx/grid";
import { scaleBand, scaleLinear } from "@visx/scale";
import { Bar } from "@visx/shape";
import {
getLabelProps,
getXTickLabelProps,
getYTickLabelProps,
getYTickWidth,
} from "../../lib/axes";
import { formatDate } from "../../lib/dates";
import { formatNumber } from "../../lib/numbers";
import { sortTimeSeries } from "../../lib/sort";
const propTypes = {
data: PropTypes.array.isRequired,
accessors: PropTypes.shape({
x: PropTypes.func.isRequired,
y: PropTypes.func.isRequired,
}).isRequired,
settings: PropTypes.shape({
x: PropTypes.object,
y: PropTypes.object,
colors: PropTypes.object,
}),
labels: PropTypes.shape({
left: PropTypes.string,
bottom: PropTypes.string,
}),
};
const layout = {
width: 540,
height: 300,
margin: {
top: 0,
left: 55,
right: 40,
bottom: 40,
},
font: {
size: 11,
family: "Lato, sans-serif",
},
colors: {
brand: "#509ee3",
textLight: "#b8bbc3",
textMedium: "#949aab",
},
numTicks: 5,
barPadding: 0.2,
labelFontWeight: 700,
labelPadding: 12,
strokeDasharray: "4",
};
const TimeSeriesBarChart = ({ data, accessors, settings, labels }) => {
data = sortTimeSeries(data);
const colors = settings?.colors;
const yTickWidth = getYTickWidth(data, accessors, settings, layout.font.size);
const yLabelOffset = yTickWidth + layout.labelPadding;
const xMin = yLabelOffset + layout.font.size * 1.5;
const xMax = layout.width - layout.margin.right;
const yMax = layout.height - layout.margin.bottom;
const innerWidth = xMax - xMin;
const innerHeight = yMax - layout.margin.top;
const leftLabel = labels?.left;
const bottomLabel = labels?.bottom;
const palette = { ...layout.colors, ...colors };
const xScale = scaleBand({
domain: data.map(accessors.x),
range: [xMin, xMax],
round: true,
padding: layout.barPadding,
});
const yScale = scaleLinear({
domain: [0, Math.max(...data.map(accessors.y))],
range: [yMax, 0],
nice: true,
});
const getBarProps = d => {
const width = xScale.bandwidth();
const height = innerHeight - yScale(accessors.y(d));
const x = xScale(accessors.x(d));
const y = yMax - height;
return { x, y, width, height, fill: palette.brand };
};
return (
<svg width={layout.width} height={layout.height}>
<GridRows
scale={yScale}
left={xMin}
width={innerWidth}
strokeDasharray={layout.strokeDasharray}
/>
{data.map((d, index) => (
<Bar key={index} {...getBarProps(d)} />
))}
<AxisLeft
scale={yScale}
left={xMin}
label={leftLabel}
labelOffset={yLabelOffset}
hideTicks
hideAxisLine
labelProps={getLabelProps(layout)}
tickFormat={value => formatNumber(value, settings?.y)}
tickLabelProps={() => getYTickLabelProps(layout)}
/>
<AxisBottom
scale={xScale}
top={yMax}
label={bottomLabel}
numTicks={layout.numTicks}
stroke={palette.textLight}
tickStroke={palette.textLight}
labelProps={getLabelProps(layout)}
tickFormat={value => formatDate(value, settings?.x)}
tickLabelProps={() => getXTickLabelProps(layout)}
/>
</svg>
);
};
TimeSeriesBarChart.propTypes = propTypes;
export default TimeSeriesBarChart;
export { default } from "./TimeSeriesBarChart";
import React from "react";
import PropTypes from "prop-types";
import { scaleLinear, scaleTime } from "@visx/scale";
import { GridRows } from "@visx/grid";
import { AxisBottom, AxisLeft } from "@visx/axis";
import { LinePath } from "@visx/shape";
import {
getXTickLabelProps,
getYTickWidth,
getYTickLabelProps,
getLabelProps,
} from "../../lib/axes";
import { formatDate } from "../../lib/dates";
import { formatNumber } from "../../lib/numbers";
import { sortTimeSeries } from "../../lib/sort";
const propTypes = {
data: PropTypes.array.isRequired,
accessors: PropTypes.shape({
x: PropTypes.func,
y: PropTypes.func,
}).isRequired,
settings: PropTypes.shape({
x: PropTypes.object,
y: PropTypes.object,
colors: PropTypes.object,
}),
labels: PropTypes.shape({
left: PropTypes.string,
bottom: PropTypes.string,
}),
};
const layout = {
width: 540,
height: 300,
margin: {
top: 0,
left: 55,
right: 40,
bottom: 40,
},
font: {
size: 11,
family: "Lato, sans-serif",
},
colors: {
brand: "#509ee3",
textLight: "#b8bbc3",
textMedium: "#949aab",
},
numTicks: 5,
labelFontWeight: 700,
labelPadding: 12,
strokeWidth: 2,
strokeDasharray: "4",
};
const TimeSeriesLineChart = ({ data, accessors, settings, labels }) => {
data = sortTimeSeries(data);
const colors = settings?.colors;
const yTickWidth = getYTickWidth(data, accessors, settings, layout.font.size);
const yLabelOffset = yTickWidth + layout.labelPadding;
const xMin = yLabelOffset + layout.font.size * 1.5;
const xMax = layout.width - layout.margin.right;
const yMax = layout.height - layout.margin.bottom;
const innerWidth = xMax - xMin;
const leftLabel = labels?.left;
const bottomLabel = labels?.bottom;
const palette = { ...layout.colors, ...colors };
const xScale = scaleTime({
domain: [
Math.min(...data.map(accessors.x)),
Math.max(...data.map(accessors.x)),
],
range: [xMin, xMax],
});
const yScale = scaleLinear({
domain: [0, Math.max(...data.map(accessors.y))],
range: [yMax, 0],
nice: true,
});
return (
<svg width={layout.width} height={layout.height}>
<GridRows
scale={yScale}
left={xMin}
width={innerWidth}
strokeDasharray={layout.strokeDasharray}
/>
<LinePath
data={data}
stroke={palette.brand}
strokeWidth={layout.strokeWidth}
x={d => xScale(accessors.x(d))}
y={d => yScale(accessors.y(d))}
/>
<AxisLeft
scale={yScale}
left={xMin}
label={leftLabel}
labelOffset={yLabelOffset}
hideTicks
hideAxisLine
labelProps={getLabelProps(layout)}
tickFormat={value => formatNumber(value, settings?.y)}
tickLabelProps={() => getYTickLabelProps(layout)}
/>
<AxisBottom
scale={xScale}
top={yMax}
label={bottomLabel}
numTicks={layout.numTicks}
stroke={palette.textLight}
tickStroke={palette.textLight}
labelProps={getLabelProps(layout)}
tickFormat={value => formatDate(value, settings?.x)}
tickLabelProps={() => getXTickLabelProps(layout)}
/>
</svg>
);
};
TimeSeriesLineChart.propTypes = propTypes;
export default TimeSeriesLineChart;
export { default } from "./TimeSeriesLineChart";
import React from "react";
import PropTypes from "prop-types";
import CategoricalAreaChart from "../../components/CategoricalAreaChart";
import CategoricalBarChart from "../../components/CategoricalBarChart";
import CategoricalDonutChart from "../../components/CategoricalDonutChart";
import CategoricalLineChart from "../../components/CategoricalLineChart";
import CategoricalWaterfallChart from "../../components/CategoricalWaterfallChart";
import TimeSeriesAreaChart from "../../components/TimeSeriesAreaChart";
import TimeSeriesBarChart from "../../components/TimeSeriesBarChart";
import TimeSeriesLineChart from "../../components/TimeSeriesLineChart";
import ProgressBar from "../../components/ProgressBar";
import Funnel from "../../components/FunnelChart";
import TimeSeriesWaterfallChart from "../../components/TimeSeriesWaterfallChart";
......@@ -9,8 +15,14 @@ import LineAreaBarChart from "../../components/LineAreaBarChart";
const propTypes = {
type: PropTypes.oneOf([
"categorical/area",
"categorical/bar",
"categorical/donut",
"categorical/line",
"categorical/waterfall",
"timeseries/area",
"timeseries/bar",
"timeseries/line",
"timeseries/waterfall",
"progress",
"combo-chart",
......@@ -21,10 +33,22 @@ const propTypes = {
const StaticChart = ({ type, options }) => {
switch (type) {
case "categorical/area":
return <CategoricalAreaChart {...options} />;
case "categorical/bar":
return <CategoricalBarChart {...options} />;
case "categorical/donut":
return <CategoricalDonutChart {...options} />;
case "categorical/line":
return <CategoricalLineChart {...options} />;
case "categorical/waterfall":
return <CategoricalWaterfallChart {...options} />;
case "timeseries/area":
return <TimeSeriesAreaChart {...options} />;
case "timeseries/bar":
return <TimeSeriesBarChart {...options} />;
case "timeseries/line":
return <TimeSeriesLineChart {...options} />;
case "timeseries/waterfall":
return <TimeSeriesWaterfallChart {...options} />;
case "progress":
......
......@@ -3,6 +3,108 @@ import { render, screen } from "@testing-library/react";
import StaticChart from "./StaticChart";
describe("StaticChart", () => {
it("should render categorical/line", () => {
render(
<StaticChart
type="categorical/line"
options={{
data: [
["Gadget", 20],
["Widget", 31],
],
accessors: {
x: row => row[0],
y: row => row[1],
},
settings: {
y: {
number_style: "currency",
currency: "USD",
currency_style: "symbol",
},
},
labels: {
left: "Count",
bottom: "Category",
},
}}
/>,
);
screen.getByText("Gadget");
screen.getByText("Widget");
screen.getAllByText("Count");
screen.getAllByText("Category");
});
it("should render categorical/area", () => {
render(
<StaticChart
type="categorical/area"
options={{
data: [
["Gadget", 20],
["Widget", 31],
],
accessors: {
x: row => row[0],
y: row => row[1],
},
settings: {
y: {
number_style: "currency",
currency: "USD",
currency_style: "symbol",
},
},
labels: {
left: "Count",
bottom: "Category",
},
}}
/>,
);
screen.getByText("Gadget");
screen.getByText("Widget");
screen.getAllByText("Count");
screen.getAllByText("Category");
});
it("should render categorical/bar", () => {
render(
<StaticChart
type="categorical/bar"
options={{
data: [
["Gadget", 20],
["Widget", 31],
],
accessors: {
x: row => row[0],
y: row => row[1],
},
settings: {
y: {
number_style: "currency",
currency: "USD",
currency_style: "symbol",
},
},
labels: {
left: "Count",
bottom: "Category",
},
}}
/>,
);
screen.getByText("Gadget");
screen.getByText("Widget");
screen.getAllByText("Count");
screen.getAllByText("Category");
});
it("should render categorical/donut", () => {
render(
<StaticChart
......@@ -34,4 +136,94 @@ describe("StaticChart", () => {
screen.getByText("$5,100.00");
screen.getAllByText("TOTAL");
});
it("should render timeseries/line", () => {
render(
<StaticChart
type="timeseries/line"
options={{
data: [
["2010-11-07", 20],
["2020-11-08", 30],
],
accessors: {
x: row => new Date(row[0]).valueOf(),
y: row => row[1],
},
settings: {
x: {
date_style: "dddd",
},
},
labels: {
left: "Count",
bottom: "Time",
},
}}
/>,
);
screen.getAllByText("Count");
screen.getAllByText("Time");
});
it("should render timeseries/area", () => {
render(
<StaticChart
type="timeseries/area"
options={{
data: [
["2010-11-07", 20],
["2020-11-08", 30],
],
accessors: {
x: row => new Date(row[0]).valueOf(),
y: row => row[1],
},
settings: {
x: {
date_style: "MMM",
},
},
labels: {
left: "Count",
bottom: "Time",
},
}}
/>,
);
screen.getAllByText("Count");
screen.getAllByText("Time");
});
it("should render timeseries/bar", () => {
render(
<StaticChart
type="timeseries/bar"
options={{
data: [
["2010-11-07", 20],
["2020-11-08", 30],
],
accessors: {
x: row => new Date(row[0]).valueOf(),
y: row => row[1],
},
settings: {
x: {
date_style: "dddd",
},
},
labels: {
left: "Count",
bottom: "Time",
},
}}
/>,
);
screen.getAllByText("Count");
screen.getAllByText("Time");
});
});
......@@ -9,7 +9,8 @@ describe("visual tests > internal > static-viz", () => {
it("basic charts", () => {
cy.visit("/_internal/static-viz");
cy.findByText("Waterfall chart with categorical data and total");
cy.findByText("Bar chart with timeseries data");
cy.findByText("Line chart with timeseries data");
cy.findByText("Donut chart with categorical data");
cy.percySnapshot();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment