PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.15
Yatra – Travel Booking & Tour Operator Software v3.0.15
3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 2.0.10 All 83 releases
yatra / resources / js / components / charts / SimpleLineChart.tsx

SimpleLineChart.tsx in Yatra – Travel Booking & Tour Operator Software 3.0.15, at resources/js/components/charts/SimpleLineChart.tsx

179 lines 4.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Simple Line Chart Component
3 * Lightweight line chart for displaying trends
4 * Modular and extensible for Pro version enhancements
5 */
6
7 import React from "react";
8 import { __ } from "../../lib/i18n";
9
10 interface DataPoint {
11 label: string;
12 value: number;
13 }
14
15 interface SimpleLineChartProps {
16 data: DataPoint[];
17 title: string;
18 height?: number;
19 color?: string;
20 showGrid?: boolean;
21 }
22
23 /**
24 * Simple Line Chart Component
25 * Renders a basic line chart using SVG
26 */
27 export const SimpleLineChart: React.FC<SimpleLineChartProps> = ({
28 data,
29 title,
30 height = 200,
31 color = "#3b82f6",
32 showGrid = true,
33 }) => {
34 if (!data || data.length === 0) {
35 return (
36 <div className="flex items-center justify-center h-full text-gray-500 dark:text-gray-400">
37 {__("No data available", "yatra")}
38 </div>
39 );
40 }
41
42 const maxValue = Math.max(...data.map((d) => d.value), 1);
43 const minValue = Math.min(...data.map((d) => d.value), 0);
44 const range = maxValue - minValue || 1;
45
46 const width = 100;
47 const chartHeight = height - 40;
48 const padding = 10;
49
50 // Calculate points for the line
51 const points = data.map((point, index) => {
52 const x =
53 padding + (index * (width - 2 * padding)) / (data.length - 1 || 1);
54 const y =
55 chartHeight -
56 padding -
57 ((point.value - minValue) / range) * (chartHeight - 2 * padding);
58 return { x, y, value: point.value, label: point.label };
59 });
60
61 // Create path for the line
62 const pathData = points
63 .map((point, index) => {
64 return `${index === 0 ? "M" : "L"} ${point.x} ${point.y}`;
65 })
66 .join(" ");
67
68 // Create area path (for fill)
69 const areaPath = `${pathData} L ${points[points.length - 1].x} ${chartHeight - padding} L ${padding} ${chartHeight - padding} Z`;
70
71 return (
72 <div className="w-full h-full">
73 {title && (
74 <h3 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-4">
75 {title}
76 </h3>
77 )}
78 <svg
79 width="100%"
80 height={height}
81 viewBox={`0 0 ${width} ${height}`}
82 className="overflow-visible"
83 >
84 {/* Grid lines - subtle */}
85 {showGrid && (
86 <g
87 stroke="#f3f4f6"
88 strokeWidth="0.5"
89 className="dark:stroke-gray-700"
90 >
91 {[0, 0.25, 0.5, 0.75, 1].map((ratio) => {
92 const y =
93 chartHeight - padding - ratio * (chartHeight - 2 * padding);
94 return (
95 <line
96 key={ratio}
97 x1={padding}
98 y1={y}
99 x2={width - padding}
100 y2={y}
101 />
102 );
103 })}
104 </g>
105 )}
106
107 {/* Area fill - subtle */}
108 <path
109 d={areaPath}
110 fill={color}
111 fillOpacity="0.08"
112 className="dark:opacity-20"
113 />
114
115 {/* Line */}
116 <path
117 d={pathData}
118 fill="none"
119 stroke={color}
120 strokeWidth="2.5"
121 strokeLinecap="round"
122 strokeLinejoin="round"
123 />
124
125 {/* Data points */}
126 {points.map((point, index) => (
127 <g key={index}>
128 <circle
129 cx={point.x}
130 cy={point.y}
131 r="3.5"
132 fill="white"
133 stroke={color}
134 strokeWidth="2"
135 className="hover:r-4 transition-all"
136 />
137 <title>{`${point.label}: ${point.value}`}</title>
138 </g>
139 ))}
140
141 {/* X-axis labels */}
142 {points.map((point, index) => {
143 // Show all labels but space them better
144 const shouldShow =
145 index === 0 ||
146 index === data.length - 1 ||
147 index % Math.max(1, Math.floor(data.length / 4)) === 0;
148 if (shouldShow) {
149 // Split long labels (like "MayJun" -> "May" / "Jun")
150 const labelParts =
151 point.label.length > 5
152 ? point.label.match(/.{1,3}/g) || [point.label]
153 : [point.label];
154
155 return (
156 <g key={index}>
157 {labelParts.map((part, partIndex) => (
158 <text
159 key={partIndex}
160 x={point.x}
161 y={chartHeight - 5 + partIndex * 10}
162 textAnchor="middle"
163 className="text-xs fill-gray-500 dark:fill-gray-400"
164 >
165 {part}
166 </text>
167 ))}
168 </g>
169 );
170 }
171 return null;
172 })}
173 </svg>
174 </div>
175 );
176 };
177
178 export default SimpleLineChart;
179