mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 09:30:31 +03:00
Improved labels displayed in charts when visits are highlighted
This commit is contained in:
parent
b6ab9a1bdd
commit
6a372badfa
4 changed files with 23 additions and 9 deletions
|
@ -13,10 +13,11 @@ const propTypes = {
|
||||||
stats: PropTypes.object,
|
stats: PropTypes.object,
|
||||||
max: PropTypes.number,
|
max: PropTypes.number,
|
||||||
highlightedStats: PropTypes.object,
|
highlightedStats: PropTypes.object,
|
||||||
|
highlightedLabel: PropTypes.string,
|
||||||
onClick: PropTypes.func,
|
onClick: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateGraphData = (title, isBarChart, labels, data, highlightedData) => ({
|
const generateGraphData = (title, isBarChart, labels, data, highlightedData, highlightedLabel) => ({
|
||||||
labels,
|
labels,
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
|
@ -41,7 +42,7 @@ const generateGraphData = (title, isBarChart, labels, data, highlightedData) =>
|
||||||
},
|
},
|
||||||
highlightedData && {
|
highlightedData && {
|
||||||
title,
|
title,
|
||||||
label: 'Selected',
|
label: highlightedLabel || 'Selected',
|
||||||
data: highlightedData,
|
data: highlightedData,
|
||||||
backgroundColor: 'rgba(247, 127, 40, 0.4)',
|
backgroundColor: 'rgba(247, 127, 40, 0.4)',
|
||||||
borderColor: '#F77F28',
|
borderColor: '#F77F28',
|
||||||
|
@ -60,7 +61,7 @@ const determineHeight = (isBarChart, labels) => {
|
||||||
return isBarChart && labels.length > 20 ? labels.length * 8 : null;
|
return isBarChart && labels.length > 20 ? labels.length * 8 : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderGraph = (title, isBarChart, stats, max, highlightedStats, onClick) => {
|
const renderGraph = (title, isBarChart, stats, max, highlightedStats, highlightedLabel, onClick) => {
|
||||||
const hasHighlightedStats = highlightedStats && Object.keys(highlightedStats).length > 0;
|
const hasHighlightedStats = highlightedStats && Object.keys(highlightedStats).length > 0;
|
||||||
const Component = isBarChart ? HorizontalBar : Doughnut;
|
const Component = isBarChart ? HorizontalBar : Doughnut;
|
||||||
const labels = keys(stats).map(dropLabelIfHidden);
|
const labels = keys(stats).map(dropLabelIfHidden);
|
||||||
|
@ -94,7 +95,7 @@ const renderGraph = (title, isBarChart, stats, max, highlightedStats, onClick) =
|
||||||
target.style.cursor = chartElement[0] ? 'pointer' : 'default';
|
target.style.cursor = chartElement[0] ? 'pointer' : 'default';
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
const graphData = generateGraphData(title, isBarChart, labels, data, highlightedData);
|
const graphData = generateGraphData(title, isBarChart, labels, data, highlightedData, highlightedLabel);
|
||||||
const height = determineHeight(isBarChart, labels);
|
const height = determineHeight(isBarChart, labels);
|
||||||
|
|
||||||
// Provide a key based on the height, so that every time the dataset changes, a new graph is rendered
|
// Provide a key based on the height, so that every time the dataset changes, a new graph is rendered
|
||||||
|
@ -118,10 +119,10 @@ const renderGraph = (title, isBarChart, stats, max, highlightedStats, onClick) =
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const GraphCard = ({ title, footer, isBarChart, stats, max, highlightedStats, onClick }) => (
|
const GraphCard = ({ title, footer, isBarChart, stats, max, highlightedStats, highlightedLabel, onClick }) => (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="graph-card__header">{typeof title === 'function' ? title() : title}</CardHeader>
|
<CardHeader className="graph-card__header">{typeof title === 'function' ? title() : title}</CardHeader>
|
||||||
<CardBody>{renderGraph(title, isBarChart, stats, max, highlightedStats, onClick)}</CardBody>
|
<CardBody>{renderGraph(title, isBarChart, stats, max, highlightedStats, highlightedLabel, onClick)}</CardBody>
|
||||||
{footer && <CardFooter className="graph-card__footer--sticky">{footer}</CardFooter>}
|
{footer && <CardFooter className="graph-card__footer--sticky">{footer}</CardFooter>}
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|
|
@ -17,6 +17,7 @@ export default class SortableBarGraph extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
stats: PropTypes.object.isRequired,
|
stats: PropTypes.object.isRequired,
|
||||||
highlightedStats: PropTypes.object,
|
highlightedStats: PropTypes.object,
|
||||||
|
highlightedLabel: PropTypes.string,
|
||||||
title: PropTypes.string.isRequired,
|
title: PropTypes.string.isRequired,
|
||||||
sortingItems: PropTypes.object.isRequired,
|
sortingItems: PropTypes.object.isRequired,
|
||||||
extraHeaderContent: PropTypes.func,
|
extraHeaderContent: PropTypes.func,
|
||||||
|
|
|
@ -42,6 +42,7 @@ const VisitsStats = ({ processStatsFromVisits, normalizeVisits }, OpenMapModalBt
|
||||||
const [ showTable, toggleTable ] = useToggle();
|
const [ showTable, toggleTable ] = useToggle();
|
||||||
const [ tableIsSticky, , setSticky, unsetSticky ] = useToggle();
|
const [ tableIsSticky, , setSticky, unsetSticky ] = useToggle();
|
||||||
const [ highlightedVisits, setHighlightedVisits ] = useState([]);
|
const [ highlightedVisits, setHighlightedVisits ] = useState([]);
|
||||||
|
const [ highlightedLabel, setHighlightedLabel ] = useState();
|
||||||
const [ isMobileDevice, setIsMobileDevice ] = useState(false);
|
const [ isMobileDevice, setIsMobileDevice ] = useState(false);
|
||||||
const determineIsMobileDevice = () => setIsMobileDevice(matchMedia('(max-width: 991px)').matches);
|
const determineIsMobileDevice = () => setIsMobileDevice(matchMedia('(max-width: 991px)').matches);
|
||||||
const setSelectedVisits = (selectedVisits) => {
|
const setSelectedVisits = (selectedVisits) => {
|
||||||
|
@ -53,9 +54,11 @@ const VisitsStats = ({ processStatsFromVisits, normalizeVisits }, OpenMapModalBt
|
||||||
|
|
||||||
if (selectedBar === newSelectedBar) {
|
if (selectedBar === newSelectedBar) {
|
||||||
setHighlightedVisits([]);
|
setHighlightedVisits([]);
|
||||||
|
setHighlightedLabel(undefined);
|
||||||
selectedBar = undefined;
|
selectedBar = undefined;
|
||||||
} else {
|
} else {
|
||||||
setHighlightedVisits(normalizedVisits.filter(propEq(prop, value)));
|
setHighlightedVisits(normalizedVisits.filter(propEq(prop, value)));
|
||||||
|
setHighlightedLabel(value);
|
||||||
selectedBar = newSelectedBar;
|
selectedBar = newSelectedBar;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -111,7 +114,12 @@ const VisitsStats = ({ processStatsFromVisits, normalizeVisits }, OpenMapModalBt
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12 mt-4">
|
<div className="col-12 mt-4">
|
||||||
<LineChartCard title="Visits during time" visits={visits} highlightedVisits={highlightedVisits} />
|
<LineChartCard
|
||||||
|
title="Visits during time"
|
||||||
|
visits={visits}
|
||||||
|
highlightedVisits={highlightedVisits}
|
||||||
|
highlightedLabel={highlightedLabel}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-xl-4 col-lg-6 mt-4">
|
<div className="col-xl-4 col-lg-6 mt-4">
|
||||||
<GraphCard title="Operating systems" stats={os} />
|
<GraphCard title="Operating systems" stats={os} />
|
||||||
|
@ -125,6 +133,7 @@ const VisitsStats = ({ processStatsFromVisits, normalizeVisits }, OpenMapModalBt
|
||||||
stats={referrers}
|
stats={referrers}
|
||||||
withPagination={false}
|
withPagination={false}
|
||||||
highlightedStats={highlightedVisitsToStats(highlightedVisits, 'referer')}
|
highlightedStats={highlightedVisitsToStats(highlightedVisits, 'referer')}
|
||||||
|
highlightedLabel={highlightedLabel}
|
||||||
sortingItems={{
|
sortingItems={{
|
||||||
name: 'Referrer name',
|
name: 'Referrer name',
|
||||||
amount: 'Visits amount',
|
amount: 'Visits amount',
|
||||||
|
@ -137,6 +146,7 @@ const VisitsStats = ({ processStatsFromVisits, normalizeVisits }, OpenMapModalBt
|
||||||
title="Countries"
|
title="Countries"
|
||||||
stats={countries}
|
stats={countries}
|
||||||
highlightedStats={highlightedVisitsToStats(highlightedVisits, 'country')}
|
highlightedStats={highlightedVisitsToStats(highlightedVisits, 'country')}
|
||||||
|
highlightedLabel={highlightedLabel}
|
||||||
sortingItems={{
|
sortingItems={{
|
||||||
name: 'Country name',
|
name: 'Country name',
|
||||||
amount: 'Visits amount',
|
amount: 'Visits amount',
|
||||||
|
@ -149,6 +159,7 @@ const VisitsStats = ({ processStatsFromVisits, normalizeVisits }, OpenMapModalBt
|
||||||
title="Cities"
|
title="Cities"
|
||||||
stats={cities}
|
stats={cities}
|
||||||
highlightedStats={highlightedVisitsToStats(highlightedVisits, 'city')}
|
highlightedStats={highlightedVisitsToStats(highlightedVisits, 'city')}
|
||||||
|
highlightedLabel={highlightedLabel}
|
||||||
extraHeaderContent={(activeCities) =>
|
extraHeaderContent={(activeCities) =>
|
||||||
mapLocations.length > 0 &&
|
mapLocations.length > 0 &&
|
||||||
<OpenMapModalBtn modalTitle="Cities" locations={mapLocations} activeCities={activeCities} />
|
<OpenMapModalBtn modalTitle="Cities" locations={mapLocations} activeCities={activeCities} />
|
||||||
|
|
|
@ -21,6 +21,7 @@ import Checkbox from '../../utils/Checkbox';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
|
highlightedLabel: PropTypes.string,
|
||||||
visits: PropTypes.arrayOf(VisitType),
|
visits: PropTypes.arrayOf(VisitType),
|
||||||
highlightedVisits: PropTypes.arrayOf(VisitType),
|
highlightedVisits: PropTypes.arrayOf(VisitType),
|
||||||
};
|
};
|
||||||
|
@ -91,7 +92,7 @@ const generateDataset = (stats, label, color) => ({
|
||||||
backgroundColor: color,
|
backgroundColor: color,
|
||||||
});
|
});
|
||||||
|
|
||||||
const LineChartCard = ({ title, visits, highlightedVisits }) => {
|
const LineChartCard = ({ title, visits, highlightedVisits, highlightedLabel = 'Selected' }) => {
|
||||||
const [ step, setStep ] = useState('monthly');
|
const [ step, setStep ] = useState('monthly');
|
||||||
const [ skipNoVisits, toggleSkipNoVisits ] = useToggle(true);
|
const [ skipNoVisits, toggleSkipNoVisits ] = useToggle(true);
|
||||||
|
|
||||||
|
@ -109,7 +110,7 @@ const LineChartCard = ({ title, visits, highlightedVisits }) => {
|
||||||
labels,
|
labels,
|
||||||
datasets: [
|
datasets: [
|
||||||
generateDataset(groupedVisits, 'Visits', '#4696e5'),
|
generateDataset(groupedVisits, 'Visits', '#4696e5'),
|
||||||
highlightedVisits.length > 0 && generateDataset(groupedHighlighted, 'Selected', '#F77F28'),
|
highlightedVisits.length > 0 && generateDataset(groupedHighlighted, highlightedLabel, '#F77F28'),
|
||||||
].filter(Boolean),
|
].filter(Boolean),
|
||||||
};
|
};
|
||||||
const options = {
|
const options = {
|
||||||
|
|
Loading…
Reference in a new issue