From 36c6d87cd39b7f91fe80f44336dce8eb06d17afe Mon Sep 17 00:00:00 2001 From: HF Date: Mon, 26 Sep 2022 01:21:09 +0200 Subject: [PATCH] test chart drawing --- package-lock.json | 27 +++++ package.json | 2 + src/components/Rankings.jsx | 194 +++++++++++++++++++++++++++++++++++- src/store/actions/fetch.js | 2 +- 4 files changed, 223 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e6cf2b4..fd38954 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "dependencies": { "bcrypt": "^5.0.1", + "chart.js": "^3.9.1", "compression": "^1.7.3", "cookie": "^0.5.0", "core-js": "^3.23.4", @@ -30,6 +31,7 @@ "passport-vkontakte": "^0.5.0", "ppfun-captcha": "^1.6.6", "react": "^18.2.0", + "react-chartjs-2": "^4.3.1", "react-dom": "^18.2.0", "react-icons": "^4.3.1", "react-redux": "^8.0.2", @@ -3655,6 +3657,11 @@ "node": ">=0.8.0" } }, + "node_modules/chart.js": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz", + "integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==" + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -8759,6 +8766,15 @@ "node": ">=0.10.0" } }, + "node_modules/react-chartjs-2": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-4.3.1.tgz", + "integrity": "sha512-5i3mjP6tU7QSn0jvb8I4hudTzHJqS8l00ORJnVwI2sYu0ihpj83Lv2YzfxunfxTZkscKvZu2F2w9LkwNBhj6xA==", + "peerDependencies": { + "chart.js": "^3.5.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -13780,6 +13796,11 @@ } } }, + "chart.js": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz", + "integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==" + }, "chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -17619,6 +17640,12 @@ "loose-envify": "^1.1.0" } }, + "react-chartjs-2": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-4.3.1.tgz", + "integrity": "sha512-5i3mjP6tU7QSn0jvb8I4hudTzHJqS8l00ORJnVwI2sYu0ihpj83Lv2YzfxunfxTZkscKvZu2F2w9LkwNBhj6xA==", + "requires": {} + }, "react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", diff --git a/package.json b/package.json index 2618cf2..818bf82 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ ], "dependencies": { "bcrypt": "^5.0.1", + "chart.js": "^3.9.1", "compression": "^1.7.3", "cookie": "^0.5.0", "core-js": "^3.23.4", @@ -44,6 +45,7 @@ "passport-vkontakte": "^0.5.0", "ppfun-captcha": "^1.6.6", "react": "^18.2.0", + "react-chartjs-2": "^4.3.1", "react-dom": "^18.2.0", "react-icons": "^4.3.1", "react-redux": "^8.0.2", diff --git a/src/components/Rankings.jsx b/src/components/Rankings.jsx index 84e2dab..e114985 100644 --- a/src/components/Rankings.jsx +++ b/src/components/Rankings.jsx @@ -4,11 +4,114 @@ /* eslint-disable max-len */ -import React, { useState } from 'react'; +import React, { useState, useMemo } from 'react'; import { shallowEqual, useSelector } from 'react-redux'; import { t } from 'ttag'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend, + LineController, +} from 'chart.js'; +import { Line } from 'react-chartjs-2'; import { selectStats } from '../store/selectors/ranks'; +import { colorFromText } from '../core/utils'; + +ChartJS.register( + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend, + LineController, +); + +const options = { + responsive: true, + aspectRatio: 1.2, + color: '#e6e6e6', + scales: { + x: { + grid: { + drawBorder: false, + color: '#656565', + }, + ticks: { + color: '#e6e6e6', + }, + }, + y: { + grid: { + drawBorder: false, + color: '#656565', + }, + ticks: { + color: '#e6e6e6', + }, + }, + }, + interaction: { + mode: 'index', + intersect: false, + }, + plugins: { + legend: { + position: 'top', + }, + title: { + display: true, + color: '#e6e6e6', + text: 'Top 10 Countries [pxls / day]', + }, + }, +}; + +const onlineStatsOptions = { + responsive: true, + color: '#e6e6e6', + scales: { + x: { + grid: { + drawBorder: false, + color: '#656565', + }, + ticks: { + color: '#e6e6e6', + }, + }, + y: { + grid: { + drawBorder: false, + color: '#656565', + }, + ticks: { + color: '#e6e6e6', + }, + }, + }, + interaction: { + mode: 'index', + intersect: false, + }, + plugins: { + legend: { + display: false, + }, + title: { + display: true, + color: '#e6e6e6', + text: 'Players Online per full hour', + }, + }, +}; const Rankings = () => { @@ -23,6 +126,80 @@ const Rankings = () => { histStats, ] = useSelector(selectStats, shallowEqual); + const cHistData = useMemo(() => { + if (area !== 'charts') { + return null; + } + const dataPerCountry = {}; + const labels = []; + let ts = Date.now(); + let c = cHistStats.length; + while (c) { + const dAmount = cHistStats.length - c; + c -= 1; + // x label + const date = new Date(ts); + labels.unshift(`${date.getUTCMonth() + 1} / ${date.getUTCDate()}`); + ts -= 1000 * 3600 * 24; + // y data per country + const dailyRanks = cHistStats[c]; + for (let i = 0; i < dailyRanks.length; i += 1) { + const { cc, px } = dailyRanks[i]; + if (!dataPerCountry[cc]) { + dataPerCountry[cc] = []; + } + const countryDat = dataPerCountry[cc]; + while (countryDat.length < dAmount) { + countryDat.push(null); + } + countryDat.push(px); + } + } + console.log(dataPerCountry); + const countries = Object.keys(dataPerCountry); + const datasets = countries.map((cc) => { + const color = colorFromText(`${cc}${cc}${cc}${cc}${cc}`); + return { + label: cc, + data: dataPerCountry[cc], + borderColor: color, + backgroundColor: color, + }; + }); + return { + labels, + datasets, + }; + }, [area, cHistStats]); + + const onlineData = useMemo(() => { + if (area !== 'charts') { + return null; + } + const labels = []; + const data = []; + let ts = Date.now(); + let c = onlineStats.length; + while (c) { + c -= 1; + const date = new Date(ts); + const hours = date.getHours(); + const key = hours || `${date.getMonth() + 1} / ${date.getDate()}`; + labels.unshift(String(key)); + ts -= 1000 * 3600; + data.push(onlineStats[c]); + } + return { + labels, + datasets: [{ + label: 'Players', + data, + borderColor: '#3fadda', + backgroundColor: '#3fadda', + }], + }; + }, [area, onlineStats]); + return ( <>
@@ -61,6 +238,15 @@ const Rankings = () => { } onClick={() => setArea('countries')} >{t`Countries Today`} + + setArea('charts')} + >{t`Chart`}
{(['total', 'today', 'yesterday', 'countries'].includes(area)) && ( {
)} + {(area === 'charts') && ( + <> + + + + )}

{t`Ranking updates every 5 min. Daily rankings get reset at midnight UTC.`}

diff --git a/src/store/actions/fetch.js b/src/store/actions/fetch.js index ac1166f..1d5a219 100644 --- a/src/store/actions/fetch.js +++ b/src/store/actions/fetch.js @@ -324,7 +324,7 @@ export function requestDeleteAccount(password) { export function requestRankings() { return makeAPIGETRequest( - '/ranking', + 'https://pixelplanet.fun/ranking', false, ); }