Skip to content

Commit

Permalink
feat: complete pie chart component
Browse files Browse the repository at this point in the history
  • Loading branch information
yuanyxh committed Sep 24, 2024
1 parent 09f1d83 commit a4cbbf3
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 129 deletions.
93 changes: 0 additions & 93 deletions src/components/Canvas/Canvas.tsx

This file was deleted.

55 changes: 55 additions & 0 deletions src/components/PieChart/PieChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { useEffect, useRef } from 'react';

import { clearCanvas, scaleCanvas } from '@/utils';

export interface PieItemConfig {
value: number;
color: string;
}

export interface IPieChartProps {
radius: number;
data: PieItemConfig[];
}

const PieChart: React.FC<Readonly<IPieChartProps>> = (props) => {
const { radius, data } = props;

const canvasRef = useRef<HTMLCanvasElement>(null);
const ctxRef = useRef<CanvasRenderingContext2D | null>();

useEffect(() => {
if (!ctxRef.current) {
ctxRef.current = scaleCanvas(canvasRef.current!);

clearCanvas(ctxRef.current);
}

const ctx = ctxRef.current;

const circle = Math.PI * 2;

const total = data.reduce((p, c) => p + c.value, 0);

let ratio = 0;
for (let i = 0; i < data.length; i++) {
const sector = data[i];

const nextRatio = circle * (sector.value / total || 0);

ctx.beginPath();
ctx.moveTo(radius, radius);
ctx.arc(radius, radius, radius, ratio, nextRatio);
ctx.fillStyle = sector.color;
ctx.fill();

ratio = nextRatio;
}
}, [radius, data]);

const size = radius * 2;

return <canvas ref={canvasRef} width={size} height={size}></canvas>;
};

export default PieChart;
4 changes: 2 additions & 2 deletions src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export { default as Canvas } from './Canvas/Canvas';
export * from './Canvas/Canvas';
export { default as ContextMenu } from './ContextMenu/ContextMenu';
export { default as Dialog } from './Dialog/Dialog';
export * from './Dialog/Dialog';
export { default as Icon } from './Icon/Icon';
export { default as Image } from './Image/Image';
export { default as Loading } from './Loading/Loading';
export { default as PieChart } from './PieChart/PieChart';
export * from './PieChart/PieChart';
22 changes: 22 additions & 0 deletions src/utils/canvas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export const scaleCanvas = (canvas: HTMLCanvasElement) => {
const ctx = canvas.getContext('2d')!;

const w = canvas.width;
const h = canvas.height;

const ratio = window.devicePixelRatio || 1;
canvas.width = w * ratio;
canvas.height = h * ratio;
canvas.style.width = `${w}px`;
canvas.style.height = `${h}px`;

ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = 'high';
ctx.scale(ratio, ratio);

return ctx;
};

export const clearCanvas = (ctx: CanvasRenderingContext2D) => {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
};
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './canvas.ts';
export * from './error.ts';
export { default as EventEmitter } from './event';
export * from './fullscreen';
Expand Down
52 changes: 18 additions & 34 deletions src/viewer/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import {

import { getStorageUsage } from '@/filehandle/utils/index';

import type { CanvasInstance } from '@/components';
import { Canvas } from '@/components';
import { PieChart } from '@/components';

import styles from './styles/Settings.module.less';

Expand Down Expand Up @@ -217,8 +216,6 @@ function PersistentStorage() {
}

function StorageDetail() {
const drawRef = useRef<CanvasInstance>(null);

const [storage, setStorage] = useState<{
quota: number;
usage: number;
Expand All @@ -244,30 +241,6 @@ function StorageDetail() {
usage: usage / 1000 / 1000,
unUsage: unUsage / 1000 / 1000
});

const usageAngle = Math.PI * 2 * (res.usage / res.quota);
const unUsageAngle = Math.PI * 2 * ((res.quota - res.usage) / res.quota);

const drawEl = drawRef.current!;

const centerX = drawEl.width() / 2;
const centerY = drawEl.height() / 2;

drawEl.arc(centerX, centerY, centerX - 2, 0, Math.PI * 2);
drawEl.strokeStyle('#f0f0f0');
drawEl.stroke();

drawEl.beginPath();
drawEl.moveTo(centerX, centerY);
drawEl.arc(centerX, centerY, centerX - 2, 0, usageAngle);
drawEl.fillStyle('#ff9759');
drawEl.fill();

drawEl.beginPath();
drawEl.moveTo(centerX, centerY);
drawEl.arc(centerX, centerY, centerX - 2, usageAngle, usageAngle + unUsageAngle);
drawEl.fillStyle('white');
drawEl.fill();
})
.catch((err) => {
error((err as Error).message);
Expand All @@ -280,8 +253,19 @@ function StorageDetail() {
<h5 className={styles.subTitle}>网站存储详情</h5>

<div style={{ display: 'flex', gap: '0 30px', marginBlock: 10 }}>
{/* TODO: remove this component and add Pie chart */}
<Canvas ref={drawRef} width={120} height={120} />
<PieChart
radius={60}
data={[
{
value: storage.usage,
color: '#627ad3'
},
{
value: storage.unUsage,
color: '#9eca7f'
}
]}
/>

<div style={{ display: 'flex', flexDirection: 'column', gap: '10px 0' }}>
<div className={styles.line}>
Expand All @@ -293,17 +277,17 @@ function StorageDetail() {
</div>

<div className={styles.line}>
<span className={styles.symbol} style={{ backgroundColor: '#ff9759' }}></span>
<span className={styles.symbol} style={{ backgroundColor: '#627ad3' }}></span>

<Text type="secondary">已用存储</Text>
<Text type="secondary">已用存储量</Text>

<Text>{storage.usage.toFixed(3)} MB</Text>
</div>

<div className={styles.line}>
<span className={styles.symbol} style={{ backgroundColor: '#601986' }}></span>
<span className={styles.symbol} style={{ backgroundColor: '#9eca7f' }}></span>

<Text type="secondary">剩余可用</Text>
<Text type="secondary">剩余可用量</Text>
<Text>{storage.unUsage.toFixed(3)} MB</Text>
</div>
</div>
Expand Down

0 comments on commit a4cbbf3

Please sign in to comment.