mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 09:30:31 +03:00
Merge pull request #64 from acelaya/bugfix/graphs-height
Bugfix/graphs height
This commit is contained in:
commit
169c69df2c
4 changed files with 82 additions and 46 deletions
|
@ -8,15 +8,18 @@ const propTypes = {
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
isBarChart: PropTypes.bool,
|
isBarChart: PropTypes.bool,
|
||||||
stats: PropTypes.object,
|
stats: PropTypes.object,
|
||||||
|
matchMedia: PropTypes.func,
|
||||||
|
};
|
||||||
|
const defaultProps = {
|
||||||
|
matchMedia: global.window ? global.window.matchMedia : () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export function GraphCard({ title, isBarChart, stats }) {
|
const generateGraphData = (title, isBarChart, labels, data) => ({
|
||||||
const generateGraphData = (stats) => ({
|
labels,
|
||||||
labels: keys(stats),
|
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
title,
|
title,
|
||||||
data: values(stats),
|
data,
|
||||||
backgroundColor: isBarChart ? 'rgba(70, 150, 229, 0.4)' : [
|
backgroundColor: isBarChart ? 'rgba(70, 150, 229, 0.4)' : [
|
||||||
'#97BBCD',
|
'#97BBCD',
|
||||||
'#DCDCDC',
|
'#DCDCDC',
|
||||||
|
@ -31,9 +34,39 @@ export function GraphCard({ title, isBarChart, stats }) {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
const renderGraph = () => {
|
|
||||||
|
const determineGraphAspectRatio = (barsCount, isBarChart, matchMedia) => {
|
||||||
|
const determineAspectRationModifier = () => {
|
||||||
|
switch (true) {
|
||||||
|
case matchMedia('(max-width: 1200px)').matches:
|
||||||
|
return 1.5; // eslint-disable-line no-magic-numbers
|
||||||
|
case matchMedia('(max-width: 992px)').matches:
|
||||||
|
return 1.75; // eslint-disable-line no-magic-numbers
|
||||||
|
case matchMedia('(max-width: 768px)').matches:
|
||||||
|
return 2; // eslint-disable-line no-magic-numbers
|
||||||
|
case matchMedia('(max-width: 576px)').matches:
|
||||||
|
return 2.25; // eslint-disable-line no-magic-numbers
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const MAX_BARS_WITHOUT_HEIGHT = 20;
|
||||||
|
const DEFAULT_ASPECT_RATION = 2;
|
||||||
|
const shouldCalculateAspectRatio = isBarChart && barsCount > MAX_BARS_WITHOUT_HEIGHT;
|
||||||
|
|
||||||
|
return shouldCalculateAspectRatio
|
||||||
|
? MAX_BARS_WITHOUT_HEIGHT / determineAspectRationModifier() * DEFAULT_ASPECT_RATION / barsCount
|
||||||
|
: DEFAULT_ASPECT_RATION;
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderGraph = (title, isBarChart, stats, matchMedia) => {
|
||||||
const Component = isBarChart ? HorizontalBar : Doughnut;
|
const Component = isBarChart ? HorizontalBar : Doughnut;
|
||||||
|
const labels = keys(stats);
|
||||||
|
const data = values(stats);
|
||||||
|
const aspectRatio = determineGraphAspectRatio(labels.length, isBarChart, matchMedia);
|
||||||
const options = {
|
const options = {
|
||||||
|
aspectRatio,
|
||||||
legend: isBarChart ? { display: false } : { position: 'right' },
|
legend: isBarChart ? { display: false } : { position: 'right' },
|
||||||
scales: isBarChart ? {
|
scales: isBarChart ? {
|
||||||
xAxes: [
|
xAxes: [
|
||||||
|
@ -44,15 +77,17 @@ export function GraphCard({ title, isBarChart, stats }) {
|
||||||
} : null,
|
} : null,
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Component data={generateGraphData(stats)} options={options} />;
|
return <Component data={generateGraphData(title, isBarChart, labels, data)} options={options} height={null} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
const GraphCard = ({ title, isBarChart, stats, matchMedia }) => (
|
||||||
<Card className="mt-4">
|
<Card className="mt-4">
|
||||||
<CardHeader>{title}</CardHeader>
|
<CardHeader>{title}</CardHeader>
|
||||||
<CardBody>{renderGraph()}</CardBody>
|
<CardBody>{renderGraph(title, isBarChart, stats, matchMedia)}</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
GraphCard.propTypes = propTypes;
|
GraphCard.propTypes = propTypes;
|
||||||
|
GraphCard.defaultProps = defaultProps;
|
||||||
|
|
||||||
|
export default GraphCard;
|
||||||
|
|
|
@ -15,7 +15,7 @@ import {
|
||||||
processReferrersStats,
|
processReferrersStats,
|
||||||
} from './services/VisitsParser';
|
} from './services/VisitsParser';
|
||||||
import { VisitsHeader } from './VisitsHeader';
|
import { VisitsHeader } from './VisitsHeader';
|
||||||
import { GraphCard } from './GraphCard';
|
import GraphCard from './GraphCard';
|
||||||
import { getShortUrlDetail, shortUrlDetailType } from './reducers/shortUrlDetail';
|
import { getShortUrlDetail, shortUrlDetailType } from './reducers/shortUrlDetail';
|
||||||
import './ShortUrlVisits.scss';
|
import './ShortUrlVisits.scss';
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
import { Doughnut, HorizontalBar } from 'react-chartjs-2';
|
import { Doughnut, HorizontalBar } from 'react-chartjs-2';
|
||||||
import { keys, values } from 'ramda';
|
import { keys, values } from 'ramda';
|
||||||
import { GraphCard } from '../../src/visits/GraphCard';
|
import GraphCard from '../../src/visits/GraphCard';
|
||||||
|
|
||||||
describe('<GraphCard />', () => {
|
describe('<GraphCard />', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
|
@ -10,6 +10,7 @@ describe('<GraphCard />', () => {
|
||||||
foo: 123,
|
foo: 123,
|
||||||
bar: 456,
|
bar: 456,
|
||||||
};
|
};
|
||||||
|
const matchMedia = () => ({ matches: false });
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
if (wrapper) {
|
if (wrapper) {
|
||||||
|
@ -18,7 +19,7 @@ describe('<GraphCard />', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders Doughnut when is not a bar chart', () => {
|
it('renders Doughnut when is not a bar chart', () => {
|
||||||
wrapper = shallow(<GraphCard title="The chart" stats={stats} />);
|
wrapper = shallow(<GraphCard matchMedia={matchMedia} title="The chart" stats={stats} />);
|
||||||
const doughnut = wrapper.find(Doughnut);
|
const doughnut = wrapper.find(Doughnut);
|
||||||
const horizontal = wrapper.find(HorizontalBar);
|
const horizontal = wrapper.find(HorizontalBar);
|
||||||
|
|
||||||
|
@ -46,7 +47,7 @@ describe('<GraphCard />', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders HorizontalBar when is not a bar chart', () => {
|
it('renders HorizontalBar when is not a bar chart', () => {
|
||||||
wrapper = shallow(<GraphCard isBarChart title="The chart" stats={stats} />);
|
wrapper = shallow(<GraphCard matchMedia={matchMedia} isBarChart title="The chart" stats={stats} />);
|
||||||
const doughnut = wrapper.find(Doughnut);
|
const doughnut = wrapper.find(Doughnut);
|
||||||
const horizontal = wrapper.find(HorizontalBar);
|
const horizontal = wrapper.find(HorizontalBar);
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { Card } from 'reactstrap';
|
||||||
import * as sinon from 'sinon';
|
import * as sinon from 'sinon';
|
||||||
import { ShortUrlsVisitsComponent as ShortUrlsVisits } from '../../src/visits/ShortUrlVisits';
|
import { ShortUrlsVisitsComponent as ShortUrlsVisits } from '../../src/visits/ShortUrlVisits';
|
||||||
import MutedMessage from '../../src/utils/MuttedMessage';
|
import MutedMessage from '../../src/utils/MuttedMessage';
|
||||||
import { GraphCard } from '../../src/visits/GraphCard';
|
import GraphCard from '../../src/visits/GraphCard';
|
||||||
import DateInput from '../../src/common/DateInput';
|
import DateInput from '../../src/common/DateInput';
|
||||||
|
|
||||||
describe('<ShortUrlVisits />', () => {
|
describe('<ShortUrlVisits />', () => {
|
||||||
|
|
Loading…
Reference in a new issue