Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LineChartViews #16

Merged
merged 7 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions samples/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import PieChartWithCustomizedLabel from './pages/PieChartWithCustomizedLabel';
import CustomActiveShapePieChart from './pages/CustomActiveShapePieChart';
import LineChartExample from './pages/LineChartExample';
import DashedLineChart from './pages/DashedLineChart';
import ReferenceLineChart from './pages/ReferenceLineChart';
import TinyLineChart from './pages/TinyLineChart';
import NoNullsChart from './pages/NoNulls';
import LineChartWithLabels from './pages/LineChartWithLabels';

const App = () => {
return (
Expand All @@ -31,6 +35,10 @@ const App = () => {
<Route path="/custom-active-shape-pie" element={<CustomActiveShapePieChart />} />
<Route path="/line-chart" element={<LineChartExample />} />
<Route path="/dashed-line-chart" element={<DashedLineChart />} />
<Route path="/reference-line-chart" element={<ReferenceLineChart />} />
<Route path="/tiny-line-chart" element={<TinyLineChart />} />
<Route path="/no-nulls" element={<NoNullsChart />} />
<Route path="/line-chart-with-labels" element={<LineChartWithLabels />} />
</Routes>
</div>
</Router>
Expand Down
14 changes: 14 additions & 0 deletions samples/pages/LineChartWithLabels.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// LineChartWithLabels.tsx
import React from 'react';
import LineChartWrapper from '../utils/LineChartWrapper';

const LineChartWithLabels = () => {
const initialLines = [
{ id: 1, stroke: '#8884d8', dataKey: 'pv', type: 'monotone', label: true },
{ id: 2, stroke: '#82ca9d', dataKey: 'uv', type: 'monotone', label: true },
];

return <LineChartWrapper initialLines={initialLines} />;
};

export default LineChartWithLabels;
28 changes: 28 additions & 0 deletions samples/pages/NoNulls.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import LineChartWrapper from '../utils/LineChartWrapper';

const NoNullsChart = () => {
const initialLines = [
{ id: 1, stroke: '#8884d8', dataKey: 'uv', type: 'monotone', connectNulls: false },
];


return (
<div>
<LineChartWrapper
initialLines={initialLines}
initialWidth={730}
initialHeight={250}
initialMargin={{
top: 20,
right: 30,
left: 20,
bottom: 5,
}}
withNulls={true}
/>
</div>
);
};

export default NoNullsChart;
32 changes: 32 additions & 0 deletions samples/pages/ReferenceLineChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react';
import LineChartWrapper from '../utils/LineChartWrapper';
import ReferenceLine from '../../src/ReferenceLine';

const ReferenceLineChart = () => {
const initialLines = [
{ id: 1, stroke: '#8884d8', dataKey: 'pv', type: 'monotone' },
{ id: 2, stroke: '#82ca9d', dataKey: 'uv', type: 'monotone' },
];

const additionalComponents = [
<ReferenceLine key="refLine1" x="Page C" stroke="red" label="Max PV PAGE" />,
<ReferenceLine key="refLine2" y={5800} label="Max" stroke="red" />,
];

return (
<LineChartWrapper
initialLines={initialLines}
additionalComponents={additionalComponents}
initialWidth={730}
initialHeight={250}
initialMargin={{
top: 20,
right: 50,
left: 20,
bottom: 5,
}}
/>
);
};

export default ReferenceLineChart;
24 changes: 24 additions & 0 deletions samples/pages/TinyLineChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import LineChartWrapper from '../utils/LineChartWrapper';

const TinyLineChart = () => {
const initialLines = [
{ id: 1, stroke: '#8884d8', dataKey: 'pv', type: 'monotone' },
];

return (
<LineChartWrapper
initialLines={initialLines}
initialWidth={300}
initialHeight={200}
initialMargin={{
top: 5,
right: 5,
left: 5,
bottom: 5,
}}
/>
);
};

export default TinyLineChart;
92 changes: 66 additions & 26 deletions samples/utils/LineChartControls.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
import React from 'react';

interface LineChartControlsProps {
lines: Array<{ id: number; stroke: string; type: string }>;
setLines: React.Dispatch<React.SetStateAction<Array<{ id: number; stroke: string; type: string }>>>;
lines: Array<{
id: number;
stroke: string;
type: string;
connectNulls: boolean;
dataKey: string;
}>;
setLines: React.Dispatch<React.SetStateAction<Array<{
id: number;
stroke: string;
type: string;
connectNulls: boolean;
dataKey: string;
}>>>;
width: number;
setWidth: React.Dispatch<React.SetStateAction<number>>;
height: number;
setHeight: React.Dispatch<React.SetStateAction<number>>;
margin: { top: number; right: number; bottom: number; left: number };
setMargin: React.Dispatch<React.SetStateAction<{ top: number; right: number; bottom: number; left: number }>>;
data: Array<any>;
}

const interpolationOptions = [
Expand All @@ -24,8 +37,9 @@ export default function LineChartControls({
setHeight,
margin,
setMargin,
data,
}: LineChartControlsProps) {
const handleLineChange = (index: number, key: keyof typeof lines[number], value: string) => {
const handleLineChange = <K extends keyof typeof lines[number]>(index: number, key: K, value: typeof lines[number][K]) => {
const updatedLines = [...lines];
updatedLines[index][key] = value;
setLines(updatedLines);
Expand All @@ -35,6 +49,10 @@ export default function LineChartControls({
setMargin({ ...margin, [side]: value });
};

const hasNullValues = (dataKey: string): boolean => {
return data.some(item => item[dataKey] === undefined || item[dataKey] === null);
};

return (
<div className="bg-white p-6 shadow-lg rounded-lg mb-5 max-w-md">
<h2 className="text-2xl font-semibold mb-6 text-indigo-700">Line Chart Settings</h2>
Expand Down Expand Up @@ -86,34 +104,56 @@ export default function LineChartControls({
{lines.map((line, index) => (
<div key={line.id} className="bg-gray-50 p-4 rounded-lg mb-4 shadow-sm">
<h3 className="text-lg font-medium text-indigo-700 mb-2">Line {index + 1} Settings</h3>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Stroke Color</label>
<div className="flex items-center space-x-2">
<input
type="color"
value={line.stroke}
onChange={(e) => handleLineChange(index, 'stroke', e.target.value)}
className="w-8 h-8 border-none rounded-md cursor-pointer"
/>
<span className="text-sm font-medium text-gray-600">{line.stroke}</span>
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Stroke Color</label>
<div className="flex items-center space-x-2">
<input
type="color"
value={line.stroke}
onChange={(e) => handleLineChange(index, 'stroke', e.target.value)}
className="w-8 h-8 border-none rounded-md cursor-pointer"
/>
<span className="text-sm font-medium text-gray-600">{line.stroke}</span>
</div>
</div>

<label className="block text-sm font-medium text-gray-700 mt-2">Interpolation Type</label>
<select
value={line.type}
onChange={(e) => handleLineChange(index, 'type', e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 transition duration-300 ease-in-out"
>
{interpolationOptions.map((option) => (
<option key={option} value={option}>
{option.charAt(0).toUpperCase() + option.slice(1)}
</option>
))}
</select>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Interpolation Type</label>
<select
value={line.type}
onChange={(e) => handleLineChange(index, 'type', e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 transition duration-300 ease-in-out"
>
{interpolationOptions.map((option) => (
<option key={option} value={option}>
{option.charAt(0).toUpperCase() + option.slice(1)}
</option>
))}
</select>
</div>

{hasNullValues(line.dataKey) && (
<div className="flex items-center space-x-2">
<input
type="checkbox"
id={`connectNulls-${index}`}
checked={line.connectNulls}
onChange={(e) => handleLineChange(index, 'connectNulls', e.target.checked)}
className="w-4 h-4 text-indigo-600 border-gray-300 rounded focus:ring-indigo-500"
/>
<label
htmlFor={`connectNulls-${index}`}
className="text-sm font-medium text-gray-700"
>
Connect Null Values
</label>
</div>
)}
</div>
</div>
))}
</form>
</div>
);
}
}
74 changes: 45 additions & 29 deletions samples/utils/LineChartWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,31 @@ import Tooltip from '../../src/Tooltip';
import Legend from '../../src/Legend';
import LineChartControls from './LineChartControls';

const data = [
{ name: 'Page A', uv: 4000, pv: 2400, amt: 2400 },
{ name: 'Page B', uv: 3000, pv: 1398, amt: 2210 },
{ name: 'Page C', uv: 2000, pv: 9800, amt: 2290 },
{ name: 'Page D', uv: 2780, pv: 3908, amt: 2000 },
{ name: 'Page E', uv: 1890, pv: 4800, amt: 2181 },
{ name: 'Page F', uv: 2390, pv: 3800, amt: 2500 },
{ name: 'Page G', uv: 3490, pv: 4300, amt: 2100 },
const dataWithNulls = [
{ name: 'Page A', uv: 4000 },
{ name: 'Page B', uv: 3000 },
{ name: 'Page C', uv: 2000 },
{ name: 'Page D' },
{ name: 'Page E', uv: 1890 },
{ name: 'Page F', uv: 2390 },
{ name: 'Page G', uv: 3490 },
];

const LineChartWrapper = ({ initialLines }) => {
const LineChartWrapper = ({ initialLines, additionalComponents = [], initialWidth = 730, initialHeight = 250, initialMargin = { top: 5, right: 30, left: 20, bottom: 5 }, withNulls = false }) => {
const [lines, setLines] = useState(initialLines);
const [width, setWidth] = useState(730);
const [height, setHeight] = useState(250);
const [margin, setMargin] = useState({ top: 5, right: 30, left: 20, bottom: 5 });
const [width, setWidth] = useState(initialWidth);
const [height, setHeight] = useState(initialHeight);
const [margin, setMargin] = useState(initialMargin);

const data = withNulls ? dataWithNulls : [
{ name: 'Page A', uv: 4000, pv: 2400, amt: 2400 },
{ name: 'Page B', uv: 3000, pv: 1398, amt: 2210 },
{ name: 'Page C', uv: 2000, pv: 9800, amt: 2290 },
{ name: 'Page D', uv: 2780, pv: 3908, amt: 2000 },
{ name: 'Page E', uv: 1890, pv: 4800, amt: 2181 },
{ name: 'Page F', uv: 2390, pv: 3800, amt: 2500 },
{ name: 'Page G', uv: 3490, pv: 4300, amt: 2100 },
];

return (
<div className="p-6">
Expand All @@ -36,26 +46,32 @@ const LineChartWrapper = ({ initialLines }) => {
setHeight={setHeight}
margin={margin}
setMargin={setMargin}
data={data}
/>
<LineChart width={width} height={height} data={data} margin={margin}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Legend />
{lines.map((line) => (
<Line
key={line.id}
type={line.type}
dataKey={line.dataKey}
stroke={line.stroke}
strokeDasharray={line.strokeDasharray}
/>
))}
</LineChart>
<div className='flex items-center pl-12'>
<LineChart width={width} height={height} data={data} margin={margin}>
{width > 300 && height > 200 && <CartesianGrid strokeDasharray="3 3" />}
{width > 300 && height > 200 && <XAxis dataKey="name" />}
{width > 300 && height > 200 && <YAxis />}
{width > 300 && height > 200 && <Tooltip />}
{width > 300 && height > 200 && <Legend />}
{lines.map((line) => (
<Line
key={line.id}
type={line.type}
dataKey={line.dataKey}
stroke={line.stroke}
strokeDasharray={line.strokeDasharray}
connectNulls={line.connectNulls}
label={line.label}
/>
))}
{additionalComponents}
</LineChart>
</div>
</div>
</div>
);
};

export default LineChartWrapper;
export default LineChartWrapper;
4 changes: 4 additions & 0 deletions samples/utils/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ export default function NavBar() {
items: [
{ name: 'Line Chart', path: '/line-chart' },
{ name: 'Dashed Line Chart', path: '/dashed-line-chart' },
{ name: 'Reference Line Chart', path: '/reference-line-chart' },
{ name: 'Tiny Line Chart', path: '/tiny-line-chart' },
{ name: 'Connect Nulls Chart', path: '/no-nulls' },
{ name: 'Line Chart with Labels', path: '/line-chart-with-labels' },
],
},
];
Expand Down
Loading
Loading