WIP Fix Stacked Bar Graph
This commit is contained in:
parent
803457c083
commit
047889162e
|
@ -8,17 +8,10 @@
|
|||
|
||||
.legend {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
font-size: calc(16rem / 16);
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.tickLabel {
|
||||
font-family: "Inconsolata", monospace;
|
||||
font-weight: 800;
|
||||
fill: var(--label);
|
||||
}
|
||||
|
||||
.key {
|
||||
font-weight: bold;
|
||||
}
|
|
@ -43,14 +43,17 @@ export type StackedBarProps = {
|
|||
/** Colours for each key */
|
||||
colorRange: string[];
|
||||
/** Distance between the edge of the graph and the area where the bars are drawn, in pixels. */
|
||||
margin: {
|
||||
top: number;
|
||||
left: number;
|
||||
bottom: number;
|
||||
right: number;
|
||||
};
|
||||
margin: { top: number; left: number };
|
||||
/** Number of ticks for the value axis */
|
||||
numTicksValueAxis?: number;
|
||||
/** Distance between the left axis labels and the start of the lines of the graph, in px. */
|
||||
axisLeftOffset?: number;
|
||||
/** Distance between the bottom axis and the bottom of the container of the graph, in px. */
|
||||
axisBottomOffset?: number;
|
||||
/** Distance between the right side of the graph and the legend, in px. */
|
||||
legendLeftOffset?: number;
|
||||
/** Distance between the top of the graph and the legend, in px. */
|
||||
legendTopOffset?: number;
|
||||
/** Width of the lines in the graph, in px. */
|
||||
strokeWidth?: number;
|
||||
/** Length of the dashes and the gaps in the graph, in px. */
|
||||
|
@ -59,6 +62,9 @@ export type StackedBarProps = {
|
|||
scalePadding?: number;
|
||||
/** Margin for each item in the legend */
|
||||
itemMargin?: string;
|
||||
/** Factor multiplied with an offset to center the labels of the category-axis depending on the width/height of the graph.
|
||||
* >1 for width/height <600 and <1 for width/height >600 (vertical=width/horizontal=height) */
|
||||
categoryAxisLeftFactor?: number;
|
||||
};
|
||||
|
||||
let tooltipTimeout: number;
|
||||
|
@ -76,9 +82,14 @@ export const StackedBarGraphVertical = withTooltip<
|
|||
margin,
|
||||
scalePadding = 0.3,
|
||||
numTicksValueAxis = 6,
|
||||
axisLeftOffset = 40,
|
||||
axisBottomOffset = 40,
|
||||
strokeWidth = 2.5,
|
||||
strokeDashArray = "10,4",
|
||||
legendLeftOffset = 40,
|
||||
legendTopOffset = 40,
|
||||
itemMargin = "0 0 0 15px",
|
||||
categoryAxisLeftFactor = 1,
|
||||
tooltipOpen,
|
||||
tooltipLeft,
|
||||
tooltipTop,
|
||||
|
@ -115,15 +126,18 @@ export const StackedBarGraphVertical = withTooltip<
|
|||
});
|
||||
|
||||
// bounds
|
||||
const xMax = width - margin.left - margin.right;
|
||||
const yMax = height - margin.top - margin.bottom;
|
||||
const xMax = width;
|
||||
const yMax = height - margin.top - axisBottomOffset;
|
||||
|
||||
categoryScale.rangeRound([0, xMax]);
|
||||
categoryScale.rangeRound([0, xMax - axisLeftOffset]);
|
||||
valueScale.range([yMax, 0]);
|
||||
|
||||
return width < 10 ? null : (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.legend}>
|
||||
<div
|
||||
className={styles.legend}
|
||||
style={{ left: width + legendLeftOffset, top: legendTopOffset }}
|
||||
>
|
||||
<LegendOrdinal
|
||||
scale={colorScale}
|
||||
direction="row"
|
||||
|
@ -138,6 +152,7 @@ export const StackedBarGraphVertical = withTooltip<
|
|||
scale={valueScale}
|
||||
width={xMax}
|
||||
height={yMax}
|
||||
left={axisLeftOffset}
|
||||
numTicks={numTicksValueAxis}
|
||||
stroke={Color.tertiaryBackground}
|
||||
strokeWidth={strokeWidth}
|
||||
|
@ -146,89 +161,94 @@ export const StackedBarGraphVertical = withTooltip<
|
|||
<GridColumns
|
||||
scale={categoryScale}
|
||||
height={yMax}
|
||||
left={axisLeftOffset}
|
||||
offset={categoryScale.bandwidth() / 2}
|
||||
stroke={Color.tertiaryBackground}
|
||||
strokeWidth={strokeWidth}
|
||||
strokeDasharray={strokeDashArray}
|
||||
/>
|
||||
<BarStack<StackedBarData, string>
|
||||
data={data}
|
||||
keys={keys}
|
||||
x={getCategory}
|
||||
xScale={categoryScale}
|
||||
yScale={valueScale}
|
||||
color={colorScale}
|
||||
>
|
||||
{(barStacks) =>
|
||||
barStacks.map((barStack) =>
|
||||
barStack.bars.map((bar) => (
|
||||
<rect
|
||||
className={styles.barStack}
|
||||
key={`bar-stack-${barStack.index}-${bar.index}`}
|
||||
x={bar.x}
|
||||
y={bar.y}
|
||||
height={bar.height}
|
||||
width={bar.width}
|
||||
fill={bar.color}
|
||||
onMouseLeave={() => {
|
||||
tooltipTimeout = window.setTimeout(() => {
|
||||
hideTooltip();
|
||||
}, 300);
|
||||
}}
|
||||
onMouseMove={(event) => {
|
||||
if (tooltipTimeout) clearTimeout(tooltipTimeout);
|
||||
const eventSvgCoords = localPoint(event);
|
||||
const left = bar.x + bar.width / 2;
|
||||
showTooltip({
|
||||
tooltipData: bar,
|
||||
tooltipTop: eventSvgCoords?.y,
|
||||
tooltipLeft: left,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
))
|
||||
)
|
||||
}
|
||||
</BarStack>
|
||||
<Group left={axisLeftOffset}>
|
||||
<BarStack<StackedBarData, string>
|
||||
data={data}
|
||||
keys={keys}
|
||||
x={getCategory}
|
||||
xScale={categoryScale}
|
||||
yScale={valueScale}
|
||||
color={colorScale}
|
||||
>
|
||||
{(barStacks) =>
|
||||
barStacks.map((barStack) =>
|
||||
barStack.bars.map((bar) => (
|
||||
<rect
|
||||
className={styles.barStack}
|
||||
key={`bar-stack-${barStack.index}-${bar.index}`}
|
||||
x={bar.x}
|
||||
y={bar.y}
|
||||
height={bar.height}
|
||||
width={bar.width / 2}
|
||||
fill={bar.color}
|
||||
onMouseLeave={() => {
|
||||
tooltipTimeout = window.setTimeout(() => {
|
||||
hideTooltip();
|
||||
}, 300);
|
||||
}}
|
||||
onMouseMove={(event) => {
|
||||
if (tooltipTimeout) clearTimeout(tooltipTimeout);
|
||||
const eventSvgCoords = localPoint(event);
|
||||
const left = bar.x + bar.width / 2;
|
||||
showTooltip({
|
||||
tooltipData: bar,
|
||||
tooltipTop: eventSvgCoords?.y,
|
||||
tooltipLeft: left,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
))
|
||||
)
|
||||
}
|
||||
</BarStack>
|
||||
</Group>
|
||||
<Line
|
||||
fill={Color.tertiaryBackground}
|
||||
to={new Point({ x: 0, y: 0 })}
|
||||
from={new Point({ x: 0, y: yMax })}
|
||||
to={new Point({ x: axisLeftOffset, y: 0 })}
|
||||
from={new Point({ x: axisLeftOffset, y: yMax })}
|
||||
stroke={Color.tertiaryBackground}
|
||||
strokeWidth={strokeWidth}
|
||||
strokeDasharray={strokeDashArray}
|
||||
/>
|
||||
</Group>
|
||||
<AxisBottom
|
||||
top={yMax}
|
||||
scale={categoryScale}
|
||||
hideTicks
|
||||
hideAxisLine
|
||||
labelProps={{
|
||||
fontSize: `${10 / 16}rem`,
|
||||
}}
|
||||
tickLabelProps={() => ({
|
||||
className: styles.tickLabel,
|
||||
fill: Color.label,
|
||||
fontWeight: TICK_LABEL_FONT_WEIGHT,
|
||||
width: categoryScale.bandwidth(),
|
||||
verticalAnchor: "start",
|
||||
})}
|
||||
/>
|
||||
<AxisLeft
|
||||
scale={valueScale}
|
||||
top={5}
|
||||
numTicks={numTicksValueAxis}
|
||||
hideAxisLine
|
||||
labelProps={{
|
||||
fontSize: `${10 / 16}rem`,
|
||||
}}
|
||||
tickLabelProps={() => {
|
||||
return {
|
||||
<AxisBottom
|
||||
top={yMax}
|
||||
scale={categoryScale}
|
||||
left={
|
||||
((categoryScale.bandwidth() * 100) / width) *
|
||||
categoryAxisLeftFactor
|
||||
}
|
||||
hideTicks
|
||||
hideAxisLine
|
||||
labelProps={{
|
||||
fontSize: `${10 / 16}rem`,
|
||||
}}
|
||||
tickLabelProps={() => ({
|
||||
fill: Color.label,
|
||||
fontWeight: TICK_LABEL_FONT_WEIGHT,
|
||||
};
|
||||
}}
|
||||
/>
|
||||
})}
|
||||
/>
|
||||
<AxisLeft
|
||||
scale={valueScale}
|
||||
top={5}
|
||||
numTicks={numTicksValueAxis}
|
||||
hideAxisLine
|
||||
labelProps={{
|
||||
fontSize: `${10 / 16}rem`,
|
||||
}}
|
||||
tickLabelProps={() => {
|
||||
return {
|
||||
fill: Color.label,
|
||||
fontWeight: TICK_LABEL_FONT_WEIGHT,
|
||||
};
|
||||
}}
|
||||
/>
|
||||
</Group>
|
||||
</svg>
|
||||
|
||||
{tooltipOpen && tooltipData ? (
|
||||
|
@ -259,9 +279,14 @@ export const StackedBarGraphHorizontal = withTooltip<
|
|||
margin,
|
||||
scalePadding = 0.3,
|
||||
numTicksValueAxis = 6,
|
||||
axisLeftOffset = 40,
|
||||
axisBottomOffset = 40,
|
||||
strokeWidth = 2.5,
|
||||
strokeDashArray = "10,4",
|
||||
legendLeftOffset = 40,
|
||||
legendTopOffset = 40,
|
||||
itemMargin = "0 0 0 15px",
|
||||
categoryAxisLeftFactor = 1,
|
||||
tooltipOpen,
|
||||
tooltipLeft,
|
||||
tooltipTop,
|
||||
|
@ -298,15 +323,18 @@ export const StackedBarGraphHorizontal = withTooltip<
|
|||
});
|
||||
|
||||
// bounds
|
||||
const xMax = width - margin.left - margin.right;
|
||||
const yMax = height - margin.top - margin.bottom;
|
||||
const xMax = width;
|
||||
const yMax = height - margin.top - axisBottomOffset;
|
||||
|
||||
categoryScale.rangeRound([yMax, 0]);
|
||||
valueScale.range([0, xMax]);
|
||||
valueScale.range([0, xMax - axisLeftOffset]);
|
||||
|
||||
return width < 10 ? null : (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.legend}>
|
||||
<div
|
||||
className={styles.legend}
|
||||
style={{ left: width + legendLeftOffset, top: legendTopOffset }}
|
||||
>
|
||||
<LegendOrdinal
|
||||
scale={colorScale}
|
||||
direction="row"
|
||||
|
@ -321,6 +349,7 @@ export const StackedBarGraphHorizontal = withTooltip<
|
|||
width={xMax}
|
||||
height={yMax}
|
||||
offset={categoryScale.bandwidth() / 2}
|
||||
left={axisLeftOffset}
|
||||
stroke={Color.tertiaryBackground}
|
||||
strokeWidth={strokeWidth}
|
||||
strokeDasharray={strokeDashArray}
|
||||
|
@ -329,52 +358,56 @@ export const StackedBarGraphHorizontal = withTooltip<
|
|||
scale={valueScale}
|
||||
height={yMax}
|
||||
numTicks={numTicksValueAxis}
|
||||
left={axisLeftOffset}
|
||||
stroke={Color.tertiaryBackground}
|
||||
strokeWidth={strokeWidth}
|
||||
strokeDasharray={strokeDashArray}
|
||||
/>
|
||||
<BarStackHorizontal<StackedBarData, string>
|
||||
data={data}
|
||||
keys={keys}
|
||||
y={getCategory}
|
||||
xScale={valueScale}
|
||||
yScale={categoryScale}
|
||||
color={colorScale}
|
||||
>
|
||||
{(barStacks) =>
|
||||
barStacks.map((barStack) =>
|
||||
barStack.bars.map((bar) => (
|
||||
<rect
|
||||
className={styles.barStack}
|
||||
key={`bar-stack-${barStack.index}-${bar.index}`}
|
||||
x={bar.x}
|
||||
y={bar.y}
|
||||
height={bar.height / 2}
|
||||
width={bar.width}
|
||||
fill={bar.color}
|
||||
onMouseLeave={() => {
|
||||
tooltipTimeout = window.setTimeout(() => {
|
||||
hideTooltip();
|
||||
}, 300);
|
||||
}}
|
||||
onMouseMove={(event) => {
|
||||
if (tooltipTimeout) clearTimeout(tooltipTimeout);
|
||||
const eventSvgCoords = localPoint(event);
|
||||
const left = bar.x + bar.width / 2;
|
||||
showTooltip({
|
||||
tooltipData: bar,
|
||||
tooltipTop: eventSvgCoords?.y,
|
||||
tooltipLeft: left,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
))
|
||||
)
|
||||
}
|
||||
</BarStackHorizontal>
|
||||
<Group left={axisLeftOffset}>
|
||||
<BarStackHorizontal<StackedBarData, string>
|
||||
data={data}
|
||||
keys={keys}
|
||||
y={getCategory}
|
||||
xScale={valueScale}
|
||||
yScale={categoryScale}
|
||||
color={colorScale}
|
||||
>
|
||||
{(barStacks) =>
|
||||
barStacks.map((barStack) =>
|
||||
barStack.bars.map((bar) => (
|
||||
<rect
|
||||
className={styles.barStack}
|
||||
key={`bar-stack-${barStack.index}-${bar.index}`}
|
||||
x={bar.x}
|
||||
y={bar.y}
|
||||
height={bar.height / 2}
|
||||
width={bar.width}
|
||||
fill={bar.color}
|
||||
onMouseLeave={() => {
|
||||
tooltipTimeout = window.setTimeout(() => {
|
||||
hideTooltip();
|
||||
}, 300);
|
||||
}}
|
||||
onMouseMove={(event) => {
|
||||
if (tooltipTimeout) clearTimeout(tooltipTimeout);
|
||||
const eventSvgCoords = localPoint(event);
|
||||
const left = bar.x + bar.width / 2;
|
||||
showTooltip({
|
||||
tooltipData: bar,
|
||||
tooltipTop: eventSvgCoords?.y,
|
||||
tooltipLeft: left,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
))
|
||||
)
|
||||
}
|
||||
</BarStackHorizontal>
|
||||
</Group>
|
||||
<AxisBottom
|
||||
top={yMax}
|
||||
scale={valueScale}
|
||||
left={axisLeftOffset}
|
||||
numTicks={numTicksValueAxis}
|
||||
hideAxisLine
|
||||
hideTicks
|
||||
|
@ -387,6 +420,10 @@ export const StackedBarGraphHorizontal = withTooltip<
|
|||
})}
|
||||
/>
|
||||
<AxisLeft
|
||||
top={
|
||||
-((categoryScale.bandwidth() * 100) / width) *
|
||||
categoryAxisLeftFactor
|
||||
}
|
||||
scale={categoryScale}
|
||||
hideAxisLine
|
||||
hideTicks
|
||||
|
|
|
@ -251,11 +251,10 @@ export default function Academics() {
|
|||
Color.primaryAccentLighter,
|
||||
]}
|
||||
data={A12i}
|
||||
axisLeftOffset={80}
|
||||
margin={{
|
||||
top: 20,
|
||||
left: 80,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
left: 20,
|
||||
}}
|
||||
/>
|
||||
</ComponentWrapper>
|
||||
|
@ -274,8 +273,8 @@ export default function Academics() {
|
|||
noBackground
|
||||
>
|
||||
<StackedBarGraphVertical
|
||||
width={800}
|
||||
height={500}
|
||||
width={600}
|
||||
height={400}
|
||||
keys={A16Keys}
|
||||
colorRange={[
|
||||
Color.primaryAccent,
|
||||
|
@ -285,9 +284,7 @@ export default function Academics() {
|
|||
data={A16}
|
||||
margin={{
|
||||
top: 20,
|
||||
left: 80,
|
||||
bottom: 70,
|
||||
right: 0,
|
||||
left: 20,
|
||||
}}
|
||||
/>
|
||||
</ComponentWrapper>
|
||||
|
|
|
@ -226,8 +226,6 @@ export default function CoopPage() {
|
|||
margin={{
|
||||
top: 20,
|
||||
left: 20,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
@ -256,8 +254,6 @@ export default function CoopPage() {
|
|||
margin={{
|
||||
top: 20,
|
||||
left: 20,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
@ -301,8 +297,6 @@ export default function CoopPage() {
|
|||
margin={{
|
||||
top: 20,
|
||||
left: 20,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -126,8 +126,6 @@ export default function Home() {
|
|||
margin={{
|
||||
top: 20,
|
||||
left: 20,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
}}
|
||||
/>
|
||||
|
||||
|
@ -151,8 +149,6 @@ export default function Home() {
|
|||
margin={{
|
||||
top: 20,
|
||||
left: 20,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
}}
|
||||
/>
|
||||
|
||||
|
|
Loading…
Reference in New Issue