feat([2fd88f42]): add adjustable marker radius and collapse filters by default
This commit is contained in:
@@ -23,6 +23,7 @@ function App() {
|
|||||||
const [heatmapData, setHeatmapData] = useState<HeatmapPoint[]>([]);
|
const [heatmapData, setHeatmapData] = useState<HeatmapPoint[]>([]);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [radiusMultiplier, setRadiusMultiplier] = useState(1);
|
||||||
|
|
||||||
const handleUploadSuccess = (newFilters: FilterOptions) => {
|
const handleUploadSuccess = (newFilters: FilterOptions) => {
|
||||||
setFilters(newFilters);
|
setFilters(newFilters);
|
||||||
@@ -60,21 +61,35 @@ function App() {
|
|||||||
</header>
|
</header>
|
||||||
<main className="App-main">
|
<main className="App-main">
|
||||||
<div className="control-panel">
|
<div className="control-panel">
|
||||||
<FileUpload
|
<FileUpload
|
||||||
onUploadSuccess={handleUploadSuccess}
|
onUploadSuccess={handleUploadSuccess}
|
||||||
setIsLoading={setIsLoading}
|
setIsLoading={setIsLoading}
|
||||||
setError={setError}
|
setError={setError}
|
||||||
/>
|
/>
|
||||||
<FilterPanel
|
<FilterPanel
|
||||||
filters={filters}
|
filters={filters}
|
||||||
onFilterChange={handleFilterChange}
|
onFilterChange={handleFilterChange}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
/>
|
/>
|
||||||
|
<div className="map-controls" style={{ marginTop: '20px', paddingTop: '20px', borderTop: '1px solid #555' }}>
|
||||||
|
<h3>Map Settings</h3>
|
||||||
|
<label htmlFor="radius-slider">Marker Size: {radiusMultiplier.toFixed(1)}x</label>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
id="radius-slider"
|
||||||
|
min="0.1"
|
||||||
|
max="5"
|
||||||
|
step="0.1"
|
||||||
|
value={radiusMultiplier}
|
||||||
|
onChange={(e) => setRadiusMultiplier(parseFloat(e.target.value))}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="map-container">
|
<div className="map-container">
|
||||||
{isLoading && <p>Loading map data...</p>}
|
{isLoading && <p>Loading map data...</p>}
|
||||||
{error && <p className="error">{error}</p>}
|
{error && <p className="error">{error}</p>}
|
||||||
<MapDisplay heatmapData={heatmapData} />
|
<MapDisplay heatmapData={heatmapData} radiusMultiplier={radiusMultiplier} />
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ const FilterPanel: React.FC<FilterPanelProps> = ({ filters, onFilterChange, isLo
|
|||||||
<div className="filter-panel">
|
<div className="filter-panel">
|
||||||
<h3>Filters</h3>
|
<h3>Filters</h3>
|
||||||
{Object.entries(filters).map(([category, options]) => (
|
{Object.entries(filters).map(([category, options]) => (
|
||||||
<details key={category} className="filter-group" open>
|
<details key={category} className="filter-group">
|
||||||
<summary>{category}</summary>
|
<summary>{category}</summary>
|
||||||
<div className="filter-options">
|
<div className="filter-options">
|
||||||
{options.map(option => (
|
{options.map(option => (
|
||||||
|
|||||||
@@ -6,23 +6,26 @@ import type { HeatmapPoint } from '../App';
|
|||||||
|
|
||||||
interface MapDisplayProps {
|
interface MapDisplayProps {
|
||||||
heatmapData: HeatmapPoint[];
|
heatmapData: HeatmapPoint[];
|
||||||
|
radiusMultiplier: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MapDisplay: React.FC<MapDisplayProps> = ({ heatmapData }) => {
|
const MapDisplay: React.FC<MapDisplayProps> = ({ heatmapData, radiusMultiplier }) => {
|
||||||
const germanyCenter: [number, number] = [51.1657, 10.4515];
|
const germanyCenter: [number, number] = [51.1657, 10.4515];
|
||||||
|
|
||||||
// Simple scaling function for marker radius
|
// Simple scaling function for marker radius, now with a multiplier
|
||||||
const calculateRadius = (count: number) => {
|
const calculateRadius = (count: number) => {
|
||||||
return 5 + Math.log(count + 1) * 5;
|
// Ensure a base radius so even single points are visible
|
||||||
|
// The multiplier is applied to the dynamic part of the radius
|
||||||
|
return 3 + Math.log(count + 1) * 5 * radiusMultiplier;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Simple color scaling function
|
// Simple color scaling function
|
||||||
const getColor = (count: number, maxCount: number) => {
|
const getColor = (count: number, maxCount: number) => {
|
||||||
const ratio = count / maxCount;
|
const ratio = count / maxCount;
|
||||||
if (ratio > 0.8) return 'red';
|
if (ratio > 0.8) return '#d73027'; // Red
|
||||||
if (ratio > 0.5) return 'orange';
|
if (ratio > 0.5) return '#fdae61'; // Orange
|
||||||
if (ratio > 0.2) return 'yellow';
|
if (ratio > 0.2) return '#fee08b'; // Yellow
|
||||||
return 'green';
|
return '#66bd63'; // Green
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxCount = Math.max(...heatmapData.map(p => p.count), 1);
|
const maxCount = Math.max(...heatmapData.map(p => p.count), 1);
|
||||||
|
|||||||
Reference in New Issue
Block a user