Add Species Pie Chart
This commit is contained in:
parent
ac7fb85535
commit
e80a54eb71
4 changed files with 205 additions and 1 deletions
87
app/api/species/route.ts
Normal file
87
app/api/species/route.ts
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
import { google } from 'googleapis';
|
||||||
|
import { NextResponse } from 'next/server';
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
const target = ['https://www.googleapis.com/auth/spreadsheets.readonly'];
|
||||||
|
const jwt = new google.auth.JWT(
|
||||||
|
process.env.API_EMAIL,
|
||||||
|
undefined,
|
||||||
|
(process.env.API_KEY || '').replace(/\\n/g, '\n'),
|
||||||
|
target
|
||||||
|
);
|
||||||
|
|
||||||
|
const sheets = google.sheets({ version: 'v4', auth: jwt });
|
||||||
|
const response = await sheets.spreadsheets.get({
|
||||||
|
spreadsheetId: process.env.SPREADSHEET_ID,
|
||||||
|
ranges: [
|
||||||
|
'Overview!B22:R22',
|
||||||
|
'Overview!B23:S23',
|
||||||
|
'Overview!B24:R24',
|
||||||
|
'Overview!B25:S25',
|
||||||
|
'Overview!B26:S26',
|
||||||
|
'Overview!B27:Q27',
|
||||||
|
'Overview!B28:Q28',
|
||||||
|
'Overview!B29:Q29',
|
||||||
|
'Overview!B30:P30',
|
||||||
|
'Overview!B31:P31',
|
||||||
|
'Overview!B32:P32',
|
||||||
|
'Overview!B33:P33',
|
||||||
|
'Overview!B34:O34',
|
||||||
|
],
|
||||||
|
includeGridData: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const sheetsData = response.data.sheets;
|
||||||
|
if (sheetsData?.length) {
|
||||||
|
|
||||||
|
const rows = sheetsData[0].data;
|
||||||
|
const merges = sheetsData[0].merges;
|
||||||
|
if (rows?.length) {
|
||||||
|
let rowLenghts = new Array<any>;
|
||||||
|
if (rows[0].rowData?.length) {
|
||||||
|
rowLenghts = rows[0].rowData;
|
||||||
|
}
|
||||||
|
let speciesArray = new Array<number>;
|
||||||
|
|
||||||
|
for (let i = 0; i < rows.length; i++) {
|
||||||
|
let sRows = rows[i].rowData;
|
||||||
|
if (sRows?.length) {
|
||||||
|
let data = sRows[0].values;
|
||||||
|
if (data?.length) {
|
||||||
|
speciesArray[i] = 0;
|
||||||
|
for (let j = 0; j < data.length; j++) {
|
||||||
|
switch (data[j].userEnteredValue?.stringValue) {
|
||||||
|
case ("Taken"): {
|
||||||
|
speciesArray[i] = speciesArray[i] + 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ("A"):
|
||||||
|
case ("B"):
|
||||||
|
case ("-"): {
|
||||||
|
speciesArray[i] = speciesArray[i] + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (merges?.length) {
|
||||||
|
merges.forEach(merge => {
|
||||||
|
if (merge.startRowIndex && merge.startRowIndex - 21 == i) {
|
||||||
|
speciesArray[i] = speciesArray[i] + 2;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
speciesArray[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.json({ speciesArray });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return NextResponse.json({ status: 500 })
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,17 +3,19 @@ import { useState } from 'react';
|
||||||
import {RadarChart} from '../components/charts/radar'
|
import {RadarChart} from '../components/charts/radar'
|
||||||
import {EmpireStats} from '../components/tables/empires'
|
import {EmpireStats} from '../components/tables/empires'
|
||||||
import { Checkbox } from '@nextui-org/react';
|
import { Checkbox } from '@nextui-org/react';
|
||||||
|
import { PopChart } from '@/components/charts/pops';
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const [weighted, setWeighted] = useState(true);
|
const [weighted, setWeighted] = useState(true);
|
||||||
return (
|
return (
|
||||||
<main className="flex min-h-screen flex-row items-center">
|
<main className="flex min-h-screen flex-row items-center">
|
||||||
<div className='flex flex-row min-h-screen'>
|
<div className='flex flex-row h-screen'>
|
||||||
<RadarChart weighted={weighted}/>
|
<RadarChart weighted={weighted}/>
|
||||||
<div className='flex flex-col justify-around'>
|
<div className='flex flex-col justify-around'>
|
||||||
<EmpireStats />
|
<EmpireStats />
|
||||||
<Checkbox labelColor="primary" defaultSelected={weighted} onChange={() => setWeighted(!weighted)}>Weighted Ethics</Checkbox>
|
<Checkbox labelColor="primary" defaultSelected={weighted} onChange={() => setWeighted(!weighted)}>Weighted Ethics</Checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
<PopChart></PopChart>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
100
components/charts/pops.tsx
Normal file
100
components/charts/pops.tsx
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import useSWR from "swr";
|
||||||
|
import { Chart as ChartJS, registerables } from 'chart.js';
|
||||||
|
import { Pie } from "react-chartjs-2";
|
||||||
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
||||||
|
import { Species } from '../../types/stellaris';
|
||||||
|
|
||||||
|
const fetcher = async (url:any) => await fetch(url).then((res) => res.json());
|
||||||
|
|
||||||
|
export const PopChart = () => {
|
||||||
|
const {data: tmpData} = useSWR('/api/species',fetcher);
|
||||||
|
|
||||||
|
let data;
|
||||||
|
if (tmpData) {
|
||||||
|
let sData: Array<number> = tmpData.speciesArray
|
||||||
|
data = {
|
||||||
|
labels: sData.map((_elem, idx) => {
|
||||||
|
return Species[idx];
|
||||||
|
}),
|
||||||
|
datasets: [{
|
||||||
|
label: 'Portrait Picks',
|
||||||
|
data: sData,
|
||||||
|
backgroundColor: [
|
||||||
|
'rgb(255, 200, 200)',
|
||||||
|
'rgb(88, 47, 0)',
|
||||||
|
'rgb(255, 205, 86)',
|
||||||
|
'rgb(255, 255, 255)',
|
||||||
|
'rgb(228, 120, 25)',
|
||||||
|
'rgb(0, 247, 255)',
|
||||||
|
'rgb(252, 1, 197)',
|
||||||
|
'rgb(120, 205, 120)',
|
||||||
|
'rgb(255, 60, 60)',
|
||||||
|
'rgb(120, 60, 120)',
|
||||||
|
'rgb(54, 162, 235)',
|
||||||
|
'rgb(0, 255, 60)',
|
||||||
|
'rgb(120, 120, 120)'
|
||||||
|
],
|
||||||
|
hoverOffset: 4
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data = {
|
||||||
|
labels: [],
|
||||||
|
datasets: [{
|
||||||
|
data: [],
|
||||||
|
fill: true,
|
||||||
|
backgroundColor: '#254A6FAA',
|
||||||
|
borderColor: '#356A9F',
|
||||||
|
radius: 3
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
type: 'PIE',
|
||||||
|
data: data,
|
||||||
|
options: {
|
||||||
|
plugins: {
|
||||||
|
tooltip: {
|
||||||
|
callbacks: {
|
||||||
|
label: function(ctx: any) {
|
||||||
|
let sum = 0;
|
||||||
|
ctx.dataset.data.map((elem: number) => {
|
||||||
|
sum = sum + Number(elem)
|
||||||
|
});
|
||||||
|
return (ctx.dataset.data[ctx.dataIndex]*100/sum).toFixed(1) + "% | " + ctx.dataset.data[ctx.dataIndex] + " / " + sum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
display: true
|
||||||
|
},
|
||||||
|
datalabels: {
|
||||||
|
formatter: (value: any, context: any) => {
|
||||||
|
if (value > 0) {
|
||||||
|
return Species[context.dataIndex];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
anchor: 'center',
|
||||||
|
align: 'end',
|
||||||
|
color: 'black'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
ChartJS.register( ...registerables, ChartDataLabels )
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="chart-container h-1/2 aspect-square p-2">
|
||||||
|
<Pie {...config} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -108,3 +108,18 @@ export enum Scale {
|
||||||
fanatic = 2
|
fanatic = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum Species {
|
||||||
|
Humanoid = 0,
|
||||||
|
Mammalian = 1,
|
||||||
|
Reptilian = 2,
|
||||||
|
Avian = 3,
|
||||||
|
Arthropod = 4,
|
||||||
|
Molluscoid = 5,
|
||||||
|
Fungoid = 6,
|
||||||
|
Plantoid = 7,
|
||||||
|
Lithoid = 8,
|
||||||
|
Necroid = 9,
|
||||||
|
Aquatic = 10,
|
||||||
|
Toxoid = 11,
|
||||||
|
Machine = 12
|
||||||
|
}
|
||||||
|
|
Reference in a new issue