1
0
mirror of https://github.com/kremalicious/umami.git synced 2024-12-24 02:06:19 +01:00
umami/components/common/WorldMap.js

90 lines
2.8 KiB
JavaScript
Raw Normal View History

2020-09-20 10:33:39 +02:00
import React, { useState, useMemo } from 'react';
2020-08-01 12:34:56 +02:00
import ReactTooltip from 'react-tooltip';
2020-09-20 10:33:39 +02:00
import { ComposableMap, Geographies, Geography, ZoomableGroup } from 'react-simple-maps';
2020-08-01 12:34:56 +02:00
import classNames from 'classnames';
import tinycolor from 'tinycolor2';
2020-09-20 10:33:39 +02:00
import useTheme from 'hooks/useTheme';
import { THEME_COLORS } from 'lib/constants';
2020-08-01 12:34:56 +02:00
import styles from './WorldMap.module.css';
2020-10-01 01:27:27 +02:00
import useCountryNames from 'hooks/useCountryNames';
import useLocale from 'hooks/useLocale';
2020-08-01 12:34:56 +02:00
const geoUrl = '/world-110m.json';
2020-09-20 10:33:39 +02:00
export default function WorldMap({ data, className }) {
2020-08-01 12:34:56 +02:00
const [tooltip, setTooltip] = useState();
2020-09-20 10:33:39 +02:00
const [theme] = useTheme();
const colors = useMemo(
() => ({
baseColor: THEME_COLORS[theme].primary,
fillColor: THEME_COLORS[theme].gray100,
strokeColor: THEME_COLORS[theme].primary,
hoverColor: THEME_COLORS[theme].primary,
}),
[theme],
);
2020-10-01 01:27:27 +02:00
const [locale] = useLocale();
const countryNames = useCountryNames(locale);
2020-08-01 12:34:56 +02:00
function getFillColor(code) {
2020-09-20 10:33:39 +02:00
if (code === 'AQ') return;
2020-08-01 12:34:56 +02:00
const country = data?.find(({ x }) => x === code);
2020-09-20 10:33:39 +02:00
if (!country) {
return colors.fillColor;
}
return tinycolor(colors.baseColor)[theme === 'light' ? 'lighten' : 'darken'](
40 * (1.0 - country.z / 100),
);
2020-08-01 12:34:56 +02:00
}
2020-09-20 10:33:39 +02:00
function getOpacity(code) {
return code === 'AQ' ? 0 : 1;
2020-08-01 12:34:56 +02:00
}
2020-10-01 01:27:27 +02:00
function handleHover(code) {
2020-09-20 10:33:39 +02:00
if (code === 'AQ') return;
2020-08-01 12:34:56 +02:00
const country = data?.find(({ x }) => x === code);
2020-10-01 01:27:27 +02:00
setTooltip(`${countryNames[code]}: ${country?.y || 0} visitors`);
2020-08-01 12:34:56 +02:00
}
return (
2020-09-20 10:33:39 +02:00
<div
className={classNames(styles.container, className)}
data-tip=""
data-for="world-map-tooltip"
>
<ComposableMap projection="geoMercator">
2020-08-01 12:34:56 +02:00
<ZoomableGroup zoom={0.8} minZoom={0.7} center={[0, 40]}>
<Geographies geography={geoUrl}>
{({ geographies }) => {
return geographies.map(geo => {
const code = geo.properties.ISO_A2;
return (
<Geography
key={geo.rsmKey}
geography={geo}
fill={getFillColor(code)}
2020-09-20 10:33:39 +02:00
stroke={colors.strokeColor}
opacity={getOpacity(code)}
2020-08-01 12:34:56 +02:00
style={{
default: { outline: 'none' },
2020-09-20 10:33:39 +02:00
hover: { outline: 'none', fill: colors.hoverColor },
2020-08-01 12:34:56 +02:00
pressed: { outline: 'none' },
}}
2020-10-01 01:27:27 +02:00
onMouseOver={() => handleHover(code)}
2020-08-01 12:34:56 +02:00
onMouseOut={() => setTooltip(null)}
/>
);
});
}}
</Geographies>
</ZoomableGroup>
</ComposableMap>
2020-09-20 10:33:39 +02:00
<ReactTooltip id="world-map-tooltip">{tooltip}</ReactTooltip>
2020-08-01 12:34:56 +02:00
</div>
);
}