Heatmap Value Filter - Design Document
Overview
Add a flexible value filter to the Heatmap feature that allows users to filter PM10 data points by specific numeric conditions.
Requirements
Functional Requirements
Filter Modes: Support 7 filter modes:
=(equals) - Filter out points equal to the value≠(not equals) - Filter out points not equal to the value>(greater than) - Filter out points greater than the value≥(greater than or equal) - Filter out points greater than or equal to the value<(less than) - Filter out points less than the value≤(less than or equal) - Filter out points less than or equal to the valueRange- Only show points within the specified min/max range
UI Components:
- Toggle switch to enable/disable the filter
- Button group for mode selection
- Input field(s) for value entry (single or dual for range)
- Real-time validation with error messages
- Display count of filtered data points
Behavior:
- Default: disabled
- Independent from "Hide Zero Values" toggle (both filters stack)
- Real-time filtering as user types (with validation)
Non-Functional Requirements
- Consistent UI style with existing controls
- Performant filtering using useMemo
- Accessible (proper ARIA attributes)
UI Design
┌─────────────────────────────────────────┐
│ Data Filters │
├─────────────────────────────────────────┤
│ Mine Site: [Dropdown ▼] │
│ Assets: [Multi-select] │
│ Date Range: [Selector] │
│ Hide Zero Values: [Toggle] │
│ │
│ ┌─ Value Filter ──────────────────[●]─┐ │
│ │ [=] [≠] [>] [≥] [<] [≤] [Range] │ │
│ │ [ Enter value... ] │ │
│ │ Filtering X data points │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘Interaction Details
- Toggle on right controls enable/disable
- When disabled, button group and inputs are grayed out
- When "Range" selected, show two inputs: [Min] [Max]
- When enabled and valid, show filtered count at bottom
- Invalid input shows red border and error message
Data Structure
New Types
typescript
type ValueFilterMode = 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'range';Extended HeatmapControlsState
typescript
{
// ... existing properties
hideZeroValues: boolean;
// New: Value filter
valueFilterEnabled: boolean;
valueFilterMode: ValueFilterMode;
valueFilterValue: number | null; // Single value modes
valueFilterMin: number | null; // Range mode min
valueFilterMax: number | null; // Range mode max
}Default Values
typescript
valueFilterEnabled: false,
valueFilterMode: 'eq',
valueFilterValue: null,
valueFilterMin: null,
valueFilterMax: null,Filter Logic
typescript
const filteredRows = useMemo(() => {
let result = rows;
// 1. Apply hideZeroValues filter first
if (controls.hideZeroValues) {
result = result.filter((row) => {
const value = parseFloat(row.Location_AssetValue);
return !isNaN(value) && value > 0;
});
}
// 2. Apply value filter
if (controls.valueFilterEnabled && isValidFilter()) {
result = result.filter((row) => {
const value = parseFloat(row.Location_AssetValue);
if (isNaN(value)) return false;
switch (controls.valueFilterMode) {
case 'eq': return value !== controls.valueFilterValue;
case 'neq': return value === controls.valueFilterValue;
case 'gt': return value <= controls.valueFilterValue;
case 'gte': return value < controls.valueFilterValue;
case 'lt': return value >= controls.valueFilterValue;
case 'lte': return value > controls.valueFilterValue;
case 'range':
return value < controls.valueFilterMin || value > controls.valueFilterMax;
default: return false;
}
});
}
return result;
}, [rows, controls.hideZeroValues, controls.valueFilterEnabled,
controls.valueFilterMode, controls.valueFilterValue,
controls.valueFilterMin, controls.valueFilterMax]);Validation Rules
| Mode | Validation | Error Message |
|---|---|---|
| Single value modes | Must be valid number | "Please enter a valid number" |
| Range mode | Both Min and Max required | "Please enter valid numbers" |
| Range mode | Min ≤ Max | "Min must be less than or equal to Max" |
Implementation Tasks
| Task | Description | Est. Time |
|---|---|---|
| 1 | Add ValueFilterMode type and extend HeatmapControlsState | 2 min |
| 2 | Add default values to DEFAULT_CONTROLS | 2 min |
| 3 | Update filteredRows useMemo with value filter logic | 5 min |
| 4 | Add Value Filter UI component (toggle + buttons + inputs + validation) | 10 min |
| 5 | Build verification and manual testing | 5 min |
Total: ~25 minutes