chore: chart

feat/progress-chart
Arik Chakma 1 year ago
parent ff0e10c16c
commit 3771326cd8
  1. 2
      package.json
  2. 23
      pnpm-lock.yaml
  3. 90
      src/components/Activity/ActivityPage.tsx

@ -28,6 +28,8 @@
"@nanostores/preact": "^0.5.0",
"astro": "^2.6.3",
"astro-compress": "^1.1.47",
"chart.js": "^4.3.0",
"chartjs-plugin-datalabels": "^2.2.0",
"jose": "^4.14.4",
"js-cookie": "^3.0.5",
"nanostores": "^0.9.1",

@ -11,6 +11,8 @@ specifiers:
'@types/js-cookie': ^3.0.3
astro: ^2.6.3
astro-compress: ^1.1.47
chart.js: ^4.3.0
chartjs-plugin-datalabels: ^2.2.0
csv-parser: ^3.0.0
gh-pages: ^5.0.0
jose: ^4.14.4
@ -37,6 +39,8 @@ dependencies:
'@nanostores/preact': 0.5.0_m2wbkjxz7237icvaxqi7ignbgm
astro: 2.6.4
astro-compress: 1.1.47
chart.js: 4.3.0
chartjs-plugin-datalabels: 2.2.0_chart.js@4.3.0
jose: 4.14.4
js-cookie: 3.0.5
nanostores: 0.9.1
@ -696,6 +700,10 @@ packages:
'@jridgewell/resolve-uri': 3.1.0
'@jridgewell/sourcemap-codec': 1.4.14
/@kurkle/color/0.3.2:
resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==}
dev: false
/@ljharb/has-package-exports-patterns/0.0.2:
resolution: {integrity: sha512-4/RWEeXDO6bocPONheFe6gX/oQdP/bEpv0oL4HqjPP5DCenBSt0mHgahppY49N0CpsaqffdwPq+TlX9CYOq2Dw==}
dev: false
@ -1553,6 +1561,21 @@ packages:
resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==}
dev: false
/chart.js/4.3.0:
resolution: {integrity: sha512-ynG0E79xGfMaV2xAHdbhwiPLczxnNNnasrmPEXriXsPJGjmhOBYzFVEsB65w2qMDz+CaBJJuJD0inE/ab/h36g==}
engines: {pnpm: '>=7'}
dependencies:
'@kurkle/color': 0.3.2
dev: false
/chartjs-plugin-datalabels/2.2.0_chart.js@4.3.0:
resolution: {integrity: sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==}
peerDependencies:
chart.js: '>=3.0.0'
dependencies:
chart.js: 4.3.0
dev: false
/chokidar/3.5.3:
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
engines: {node: '>= 8.10.0'}

@ -1,4 +1,6 @@
import { useEffect, useState } from 'preact/hooks';
import { useEffect, useMemo, useRef, useState } from 'preact/hooks';
import { Chart as ChartJS, ChartTypeRegistry } from 'chart.js/auto';
import ChartDataLabels from 'chartjs-plugin-datalabels'
import { httpGet } from '../../lib/http';
import { ActivityCounters } from './ActivityCounters';
import { ResourceProgress } from './ResourceProgress';
@ -50,8 +52,15 @@ type ActivityResponse = {
}[];
};
type ChartLegendItem = {
title: string;
color: string;
}
export function ActivityPage() {
const canvasRef = useRef<HTMLCanvasElement>(null);
const [activity, setActivity] = useState<ActivityResponse>();
const [chartLegend, setChartLegend] = useState<ChartLegendItem[]>([]);
const [isLoading, setIsLoading] = useState(true);
async function loadActivity() {
@ -83,6 +92,56 @@ export function ActivityPage() {
return null;
}
const chartData = useMemo(() => {
return {
labels: [...learningRoadmaps, ...learningBestPractices].map(resource => resource.title),
data: [...learningRoadmaps, ...learningBestPractices].map(resource => resource.done)
}
}, [activity])
useEffect(() => {
let chart: ChartJS<"pie", number[], string> | null = null
const ctx = canvasRef.current?.getContext('2d');
if (!ctx) {
return;
}
if (!chart) {
chart = new ChartJS(ctx, {
type: 'pie',
data: {
labels: chartData.labels,
datasets: [{
data: chartData.data,
hoverOffset: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: {
display: false
},
}
}
});
}
const legendItems = chart?.legend?.legendItems || []
const enrichedLegendItems = legendItems.map((item, index) => {
return {
title: item.text,
color: item.fillStyle?.toString() || ''
}
})
console.log(enrichedLegendItems)
setChartLegend(enrichedLegendItems)
return () => {
chart?.destroy();
};
}, [chartData]);
return (
<>
<ActivityCounters
@ -91,6 +150,35 @@ export function ActivityPage() {
streak={activity?.streak || { count: 0 }}
/>
<div className="mx-0 px-0 py-5 md:-mx-10 md:px-8 md:py-8">
<div className="bg-white shadow-lg rounded-2xl p-8">
<h2 className="font-medium">Knowledge Structure</h2>
<div className="grid grid-cols-4 gap-5 mt-6">
<div className="w-full aspect-square flex items-center justify-center h-full">
<canvas
ref={canvasRef}
/>
</div>
<div className="col-span-3">
<div className="flex flex-col gap-1.5 justify-center h-full">
{chartLegend.map((data) => (
<div className="flex items-center gap-2">
<div
style={{
background: `${data.color}`
}}
className="w-3 h-3 rounded-full"
/>
<span className="text-xs text-gray-500">{data.title}</span>
</div>
))}
</div>
</div>
</div>
</div>
</div>
<div class="mx-0 px-0 py-5 md:-mx-10 md:px-8 md:py-8">
{learningRoadmaps.length === 0 &&
learningBestPractices.length === 0 && <EmptyActivity />}

Loading…
Cancel
Save