@classic-homes/maps-core
v0.2.10
Published
Core utilities and theme for Classic Theme maps
Readme
@classic-homes/maps-core
Core utilities, types, and themes for Classic Theme map components. This package provides the shared foundation for @classic-homes/maps-react and @classic-homes/maps-svelte.
Installation
npm install @classic-homes/maps-coreFeatures
- Theme System: Pre-configured light/dark themes with design token integration
- MapLibre Style Generation: Generate complete MapLibre GL styles from themes
- Type Definitions: Comprehensive TypeScript types for all map components
- Utility Functions: Bounds calculation, GeoJSON validation, coordinate formatting
- Style Helpers: Create hover, selection, and data-driven expressions
- Spatial Indexing: Grid-based and R-tree indexes for large datasets
- LOD Utilities: Level-of-detail management for 100k+ feature datasets
- Polygon Simplification: Douglas-Peucker algorithm for zoom-based simplification
Usage
Themes
import {
lightTheme,
darkTheme,
lightBasicStyle,
darkBasicStyle,
THEME_LIGHT,
THEME_DARK,
} from '@classic-homes/maps-core';
// Use pre-generated MapLibre styles
const mapStyle = isDark ? darkBasicStyle : lightBasicStyle;
// Or access theme colors for custom styling
const highlightColor = lightTheme.colors.highlight;Style Expressions
import {
createHoverExpression,
createSelectionExpression,
createInteractiveExpression,
createCategoricalColorExpression,
createContinuousColorExpression,
createLotFillStyle,
createLotOutlineStyle,
} from '@classic-homes/maps-core';
// Hover highlighting
const fillColor = createHoverExpression('#22c55e', '#3b82f6');
// Status-based coloring
const statusColor = createCategoricalColorExpression(
'status',
{
available: '#22c55e',
pending: '#f59e0b',
sold: '#ef4444',
},
'#888888'
);
// Lot fill with hover/selection support
const lotStyle = createLotFillStyle({
defaultColor: '#22c55e',
hoverColor: '#3b82f6',
selectedColor: '#f59e0b',
opacity: 0.7,
});Bounds and Data Utilities
import {
calculateBounds,
combineBounds,
loadGeoJSON,
validateGeoJSON,
calculateCentroid,
filterByGeometryType,
} from '@classic-homes/maps-core';
// Calculate bounds of a GeoJSON
const bounds = calculateBounds(featureCollection);
// Load and validate GeoJSON
const { data, error, success } = await loadGeoJSON('/api/features.geojson');
// Filter by geometry type
const polygonsOnly = filterByGeometryType(featureCollection, ['Polygon', 'MultiPolygon']);Spatial Indexing (Large Datasets)
import {
buildSpatialIndex,
queryByBounds,
buildRTreeIndex,
queryRTreeByBounds,
createIdleViewportManager,
} from '@classic-homes/maps-core';
// Build a spatial index for fast viewport queries
const index = buildSpatialIndex(featureCollection, { targetCells: 100 });
// Query visible features in viewport
const visible = queryByBounds(index, viewportBounds, { buffer: 0.1 });
// For smooth panning, use the idle-aware viewport manager
const viewportManager = createIdleViewportManager(featureCollection, {
indexType: 'rtree',
bufferFraction: 0.2,
});
const result = viewportManager.query(viewportBounds);Level-of-Detail (LOD) for Large Datasets
import {
generateLODData,
generateLODDataWithSimplification,
createDynamicLODManager,
DEFAULT_SIMPLIFICATION_THRESHOLDS,
} from '@classic-homes/maps-core';
// Generate LOD boundaries
const lod = generateLODData(lotsData, {
groupBy: 'community',
subGroupBy: 'filing',
useConvexHull: true,
});
// With polygon simplification for different zoom levels
const lodWithSimplification = generateLODDataWithSimplification(lotsData, {
groupBy: 'community',
simplificationThresholds: DEFAULT_SIMPLIFICATION_THRESHOLDS,
});
// Dynamic FPS-based LOD threshold adjustment
const lodManager = createDynamicLODManager({
baseThresholds: { groupMaxZoom: 12, subGroupMaxZoom: 14 },
targetFps: 50,
});Fast GeoJSON Change Detection
import { createGeoJSONFingerprint, fingerprintEqual, geoJSONEqual } from '@classic-homes/maps-core';
// O(1) equality check instead of deep comparison
const prevFingerprint = createGeoJSONFingerprint(prevData);
const nextFingerprint = createGeoJSONFingerprint(nextData);
if (!fingerprintEqual(prevFingerprint, nextFingerprint)) {
// Data changed, update the map
updateSource(nextData);
}Type Exports
The package exports comprehensive TypeScript types:
import type {
// Coordinates
LngLat,
MapBounds,
BoundsArray,
MapViewport,
// GeoJSON
GeoJSONFeature,
GeoJSONFeatureCollection,
GeoJSONGeometry,
GeoJSONPolygon,
// Events
MapClickEventParams,
MapHoverEventParams,
FeatureClickEventParams,
FeatureHoverEventParams,
MarkerClickEventParams,
// Component Props
MapProps,
SourceProps,
FillLayerProps,
LineLayerProps,
CircleLayerProps,
MarkerProps,
PopupProps,
// Themes
MapTheme,
MapThemeColors,
MapStyleSpec,
} from '@classic-homes/maps-core';API Reference
Theme Functions
| Function | Description |
| --------------------------- | ---------------------------- |
| generateLightTheme() | Generate light theme colors |
| generateDarkTheme() | Generate dark theme colors |
| generateBasicStyle(theme) | Generate MapLibre style spec |
| getTheme(name) | Get theme by name |
Style Helpers
| Function | Description |
| ------------------------------------------------------ | ----------------------------------------- |
| createFillStyle(opts) | Create fill layer paint properties |
| createLineStyle(opts) | Create line layer paint/layout properties |
| createCircleStyle(opts) | Create circle layer paint properties |
| createHoverExpression(base, hover) | Feature-state based hover expression |
| createSelectionExpression(base, selected) | Feature-state based selection expression |
| createInteractiveExpression(base, hover, selected) | Combined hover + selection |
| createCategoricalColorExpression(prop, map, default) | Match expression for categories |
| createContinuousColorExpression(prop, stops, interp) | Interpolate expression |
| createZoomExpression(stops) | Zoom-based interpolation |
Data Utilities
| Function | Description |
| --------------------------------- | ------------------------------- |
| loadGeoJSON(url, opts) | Fetch and validate GeoJSON |
| validateGeoJSON(data) | Validate GeoJSON structure |
| calculateCentroid(geojson) | Calculate centroid of features |
| countFeaturesByType(fc) | Count features by geometry type |
| filterByGeometryType(fc, types) | Filter by geometry types |
Bounds Utilities
| Function | Description |
| ----------------------------- | ------------------------------ |
| calculateBounds(geojson) | Get bounding box of features |
| extendBounds(bounds, point) | Extend bounds to include point |
| combineBounds(a, b) | Merge two bounds |
| isValidBounds(bounds) | Validate bounds array |
Spatial Indexing
| Function | Description |
| ------------------------------------------- | ------------------------------ |
| buildSpatialIndex(fc, opts) | Build grid-based spatial index |
| queryByBounds(index, bounds, opts) | Query features in viewport |
| buildRTreeIndex(fc, opts) | Build R-tree spatial index |
| queryRTreeByBounds(index, bounds, opts) | Query R-tree by bounds |
| createIdleViewportManager(fc, opts) | Smooth viewport querying |
| createPredictiveViewportManager(fc, opts) | Predictive pan loading |
LOD Utilities
| Function | Description |
| ------------------------------------------ | ------------------------------ |
| groupFeaturesByProperty(fc, opts) | Group features by property |
| generateLODData(fc, opts) | Generate LOD boundaries |
| generateConvexHull(features) | Generate convex hull polygon |
| simplifyPolygon(polygon, tolerance) | Douglas-Peucker simplification |
| simplifyFeatureCollection(fc, tolerance) | Simplify all features |
| createDynamicLODManager(opts) | FPS-based threshold adjustment |
License
MIT
