Move pie chart labels to middle
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
import { useQuery } from "@tanstack/react-query"
|
import { useQuery } from "@tanstack/react-query"
|
||||||
import { CardHeader, CardTitle, CardContent } from "@/components/ui/card"
|
import { CardHeader, CardTitle, CardContent } from "@/components/ui/card"
|
||||||
import { PieChart, Pie, ResponsiveContainer, Cell, Tooltip } from "recharts"
|
import { PieChart, Pie, ResponsiveContainer, Cell, Tooltip, Sector } from "recharts"
|
||||||
import config from "@/config"
|
import config from "@/config"
|
||||||
import { formatCurrency } from "@/lib/utils"
|
import { formatCurrency } from "@/lib/utils"
|
||||||
import { ClipboardList, AlertCircle, Layers, DollarSign, ShoppingCart } from "lucide-react" // Importing icons
|
import { ClipboardList, AlertCircle, Layers, DollarSign, ShoppingCart } from "lucide-react" // Importing icons
|
||||||
|
import { useState } from "react"
|
||||||
|
|
||||||
interface PurchaseMetricsData {
|
interface PurchaseMetricsData {
|
||||||
activePurchaseOrders: number
|
activePurchaseOrders: number
|
||||||
@@ -31,7 +32,57 @@ const COLORS = [
|
|||||||
"#FF7C43",
|
"#FF7C43",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const renderActiveShape = (props: any) => {
|
||||||
|
const { cx, cy, innerRadius, vendor, cost } = props;
|
||||||
|
|
||||||
|
// Split vendor name into words and create lines of max 12 chars
|
||||||
|
const words = vendor.split(' ');
|
||||||
|
const lines: string[] = [];
|
||||||
|
let currentLine = '';
|
||||||
|
|
||||||
|
words.forEach((word: string) => {
|
||||||
|
if ((currentLine + ' ' + word).length <= 12) {
|
||||||
|
currentLine = currentLine ? `${currentLine} ${word}` : word;
|
||||||
|
} else {
|
||||||
|
if (currentLine) lines.push(currentLine);
|
||||||
|
currentLine = word;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (currentLine) lines.push(currentLine);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<g>
|
||||||
|
{lines.map((line, i) => (
|
||||||
|
<text
|
||||||
|
key={i}
|
||||||
|
x={cx}
|
||||||
|
y={cy}
|
||||||
|
dy={-20 + (i * 16)}
|
||||||
|
textAnchor="middle"
|
||||||
|
fill="#888888"
|
||||||
|
className="text-xs"
|
||||||
|
>
|
||||||
|
{line}
|
||||||
|
</text>
|
||||||
|
))}
|
||||||
|
<text
|
||||||
|
x={cx}
|
||||||
|
y={cy}
|
||||||
|
dy={lines.length * 16 - 10}
|
||||||
|
textAnchor="middle"
|
||||||
|
fill="#000000"
|
||||||
|
className="text-base font-medium"
|
||||||
|
>
|
||||||
|
{formatCurrency(cost)}
|
||||||
|
</text>
|
||||||
|
{props.children}
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export function PurchaseMetrics() {
|
export function PurchaseMetrics() {
|
||||||
|
const [activeIndex, setActiveIndex] = useState<number | undefined>();
|
||||||
|
|
||||||
const { data } = useQuery<PurchaseMetricsData>({
|
const { data } = useQuery<PurchaseMetricsData>({
|
||||||
queryKey: ["purchase-metrics"],
|
queryKey: ["purchase-metrics"],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
@@ -104,6 +155,10 @@ export function PurchaseMetrics() {
|
|||||||
innerRadius={60}
|
innerRadius={60}
|
||||||
outerRadius={80}
|
outerRadius={80}
|
||||||
paddingAngle={2}
|
paddingAngle={2}
|
||||||
|
activeIndex={activeIndex}
|
||||||
|
activeShape={renderActiveShape}
|
||||||
|
onMouseEnter={(_, index) => setActiveIndex(index)}
|
||||||
|
onMouseLeave={() => setActiveIndex(undefined)}
|
||||||
>
|
>
|
||||||
{data?.vendorOrders?.map((entry, index) => (
|
{data?.vendorOrders?.map((entry, index) => (
|
||||||
<Cell
|
<Cell
|
||||||
@@ -112,10 +167,6 @@ export function PurchaseMetrics() {
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Pie>
|
</Pie>
|
||||||
<Tooltip
|
|
||||||
formatter={(value: number) => formatCurrency(value)}
|
|
||||||
labelFormatter={(label: string) => `Vendor: ${label}`}
|
|
||||||
/>
|
|
||||||
</PieChart>
|
</PieChart>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { useQuery } from "@tanstack/react-query"
|
import { useQuery } from "@tanstack/react-query"
|
||||||
import { CardHeader, CardTitle, CardContent } from "@/components/ui/card"
|
import { CardHeader, CardTitle, CardContent } from "@/components/ui/card"
|
||||||
import { PieChart, Pie, ResponsiveContainer, Cell, Tooltip } from "recharts"
|
import { PieChart, Pie, ResponsiveContainer, Cell, Tooltip, Sector } from "recharts"
|
||||||
import config from "@/config"
|
import config from "@/config"
|
||||||
import { formatCurrency } from "@/lib/utils"
|
import { formatCurrency } from "@/lib/utils"
|
||||||
import { Package, Layers, DollarSign, ShoppingCart } from "lucide-react" // Importing icons
|
import { Package, Layers, DollarSign, ShoppingCart } from "lucide-react" // Importing icons
|
||||||
|
import { useState } from "react"
|
||||||
|
|
||||||
interface StockMetricsData {
|
interface StockMetricsData {
|
||||||
totalProducts: number
|
totalProducts: number
|
||||||
@@ -31,7 +32,57 @@ const COLORS = [
|
|||||||
"#FF7C43",
|
"#FF7C43",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const renderActiveShape = (props: any) => {
|
||||||
|
const { cx, cy, innerRadius, vendor, cost } = props;
|
||||||
|
|
||||||
|
// Split vendor name into words and create lines of max 12 chars
|
||||||
|
const words = vendor.split(' ');
|
||||||
|
const lines: string[] = [];
|
||||||
|
let currentLine = '';
|
||||||
|
|
||||||
|
words.forEach((word: string) => {
|
||||||
|
if ((currentLine + ' ' + word).length <= 12) {
|
||||||
|
currentLine = currentLine ? `${currentLine} ${word}` : word;
|
||||||
|
} else {
|
||||||
|
if (currentLine) lines.push(currentLine);
|
||||||
|
currentLine = word;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (currentLine) lines.push(currentLine);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<g>
|
||||||
|
{lines.map((line, i) => (
|
||||||
|
<text
|
||||||
|
key={i}
|
||||||
|
x={cx}
|
||||||
|
y={cy}
|
||||||
|
dy={-20 + (i * 16)}
|
||||||
|
textAnchor="middle"
|
||||||
|
fill="#888888"
|
||||||
|
className="text-xs"
|
||||||
|
>
|
||||||
|
{line}
|
||||||
|
</text>
|
||||||
|
))}
|
||||||
|
<text
|
||||||
|
x={cx}
|
||||||
|
y={cy}
|
||||||
|
dy={lines.length * 16 - 10}
|
||||||
|
textAnchor="middle"
|
||||||
|
fill="#000000"
|
||||||
|
className="text-base font-medium"
|
||||||
|
>
|
||||||
|
{formatCurrency(cost)}
|
||||||
|
</text>
|
||||||
|
{props.children}
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export function StockMetrics() {
|
export function StockMetrics() {
|
||||||
|
const [activeIndex, setActiveIndex] = useState<number | undefined>();
|
||||||
|
|
||||||
const { data } = useQuery<StockMetricsData>({
|
const { data } = useQuery<StockMetricsData>({
|
||||||
queryKey: ["stock-metrics"],
|
queryKey: ["stock-metrics"],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
@@ -104,6 +155,10 @@ export function StockMetrics() {
|
|||||||
innerRadius={60}
|
innerRadius={60}
|
||||||
outerRadius={80}
|
outerRadius={80}
|
||||||
paddingAngle={2}
|
paddingAngle={2}
|
||||||
|
activeIndex={activeIndex}
|
||||||
|
activeShape={renderActiveShape}
|
||||||
|
onMouseEnter={(_, index) => setActiveIndex(index)}
|
||||||
|
onMouseLeave={() => setActiveIndex(undefined)}
|
||||||
>
|
>
|
||||||
{data?.vendorStock?.map((entry, index) => (
|
{data?.vendorStock?.map((entry, index) => (
|
||||||
<Cell
|
<Cell
|
||||||
@@ -112,10 +167,6 @@ export function StockMetrics() {
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Pie>
|
</Pie>
|
||||||
<Tooltip
|
|
||||||
formatter={(value: number) => formatCurrency(value)}
|
|
||||||
labelFormatter={(label: string) => `Vendor: ${label}`}
|
|
||||||
/>
|
|
||||||
</PieChart>
|
</PieChart>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user