diff --git a/.eslintrc b/.eslintrc
index 7ac3f4ec..b14ea6b0 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -26,6 +26,7 @@
"no-console": "warn",
"template-curly-spacing": ["error", "never"],
"no-warning-comments": "off",
+ "no-magic-numbers": "off",
"no-undefined": "off",
"indent": ["error", 2, {
"SwitchCase": 1
diff --git a/package.json b/package.json
index e9c6f15e..457521b4 100644
--- a/package.json
+++ b/package.json
@@ -38,13 +38,13 @@
"prop-types": "^15.6.2",
"qs": "^6.5.2",
"ramda": "^0.26.1",
- "react": "^16.7.0",
+ "react": "^16.8.0",
"react-autosuggest": "^9.4.0",
"react-chartjs-2": "^2.7.4",
"react-color": "^2.14.1",
"react-copy-to-clipboard": "^5.0.1",
"react-datepicker": "~1.5.0",
- "react-dom": "^16.7.0",
+ "react-dom": "^16.8.0",
"react-leaflet": "^2.2.1",
"react-moment": "^0.7.6",
"react-redux": "^5.0.7",
diff --git a/src/utils/utils.js b/src/utils/utils.js
index 60f33c16..a49cc604 100644
--- a/src/utils/utils.js
+++ b/src/utils/utils.js
@@ -4,7 +4,9 @@ import marker from 'leaflet/dist/images/marker-icon.png';
import markerShadow from 'leaflet/dist/images/marker-shadow.png';
import { range } from 'ramda';
+const TEN_ROUNDING_NUMBER = 10;
const DEFAULT_TIMEOUT_DELAY = 2000;
+const { ceil } = Math;
export const stateFlagTimeout = (setTimeout) => (
setState,
@@ -40,3 +42,5 @@ export const fixLeafletIcons = () => {
};
export const rangeOf = (size, mappingFn, startAt = 1) => range(startAt, size + 1).map(mappingFn);
+
+export const roundTen = (number) => ceil(number / TEN_ROUNDING_NUMBER) * TEN_ROUNDING_NUMBER;
diff --git a/src/visits/GraphCard.js b/src/visits/GraphCard.js
index 2cbbda75..44facee7 100644
--- a/src/visits/GraphCard.js
+++ b/src/visits/GraphCard.js
@@ -1,18 +1,16 @@
-import { Card, CardHeader, CardBody } from 'reactstrap';
+import { Card, CardHeader, CardBody, CardFooter } from 'reactstrap';
import { Doughnut, HorizontalBar } from 'react-chartjs-2';
import PropTypes from 'prop-types';
import React from 'react';
import { keys, values } from 'ramda';
const propTypes = {
- title: PropTypes.string,
- children: PropTypes.node,
+ title: PropTypes.oneOfType([ PropTypes.string, PropTypes.node ]),
+ footer: PropTypes.oneOfType([ PropTypes.string, PropTypes.node ]),
isBarChart: PropTypes.bool,
stats: PropTypes.object,
- matchMedia: PropTypes.func,
-};
-const defaultProps = {
- matchMedia: global.window ? global.window.matchMedia : () => {},
+ max: PropTypes.number,
+ redraw: PropTypes.bool,
};
const generateGraphData = (title, isBarChart, labels, data) => ({
@@ -36,62 +34,42 @@ const generateGraphData = (title, isBarChart, labels, data) => ({
],
});
-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 dropLabelIfHidden = (label) => label.startsWith('hidden') ? '' : label;
- 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 renderGraph = (title, isBarChart, stats, max, redraw) => {
const Component = isBarChart ? HorizontalBar : Doughnut;
- const labels = keys(stats);
+ const labels = keys(stats).map(dropLabelIfHidden);
const data = values(stats);
- const aspectRatio = determineGraphAspectRatio(labels.length, isBarChart, matchMedia);
const options = {
- aspectRatio,
legend: isBarChart ? { display: false } : { position: 'right' },
scales: isBarChart ? {
xAxes: [
{
- ticks: { beginAtZero: true },
+ ticks: { beginAtZero: true, max },
},
],
} : null,
tooltips: {
intersect: !isBarChart,
+
+ // Do not show tooltip on items with empty label when in a bar chart
+ filter: ({ yLabel }) => !isBarChart || yLabel !== '',
},
};
+ const graphData = generateGraphData(title, isBarChart, labels, data);
+ const height = labels.length < 20 ? null : labels.length * 8;
- return