poeti8 5 лет назад
Родитель
Сommit
4079d64276

+ 86 - 0
client/components/Charts/Map.tsx

@@ -0,0 +1,86 @@
+import styled from "styled-components";
+import React from "react";
+// import { VectorMap } from "@south-paw/react-vector-maps";
+
+import { Colors } from "../../consts";
+import Tooltip from "../Tooltip";
+import world from "./world.json";
+
+const Svg = styled.svg`
+  path {
+    fill: ${Colors.Map0};
+    stroke: #fff;
+  }
+
+  path.country-6 {
+    fill: ${Colors.Map06};
+    stroke: #fff;
+  }
+  path.country-5 {
+    fill: ${Colors.Map05};
+    stroke: #fff;
+  }
+  path.country-4 {
+    fill: ${Colors.Map04};
+    stroke: #fff;
+  }
+  path.country-3 {
+    fill: ${Colors.Map03};
+    stroke: #fff;
+  }
+  path.country-2 {
+    fill: ${Colors.Map02};
+    stroke: #fff;
+  }
+  path.country-1 {
+    fill: ${Colors.Map01};
+    stroke: #fff;
+  }
+`;
+
+interface Props {
+  data: Array<{ name: string; value: number }>;
+}
+
+const Map = ({ data }) => {
+  const [mostVisits] = data.sort((a, b) => (a > b ? 1 : -1));
+  return (
+    <>
+      {world.layers.map(layer => (
+        <>
+          <Tooltip
+            type="light"
+            effect="float"
+            id={`${layer.id}-tooltip-country`}
+          >
+            {layer.name}:{" "}
+            {data.find(d => d.name.toLowerCase() === layer.id)?.value || 0}
+          </Tooltip>
+        </>
+      ))}
+      <Svg
+        xmlns="http://www.w3.org/2000/svg"
+        aria-label="world map"
+        viewBox={world.viewBox}
+      >
+        {world.layers.map(layer => (
+          <>
+            <path
+              data-tip
+              data-for={`${layer.id}-tooltip-country`}
+              className={`country-${Math.ceil(
+                ((data.find(d => d.name.toLowerCase() === layer.id)?.value ||
+                  0) / mostVisits?.value || 0) * 6
+              )}`}
+              key={layer.id}
+              aria-label={layer.name}
+              d={layer.d}
+            />
+          </>
+        ))}
+      </Svg>
+    </>
+  );
+};
+
+export default Map;

+ 1 - 0
client/components/Charts/index.tsx

@@ -1,3 +1,4 @@
 export { default as Area } from "./Area";
 export { default as Bar } from "./Bar";
 export { default as Pie } from "./Pie";
+export { default as Map } from "./Map";

Разница между файлами не показана из-за своего большого размера
+ 48 - 0
client/components/Charts/world.json


+ 5 - 3
client/components/Tooltip.tsx

@@ -1,12 +1,14 @@
 import ReactTooltip from "react-tooltip";
 import styled from "styled-components";
 
-const Tooltip = styled(ReactTooltip).attrs({
-  effect: "solid"
-})`
+const Tooltip = styled(ReactTooltip)`
   padding: 3px 7px;
   border-radius: 4px;
   font-size: 11px;
 `;
 
+Tooltip.defaultProps = {
+  effect: "solid"
+};
+
 export default Tooltip;

+ 24 - 17
client/consts/consts.ts

@@ -16,32 +16,39 @@ export enum APIv2 {
 }
 
 export enum Colors {
-  Text = "hsl(200, 35%, 25%)",
   Bg = "hsl(206, 12%, 95%)",
-  Spinner = "hsl(200, 15%, 70%)",
-  FeaturesBg = "hsl(230, 15%, 92%)",
-  ExtensionsBg = "hsl(230, 15%, 20%)",
-  Icon = "hsl(200, 35%, 45%)",
-  IconShadow = "hsla(200, 15%, 60%, 0.12)",
+  CheckIcon = "hsl(144, 50%, 60%)",
   CopyIcon = "hsl(144, 40%, 57%)",
   CopyIconBg = "hsl(144, 100%, 96%)",
-  CheckIcon = "hsl(144, 50%, 60%)",
-  TrashIcon = "hsl(0, 100%, 69%)",
-  TrashIconBg = "hsl(0, 100%, 96%)",
-  StopIcon = "hsl(10, 100%, 40%)",
-  StopIconBg = "hsl(10, 100%, 96%)",
-  QrCodeIcon = "hsl(0, 0%, 35%)",
-  QrCodeIconBg = "hsl(0, 0%, 94%)",
+  Divider = "hsl(200, 20%, 92%)",
   EditIcon = "hsl(46, 90%, 50%)",
   EditIconBg = "hsl(46, 100%, 94%)",
+  ExtensionsBg = "hsl(230, 15%, 20%)",
+  FeaturesBg = "hsl(230, 15%, 92%)",
+  Icon = "hsl(200, 35%, 45%)",
+  IconShadow = "hsla(200, 15%, 60%, 0.12)",
+  Map0 = "hsl(200, 15%, 92%)",
+  Map06 = "hsl(261, 46%, 68%)",
+  Map05 = "hsl(261, 46%, 72%)",
+  Map04 = "hsl(261, 46%, 76%)",
+  Map03 = "hsl(261, 46%, 82%)",
+  Map02 = "hsl(261, 46%, 86%)",
+  Map01 = "hsl(261, 46%, 90%)",
   PieIcon = "hsl(260, 100%, 69%)",
   PieIconBg = "hsl(260, 100%, 96%)",
+  QrCodeIcon = "hsl(0, 0%, 35%)",
+  QrCodeIconBg = "hsl(0, 0%, 94%)",
+  Spinner = "hsl(200, 15%, 70%)",
+  StatsLastUpdateText = "hsl(200, 14%, 60%)",
+  StatsTotalUnderline = "hsl(200, 35%, 65%)",
+  StopIcon = "hsl(10, 100%, 40%)",
+  StopIconBg = "hsl(10, 100%, 96%)",
+  TableBorder = "hsl(200, 14%, 90%)",
   TableHeadBg = "hsl(200, 12%, 95%)",
   TableHeadBorder = "hsl(200, 14%, 94%)",
-  TableBorder = "hsl(200, 14%, 90%)",
   TableRowHover = "hsl(200, 14%, 98%)",
   TableShadow = "hsla(200, 20%, 70%, 0.3)",
-  StatsLastUpdateText = "hsl(200, 14%, 60%)",
-  StatsTotalUnderline = "hsl(200, 35%, 65%)",
-  Divider = "hsl(200, 20%, 92%)"
+  Text = "hsl(200, 35%, 25%)",
+  TrashIcon = "hsl(0, 100%, 69%)",
+  TrashIconBg = "hsl(0, 100%, 96%)"
 }

+ 3 - 3
client/pages/stats.tsx

@@ -9,13 +9,13 @@ import Text, { H1, H2, H4, Span } from "../components/Text";
 import { getAxiosConfig, removeProtocol } from "../utils";
 import { Button, NavButton } from "../components/Button";
 import { Col, RowCenterV } from "../components/Layout";
-import { Area, Bar, Pie } from "../components/Charts";
+import { Area, Bar, Pie, Map } from "../components/Charts";
 import PageLoading from "../components/PageLoading";
 import AppWrapper from "../components/AppWrapper";
 import Divider from "../components/Divider";
+import { APIv2, Colors } from "../consts";
 import { useStoreState } from "../store";
 import ALink from "../components/ALink";
-import { APIv2, Colors } from "../consts";
 import Icon from "../components/Icon";
 
 interface Props {
@@ -173,7 +173,7 @@ const StatsPage: NextPage<Props> = ({ id }) => {
                         <H2 mb={3} light>
                           Country.
                         </H2>
-                        <Pie data={stats.stats.country} />
+                        <Map data={stats.stats.country} />
                       </Col>
                       <Col flex="1 1 0">
                         <H2 mb={3} light>

Некоторые файлы не были показаны из-за большого количества измененных файлов