geo-toolkits
v1.0.0
Published
A comprehensive TypeScript library for geospatial operations including geofencing, polygon containment, area calculations, and coordinate processing. Supports GeoJSON, KML, and KMZ file formats with both local file and remote URL loading capabilities.
Downloads
14
Maintainers
Readme
geo-toolkits
A comprehensive TypeScript library for geospatial data processing, area calculations, and geofencing operations. Supports GeoJSON, KML, and KMZ file formats with both local file and remote URL loading capabilities.
🌟 Features
- 🗺️ Multi-format Support: Load GeoJSON, KML, and KMZ files
- 📁 Flexible Loading: Support for both local files and remote URLs
- 🎯 Geofencing: Point-in-polygon detection with hole support
- 📐 Area Calculations: Accurate spherical area calculations for Earth surface
- 📊 Statistical Analysis: Comprehensive area and geometric statistics
- 🔍 Spatial Queries: Find closest features and multiple containment checks
- ⚡ Performance Optimized: Bounding box pre-filtering for fast operations
- 📝 TypeScript: Full type safety and IntelliSense support
📦 Installation
npm install geo-toolkits🚀 Quick Start
import { GeoToolKit } from 'geo-toolkits';
const kit = new GeoToolKit();
// Load spatial data
await kit.loadFromFile('./boundaries.geojson');
// or from URL
await kit.loadFromUrl('https://example.com/data.geojson');
// Check if a point is inside any polygon
const result = kit.contains(40.7128, -74.0060); // NYC coordinates
if (result.isInside) {
console.log(`Point is inside feature: ${result.featureIndex}`);
}
// Calculate total area
const totalArea = kit.getArea(); // in square meters
const areaInKm2 = kit.getAreaInUnit('square_kilometers');
// Get bounding box
const bbox = kit.getBoundingBox();
console.log(`Area spans: ${bbox.maxLat - bbox.minLat} degrees latitude`);📖 API Reference
Data Loading
loadFromFile(filePath: string): Promise<void>
Load spatial data from a local file. Supports GeoJSON (.geojson, .json), KML (.kml), and KMZ (.kmz) formats.
await kit.loadFromFile('./data/boundaries.geojson');
await kit.loadFromFile('./data/regions.kml');
await kit.loadFromFile('./data/areas.kmz');loadFromUrl(url: string): Promise<void>
Load spatial data from a remote URL. Automatically detects file format and handles network timeouts.
await kit.loadFromUrl('https://example.com/boundaries.geojson');
await kit.loadFromUrl('https://maps.example.com/regions.kml');isLoaded(): boolean
Check if spatial data has been successfully loaded.
if (kit.isLoaded()) {
console.log('Data is ready for analysis');
}Dataset Information
getDatasetInfo()
Get comprehensive information about the loaded dataset.
const info = kit.getDatasetInfo();
console.log({
source: info.source,
originalFormat: info.originalFormat, // 'geojson' | 'kml' | 'kmz'
featureCount: info.featureCount,
polygonCount: info.polygonCount,
multiPolygonCount: info.multiPolygonCount,
fileSize: info.fileSize,
loadedAt: info.loadedAt
});Feature Access
getFeatures(): SpatialFeature[]
Get all loaded spatial features (Polygons and MultiPolygons only).
const features = kit.getFeatures();
features.forEach((feature, index) => {
console.log(`Feature ${index}: ${feature.type}`);
console.log(`Properties:`, feature.properties);
});getPolygons(): PolygonFeature[]
Get only Polygon features from the dataset.
const polygons = kit.getPolygons();
console.log(`Found ${polygons.length} polygon features`);getMultiPolygons(): MultiPolygonFeature[]
Get only MultiPolygon features from the dataset.
const multiPolygons = kit.getMultiPolygons();
console.log(`Found ${multiPolygons.length} multi-polygon features`);Geofencing Operations
contains(lat: number, lng: number): ContainmentResult
Check if a coordinate point is contained within any polygon feature. Handles polygons with holes and MultiPolygon features.
const result = kit.contains(40.7128, -74.0060);
if (result.isInside) {
console.log(`Point is inside feature ${result.featureIndex}`);
console.log(`Feature properties:`, result.properties);
if (result.geometryType === 'MultiPolygon') {
console.log(`Specific polygon: ${result.polygonIndex}`);
}
}findClosestFeature(lat: number, lng: number)
Find the closest feature to a given coordinate point.
const closest = kit.findClosestFeature(40.7128, -74.0060);
if (closest) {
console.log(`Closest feature: ${closest.featureIndex}`);
console.log(`Distance: ${closest.distance} meters`);
}getAllContainingFeatures(lat: number, lng: number): ContainmentResult[]
Get all features that contain the given coordinate (useful for overlapping polygons).
const allContaining = kit.getAllContainingFeatures(40.7128, -74.0060);
console.log(`Point is contained in ${allContaining.length} features`);
allContaining.forEach(result => {
console.log(`Feature ${result.featureIndex}: ${result.properties.name}`);
});Geometry Calculations
getBoundingBox(): BoundingBox | null
Get the overall bounding box that encompasses all features.
const bbox = kit.getBoundingBox();
if (bbox) {
console.log(`Latitude range: ${bbox.minLat} to ${bbox.maxLat}`);
console.log(`Longitude range: ${bbox.minLng} to ${bbox.maxLng}`);
}getMidpoint(): MidpointResult | null
Calculate the geometric center (midpoint) of all features.
const center = kit.getMidpoint();
if (center) {
console.log(`Dataset center: ${center.latitude}, ${center.longitude}`);
}isWithinBoundingBox(lat: number, lng: number): boolean
Quick check if a coordinate is within the overall dataset bounding box.
const withinBounds = kit.isWithinBoundingBox(40.7128, -74.0060);
console.log(`Point within dataset bounds: ${withinBounds}`);Area Calculations
getArea(): number
Calculate the total area of all features in square meters using spherical geometry.
const totalArea = kit.getArea(); // square meters
console.log(`Total area: ${totalArea.toLocaleString()} m²`);getAreaInUnit(unit): number
Get total area in specific units.
const areaKm2 = kit.getAreaInUnit('square_kilometers');
const areaHectares = kit.getAreaInUnit('hectares');
const areaAcres = kit.getAreaInUnit('acres');
console.log(`Area: ${areaKm2.toFixed(2)} km²`);
console.log(`Area: ${areaHectares.toFixed(2)} hectares`);
console.log(`Area: ${areaAcres.toFixed(2)} acres`);getAreaDetails(): AreaResult
Get detailed area breakdown for each feature.
const details = kit.getAreaDetails();
console.log(`Total area: ${details.totalArea} ${details.unit}`);
details.features.forEach(feature => {
console.log(`Feature ${feature.featureIndex}: ${feature.area} m²`);
// For MultiPolygon features
if (feature.polygonAreas) {
feature.polygonAreas.forEach((polyArea, index) => {
console.log(` Polygon ${index}: ${polyArea} m²`);
});
}
});getFeatureArea(featureIndex: number): number
Calculate area of a specific feature by index.
const feature0Area = kit.getFeatureArea(0);
console.log(`Feature 0 area: ${feature0Area} m²`);getAreaStatistics()
Get comprehensive area statistics for the dataset.
const stats = kit.getAreaStatistics();
console.log({
totalArea: stats.totalArea,
averageArea: stats.averageArea,
largestFeature: stats.largestFeature,
smallestFeature: stats.smallestFeature,
distribution: {
min: stats.areaDistribution.min,
max: stats.areaDistribution.max,
median: stats.areaDistribution.median,
standardDeviation: stats.areaDistribution.stdDev
}
});Utility Methods
validateCoordinates(lat: number, lng: number): boolean
Validate if coordinates are within valid ranges.
const isValid = kit.validateCoordinates(40.7128, -74.0060);
if (!isValid) {
console.log('Invalid coordinates provided');
}🎯 Use Cases
Real Estate Applications
// Load property boundaries
await kit.loadFromFile('./property-boundaries.geojson');
// Check if a house location is within a specific zone
const houseLocation = kit.contains(40.7128, -74.0060);
if (houseLocation.isInside) {
const zone = houseLocation.properties.zoning_type;
console.log(`House is in ${zone} zone`);
}
// Calculate total developable area
const totalArea = kit.getAreaInUnit('acres');
console.log(`Total developable area: ${totalArea} acres`);Delivery & Logistics
// Load delivery zones
await kit.loadFromUrl('https://api.company.com/delivery-zones.geojson');
// Check if delivery address is serviceable
const deliveryLocation = kit.contains(customerLat, customerLng);
if (deliveryLocation.isInside) {
const zone = deliveryLocation.properties.delivery_zone;
const fee = deliveryLocation.properties.delivery_fee;
console.log(`Delivery available in ${zone} for $${fee}`);
} else {
console.log('Sorry, we don\'t deliver to this location');
}Environmental Monitoring
// Load protected areas
await kit.loadFromFile('./protected-areas.geojson');
// Check if coordinates are in protected zone
const location = kit.contains(sensorLat, sensorLng);
if (location.isInside) {
const protectionLevel = location.properties.protection_level;
console.log(`Sensor is in ${protectionLevel} protected area`);
}
// Calculate total protected area
const protectedArea = kit.getAreaInUnit('hectares');
console.log(`Total protected area: ${protectedArea} hectares`);Urban Planning
// Load city districts
await kit.loadFromFile('./city-districts.geojson');
// Analyze district sizes
const areaStats = kit.getAreaStatistics();
console.log(`Largest district: ${areaStats.largestFeature.area / 1000000} km²`);
console.log(`Average district size: ${areaStats.averageArea / 1000000} km²`);
// Find which district a new development is in
const development = kit.contains(newDevLat, newDevLng);
if (development.isInside) {
const district = development.properties.district_name;
console.log(`New development is in ${district}`);
}🔧 Advanced Usage
Working with Multiple Datasets
const residentialKit = new GeoToolKit();
const commercialKit = new GeoToolKit();
await residentialKit.loadFromFile('./residential-zones.geojson');
await commercialKit.loadFromFile('./commercial-zones.geojson');
// Check property zoning
const residentialCheck = residentialKit.contains(lat, lng);
const commercialCheck = commercialKit.contains(lat, lng);
if (residentialCheck.isInside) {
console.log('Property is in residential zone');
} else if (commercialCheck.isInside) {
console.log('Property is in commercial zone');
}Error Handling
try {
await kit.loadFromUrl('https://example.com/data.geojson');
const result = kit.contains(lat, lng);
console.log('Geofencing check completed');
} catch (error) {
if (error.code === 'FILE_NOT_FOUND') {
console.log('Data file not found');
} else if (error.code === 'INVALID_COORDINATES') {
console.log('Invalid coordinates provided');
} else {
console.log('An error occurred:', error.message);
}
}📊 Supported File Formats
| Format | Extension | Description |
|--------|-----------|-------------|
| GeoJSON | .geojson, .json | Standard geospatial JSON format |
| KML | .kml | Keyhole Markup Language |
| KMZ | .kmz | Compressed KML format |
Note: Only Polygon and MultiPolygon geometries are supported. Point, LineString, and other geometry types are filtered out during loading.
🌍 Coordinate System
- Input: WGS84 (EPSG:4326) latitude/longitude coordinates
- Range: Latitude: -90 to 90, Longitude: -180 to 180
- Area Calculations: Uses spherical geometry for accurate Earth surface area calculations
- Distance Calculations: Uses Haversine formula for great circle distances
⚡ Performance
- Bounding Box Optimization: Fast pre-filtering eliminates ~90% of expensive polygon checks
- Spatial Indexing: Efficient point-in-polygon operations
- Memory Efficient: Processes large datasets without excessive memory usage
- TypeScript: Zero runtime overhead with full compile-time type checking
🔗 TypeScript Support
Full TypeScript support with comprehensive type definitions:
import {
GeoToolKit,
type ContainmentResult,
type BoundingBox,
type AreaResult
} from 'geo-toolkits';
const kit = new GeoToolKit();
const result: ContainmentResult = kit.contains(40.7128, -74.0060);
const bbox: BoundingBox | null = kit.getBoundingBox();📄 License
MIT
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📞 Support
For issues and questions, please visit our GitHub repository.
