Skip to content
Snippets Groups Projects
Commit b91f5cbe authored by Bjarke Madsen's avatar Bjarke Madsen
Browse files

Create reusable method for creating graph legends

Add legend at the top and bottom of the staffgraphs
parent 40c2e5d1
No related branches found
No related tags found
1 merge request!34Rework to use a common font config across graphs and add x-axis and legends on top and bottom of graphs
import React from 'react';
interface InputProps {
children: React.ReactNode;
location?: "top" | "bottom" | "both"
}
const WithLegend: React.FC<InputProps> = ({ children, location }) => {
if (!location) location = "both";
const top = location === "top" || location === "both";
const bottom = location === "bottom" || location === "both";
return (
<>
{top && <div style={{ paddingLeft: '33%', 'paddingTop': '2.5rem', 'paddingBottom': '1.5rem' }} id={'legendtop'} />}
{children}
{bottom && <div style={{ paddingLeft: '33%', 'paddingTop': '1.5rem' }} id={'legendbottom'} />}
</>
);
};
export default WithLegend;
......@@ -7,8 +7,8 @@ import { createNRENStaffDataset, getYearsAndNrens, loadDataWithFilterSelectionFa
import DataPage from '../components/DataPage';
import Filter from "../components/graphing/Filter"
import { Sections } from '../helpers/constants';
ChartJS.defaults.font.size = 14;
import WithLegend from '../components/WithLegend';
import htmlLegendPlugin from '../plugins/HTMLLegendPlugin';
ChartJS.register(
CategoryScale,
......@@ -25,9 +25,12 @@ const chartOptions = {
duration: 0
},
plugins: {
htmlLegend: {
// ID of the container(s) to put the legend in
containerIDs: ['legendtop', 'legendbottom'],
},
legend: {
display: true,
position: 'bottom' as const
display: false,
},
tooltip: {
callbacks: {
......@@ -126,12 +129,15 @@ function StaffGraph({ filterSelection, setFilterSelection, roles = false }: inpu
const text = roles ? "Roles" : "Employment";
return (
<DataPage title={"NREN Staff " + text} category={Sections.Organisation} filter={filterNode}>
<div className="chart-container" style={{ 'height': `${height}rem` }}>
<Bar
data={nrenStaffDataset}
options={chartOptions}
/>
</div>
<WithLegend>
<div className="chart-container" style={{ 'height': `${height}rem` }}>
<Bar
data={nrenStaffDataset}
options={chartOptions}
plugins={[htmlLegendPlugin]}
/>
</div>
</WithLegend>
</DataPage>
);
}
......
const getOrCreateLegendList = (chart, id) => {
const legendContainer = document.getElementById(id);
if (!legendContainer) {
return null;
}
let listContainer = legendContainer.querySelector('ul');
if (!listContainer) {
listContainer = document.createElement('ul');
listContainer.style.display = 'flex';
listContainer.style.flexDirection = 'row';
listContainer.style.margin = '0';
listContainer.style.padding = '0';
legendContainer.appendChild(listContainer);
}
return listContainer;
};
const htmlLegendPlugin = {
id: 'htmlLegend',
afterUpdate(chart, args, options) {
for (const id of options.containerIDs) {
const ul = getOrCreateLegendList(chart, id);
if (!ul) {
return;
}
// Remove old legend items
while (ul.firstChild) {
ul.firstChild.remove();
}
// Reuse the built-in legendItems generator
const items = chart.options.plugins.legend.labels.generateLabels(chart);
items.forEach(item => {
const li = document.createElement('li');
li.style.alignItems = 'center';
li.style.cursor = 'pointer';
li.style.display = 'flex';
li.style.flexDirection = 'row';
li.style.marginLeft = '10px';
li.onclick = () => {
const { type } = chart.config;
if (type === 'pie' || type === 'doughnut') {
// Pie and doughnut charts only have a single dataset and visibility is per item
chart.toggleDataVisibility(item.index);
} else {
chart.setDatasetVisibility(item.datasetIndex, !chart.isDatasetVisible(item.datasetIndex));
}
chart.update();
};
// Color box
const boxSpan = document.createElement('span');
boxSpan.style.background = item.fillStyle;
boxSpan.style.borderColor = item.strokeStyle;
boxSpan.style.borderWidth = item.lineWidth + 'px';
boxSpan.style.display = 'inline-block';
boxSpan.style.height = '1rem';
boxSpan.style.marginRight = '10px';
boxSpan.style.width = '2.5rem';
// Text
const textContainer = document.createElement('p');
textContainer.style.color = item.fontColor;
textContainer.style.margin = '0';
textContainer.style.padding = '0';
textContainer.style.textDecoration = item.hidden ? 'line-through' : '';
const text = document.createTextNode(item.text);
textContainer.appendChild(text);
li.appendChild(boxSpan);
li.appendChild(textContainer);
ul.appendChild(li);
});
}
}
};
export default htmlLegendPlugin;
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment