arshenoy commited on
Commit
e2f9788
·
verified ·
1 Parent(s): daac3e4

Update components/GaugeChart.tsx

Browse files
Files changed (1) hide show
  1. components/GaugeChart.tsx +82 -84
components/GaugeChart.tsx CHANGED
@@ -2,96 +2,94 @@ import React from 'react';
2
  import { PieChart, Pie, Cell, ResponsiveContainer } from 'recharts';
3
 
4
  interface GaugeChartProps {
5
- value: number; // 0 to 100
6
  }
7
 
8
  const GaugeChart: React.FC<GaugeChartProps> = ({ value }) => {
9
- const data = [
10
- { name: 'Low', value: 40, color: '#00ff80' },
11
- { name: 'Medium', value: 40, color: '#ffc300' },
12
- { name: 'High', value: 20, color: '#ff3300' },
13
- ];
14
 
15
- // --- PIXEL-PERFECT LAYOUT CONFIGURATION ---
16
- // Using fixed pixels for vertical alignment ensures the HTML overlay
17
- // matches the SVG chart exactly, preventing overlap during resizing.
18
- const chartHeight = 220;
19
- const centerY = 130; // The pivot point Y-coordinate
20
- const innerRadius = 70;
21
- const outerRadius = 90;
22
-
23
- // Clamp value
24
- const safeValue = Math.min(Math.max(value, 0), 100);
25
-
26
- // Calculate Rotation:
27
- // 0 value -> -90deg (Left)
28
- // 100 value -> 90deg (Right)
29
- const needleRotation = (safeValue * 1.8) - 90;
30
 
31
- return (
32
- <div className="w-full relative select-none flex justify-center overflow-hidden" style={{ height: `${chartHeight}px` }}>
33
- <ResponsiveContainer width="100%" height="100%">
34
- <PieChart>
35
- <Pie
36
- dataKey="value"
37
- startAngle={180}
38
- endAngle={0}
39
- data={data}
40
- cx="50%"
41
- cy={centerY} // Explicit pixel center
42
- innerRadius={innerRadius}
43
- outerRadius={outerRadius}
44
- paddingAngle={2}
45
- stroke="none"
46
- >
47
- {data.map((entry, index) => (
48
- <Cell key={`cell-${index}`} fill={entry.color} fillOpacity={0.3} stroke={entry.color} strokeWidth={1} />
49
- ))}
50
- </Pie>
51
- </PieChart>
52
- </ResponsiveContainer>
53
-
54
- {/* NEEDLE CONTAINER */}
55
- {/* Anchored exactly at 'centerY' pixels from the top */}
56
- <div
57
- className="absolute left-1/2 pointer-events-none"
58
- style={{
59
- top: `${centerY}px`,
60
- transform: 'translate(-50%, -50%)',
61
- zIndex: 10
62
- }}
63
- >
64
- {/* The Needle Bar */}
65
- <div
66
- className="w-1.5 bg-white origin-bottom rounded-t-full shadow-[0_0_10px_rgba(255,255,255,0.8)]"
67
- style={{
68
- height: `${outerRadius}px`,
69
- position: 'absolute',
70
- bottom: '0',
71
- left: '-3px', // Center the 6px width (1.5 * 4px)
72
- transform: `rotate(${needleRotation}deg)`,
73
- transition: 'transform 1s cubic-bezier(0.34, 1.56, 0.64, 1)' // Elastic bounce effect
74
- }}
75
- />
76
- {/* Pivot Circle Cap */}
77
- <div className="absolute w-4 h-4 bg-white rounded-full shadow-[0_0_10px_rgba(255,255,255,0.8)] -translate-x-1/2 -translate-y-1/2" />
78
- </div>
79
 
80
- {/* TEXT CONTAINER */}
81
- {/* Explicitly positioned below the pivot with a fixed gap */}
82
- <div
83
- className="absolute flex flex-col items-center justify-center pointer-events-none"
84
- style={{ top: `${centerY + 25}px`, width: '100%' }}
85
- >
86
- <span className="text-4xl font-mono font-bold text-white drop-shadow-[0_0_15px_rgba(255,255,255,0.4)] leading-none">
87
- {Math.round(safeValue)}
88
- </span>
89
- <span className="text-[10px] text-gray-400 uppercase tracking-[0.2em] font-bold mt-1">
90
- Risk Score
91
- </span>
92
- </div>
93
- </div>
94
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  };
96
 
97
  export default GaugeChart;
 
2
  import { PieChart, Pie, Cell, ResponsiveContainer } from 'recharts';
3
 
4
  interface GaugeChartProps {
5
+ value: number; // 0 to 100
6
  }
7
 
8
  const GaugeChart: React.FC<GaugeChartProps> = ({ value }) => {
9
+ const data = [
10
+ { name: 'Low', value: 40, color: '#00ff80' },
11
+ { name: 'Medium', value: 40, color: '#ffc300' },
12
+ { name: 'High', value: 20, color: '#ff3300' },
13
+ ];
14
 
15
+ // --- PIXEL-PERFECT LAYOUT CONFIGURATION ---
16
+ // Using fixed pixels for vertical alignment ensures the HTML overlay
17
+ // matches the SVG chart exactly, preventing overlap during resizing.
18
+ const chartHeight = 220;
19
+ const centerY = 130; // The pivot point Y-coordinate
20
+ const innerRadius = 70;
21
+ const outerRadius = 90;
 
 
 
 
 
 
 
 
22
 
23
+ // Clamp value
24
+ const safeValue = Math.min(Math.max(value, 0), 100);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
+ // Calculate Rotation:
27
+ // 0 value -> -90deg (Left)
28
+ // 100 value -> 90deg (Right)
29
+ const needleRotation = (safeValue * 1.8) - 90;
30
+
31
+ return (
32
+ <div className="w-full relative select-none flex justify-center overflow-hidden" style={{ height: `${chartHeight}px` }}>
33
+ <ResponsiveContainer width="100%" height="100%">
34
+ <PieChart>
35
+ <Pie
36
+ dataKey="value"
37
+ startAngle={180}
38
+ endAngle={0}
39
+ data={data}
40
+ cx="50%"
41
+ cy={centerY} // Explicit pixel center
42
+ innerRadius={innerRadius}
43
+ outerRadius={outerRadius}
44
+ paddingAngle={2}
45
+ stroke="none"
46
+ >
47
+ {data.map((entry, index) => (
48
+ <Cell key={`cell-${index}`} fill={entry.color} fillOpacity={0.3} stroke={entry.color} strokeWidth={1} />
49
+ ))}
50
+ </Pie>
51
+ </PieChart>
52
+ </ResponsiveContainer>
53
+ {/* NEEDLE CONTAINER */}
54
+ {/* Anchored exactly at 'centerY' pixels from the top */}
55
+ <div
56
+ className="absolute left-1/2 pointer-events-none"
57
+ style={{
58
+ top: `${centerY}px`,
59
+ transform: 'translate(-50%, -50%)',
60
+ zIndex: 10
61
+ }}
62
+ >
63
+ {/* The Needle Bar */}
64
+ <div
65
+ className="w-1.5 bg-white origin-bottom rounded-t-full shadow-[0_0_10px_rgba(255,255,255,0.8)]"
66
+ style={{
67
+ height: `${outerRadius}px`,
68
+ position: 'absolute',
69
+ bottom: '0',
70
+ left: '-3px', // Center the 6px width (1.5 * 4px)
71
+ transform: `rotate(${needleRotation}deg)`,
72
+ transition: 'transform 1s cubic-bezier(0.34, 1.56, 0.64, 1)' // Elastic bounce effect
73
+ }}
74
+ />
75
+ {/* Pivot Circle Cap */}
76
+ <div className="absolute w-4 h-4 bg-white rounded-full shadow-[0_0_10px_rgba(255,255,255,0.8)] -translate-x-1/2 -translate-y-1/2" />
77
+ </div>
78
+ {/* TEXT CONTAINER */}
79
+ {/* Explicitly positioned below the pivot with a fixed gap */}
80
+ <div
81
+ className="absolute flex flex-col items-center justify-center pointer-events-none"
82
+ style={{ top: `${centerY + 25}px`, width: '100%' }}
83
+ >
84
+ <span className="text-4xl font-mono font-bold text-white drop-shadow-[0_0_15px_rgba(255,255,255,0.4)] leading-none">
85
+ {Math.round(safeValue)}
86
+ </span>
87
+ <span className="text-[10px] text-gray-400 uppercase tracking-[0.2em] font-bold mt-1">
88
+ Risk Score
89
+ </span>
90
+ </div>
91
+ </div>
92
+ );
93
  };
94
 
95
  export default GaugeChart;