Improve chart visualization and UI layout #1

Merged
stephen merged 3 commits from chart-axis-improvements into main 2026-01-21 11:03:13 -07:00
Showing only changes of commit c784af3d81 - Show all commits

View File

@ -157,6 +157,39 @@ const ApartmentDashboard = () => {
} }
}; };
// Calculate nice axis bounds that round to reasonable values
const getAxisDomain = (data, dataKey, padding = 0.1) => {
if (!data || data.length === 0) return [0, 100];
const values = data.map(d => d[dataKey]).filter(v => v != null && !isNaN(v));
if (values.length === 0) return [0, 100];
const min = Math.min(...values);
const max = Math.max(...values);
const range = max - min;
// Add padding to the range
const paddedMin = min - range * padding;
const paddedMax = max + range * padding;
// Determine a nice interval based on the range
const getNiceInterval = (range) => {
if (range <= 10) return 1;
if (range <= 50) return 5;
if (range <= 100) return 10;
if (range <= 500) return 50;
if (range <= 1000) return 100;
if (range <= 5000) return 500;
return 1000;
};
const interval = getNiceInterval(range);
const niceMin = Math.floor(paddedMin / interval) * interval;
const niceMax = Math.ceil(paddedMax / interval) * interval;
return [Math.max(0, niceMin), niceMax];
};
// Process price history based on time range // Process price history based on time range
const processPriceHistory = (priceHistory, timeRange) => { const processPriceHistory = (priceHistory, timeRange) => {
if (!priceHistory || priceHistory.length === 0) return []; if (!priceHistory || priceHistory.length === 0) return [];
@ -515,7 +548,7 @@ const ApartmentDashboard = () => {
dataKey="date" dataKey="date"
tickFormatter={(date) => formatDate(date)} tickFormatter={(date) => formatDate(date)}
/> />
<YAxis tickFormatter={(value) => formatPrice(value)} /> <YAxis tickFormatter={(value) => formatPrice(value)} domain={getAxisDomain(priceHistory.filter(d => d.avgPrice !== null), 'avgPrice')} />
<Tooltip <Tooltip
formatter={(value, name) => [formatPrice(value), 'Avg Price']} formatter={(value, name) => [formatPrice(value), 'Avg Price']}
labelFormatter={(date) => formatDate(date)} labelFormatter={(date) => formatDate(date)}
@ -535,7 +568,7 @@ const ApartmentDashboard = () => {
dataKey="date" dataKey="date"
tickFormatter={(date) => formatDate(date)} tickFormatter={(date) => formatDate(date)}
/> />
<YAxis /> <YAxis domain={getAxisDomain(priceHistory, 'unitCount')} />
<Tooltip <Tooltip
formatter={(value, name) => [value, 'Available Units']} formatter={(value, name) => [value, 'Available Units']}
labelFormatter={(date) => formatDate(date)} labelFormatter={(date) => formatDate(date)}
@ -578,7 +611,7 @@ const ApartmentDashboard = () => {
<BarChart data={planStats}> <BarChart data={planStats}>
<CartesianGrid strokeDasharray="3 3" /> <CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" angle={-45} textAnchor="end" height={80} /> <XAxis dataKey="name" angle={-45} textAnchor="end" height={80} />
<YAxis tickFormatter={(value) => formatPrice(value)} /> <YAxis tickFormatter={(value) => formatPrice(value)} domain={getAxisDomain(planStats, 'avgPrice')} />
<Tooltip formatter={(value, name) => [formatPrice(value), 'Avg Price']} /> <Tooltip formatter={(value, name) => [formatPrice(value), 'Avg Price']} />
<Bar dataKey="avgPrice" fill="#8B0000" /> <Bar dataKey="avgPrice" fill="#8B0000" />
</BarChart> </BarChart>
@ -792,8 +825,8 @@ const ApartmentDashboard = () => {
<ComposedChart data={analyticsData.monthlyTrends}> <ComposedChart data={analyticsData.monthlyTrends}>
<CartesianGrid strokeDasharray="3 3" /> <CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="month" tickFormatter={(m) => m ? m.substring(2) : ''} /> <XAxis dataKey="month" tickFormatter={(m) => m ? m.substring(2) : ''} />
<YAxis yAxisId="left" tickFormatter={(v) => `$${(v/1000).toFixed(1)}k`} /> <YAxis yAxisId="left" tickFormatter={(v) => `$${(v/1000).toFixed(1)}k`} domain={getAxisDomain(analyticsData.monthlyTrends, 'avgPrice')} />
<YAxis yAxisId="right" orientation="right" /> <YAxis yAxisId="right" orientation="right" domain={getAxisDomain(analyticsData.monthlyTrends, 'unitCount')} />
<Tooltip <Tooltip
formatter={(value, name) => { formatter={(value, name) => {
if (name === 'avgPrice') return [formatPrice(value), 'Avg Price']; if (name === 'avgPrice') return [formatPrice(value), 'Avg Price'];
@ -821,7 +854,7 @@ const ApartmentDashboard = () => {
}))}> }))}>
<CartesianGrid strokeDasharray="3 3" /> <CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="monthName" /> <XAxis dataKey="monthName" />
<YAxis tickFormatter={(v) => `$${(v/1000).toFixed(1)}k`} domain={['dataMin - 100', 'dataMax + 100']} /> <YAxis tickFormatter={(v) => `$${(v/1000).toFixed(1)}k`} domain={getAxisDomain(analyticsData.seasonality, 'avgPrice')} />
<Tooltip formatter={(value) => [formatPrice(value), 'Avg Price']} /> <Tooltip formatter={(value) => [formatPrice(value), 'Avg Price']} />
<Bar dataKey="avgPrice" fill="#8B0000" /> <Bar dataKey="avgPrice" fill="#8B0000" />
</BarChart> </BarChart>
@ -839,7 +872,7 @@ const ApartmentDashboard = () => {
<BarChart data={analyticsData.pricePerSqftByBed}> <BarChart data={analyticsData.pricePerSqftByBed}>
<CartesianGrid strokeDasharray="3 3" /> <CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="bedrooms" tickFormatter={(v) => `${v} BR`} /> <XAxis dataKey="bedrooms" tickFormatter={(v) => `${v} BR`} />
<YAxis tickFormatter={(v) => `$${v.toFixed(2)}`} /> <YAxis tickFormatter={(v) => `$${v.toFixed(2)}`} domain={getAxisDomain(analyticsData.pricePerSqftByBed, 'avgPricePerSqft')} />
<Tooltip <Tooltip
formatter={(value, name) => { formatter={(value, name) => {
if (name === 'avgPricePerSqft') return [`$${value.toFixed(2)}/sqft`, 'Price/Sqft']; if (name === 'avgPricePerSqft') return [`$${value.toFixed(2)}/sqft`, 'Price/Sqft'];