Skip to content

a0a7/fastgeotoolkit

fastgeotoolkit npmDocsDemo

Rust TestsJavaScript TestsCodeQLLicense

fastgeotoolkit is a library for GPS data processing and route density mapping. The core of the library is written in Rust and it's compiled to webassembly for use in the browser and node.

Note

Only Javascript/Typescript is supported at the moment. Rust and Python releases are planned.

What it does

The main use case is creating route heatmaps where you want to see which paths/routes are used most frequently. You can test this functionality at https://fastgeotoolkit-demo.pages.dev/, using either your own data or sample data. This is an example of what a heatmap produced using fastgeotoolkit looks like: https://i.ibb.co/MxpHbVdp/image.png

However, beyond this primary usecase, this library helps you:

  • Analyze GPS tracks (distance, statistics, intersections)
  • Decode Google polylines
  • Convert between GPS data formats

Documentation

Docs are available at https://fastgeotoolkit.pages.dev/.

Installation

npm install fastgeotoolkit # or  pnpm i fastgeotoolkit

Basic Usage

import{processGpxFiles}from'fastgeotoolkit';// Process GPX files into a heatmapconstgpxFile1=newUint8Array(/* your GPX file data */);constgpxFile2=newUint8Array(/* another GPX file */);constresult=awaitprocessGpxFiles([gpxFile1,gpxFile2]);// Result contains tracks with frequency dataconsole.log(`Found ${result.tracks.length} unique track segments`);console.log(`Maximum frequency: ${result.max_frequency}`);result.tracks.forEach(track=>{console.log(`Track with ${track.coordinates.length} points, used ${track.frequency} times`);});

Working with Polylines

import{decodePolyline,processPolylines}from'fastgeotoolkit';// Decode a single polylineconstcoords=awaitdecodePolyline('_p~iF~ps|U_ulLnnqC_mqNvxq`@');console.log(coords);// [[lat, lng], [lat, lng], ...]// Process multiple polylines into a heatmapconstpolylines=['_p~iF~ps|U_ulLnnqC_mqNvxq`@','another_encoded_polyline','yet_another_one'];constheatmap=awaitprocessPolylines(polylines);

Track Analysis

import{calculateTrackStatistics,validateCoordinates}from'fastgeotoolkit';constcoordinates=[[37.7749,-122.4194],[37.7849,-122.4094]];// [lat, lng] pairs// Get basic statisticsconststats=awaitcalculateTrackStatistics(coordinates);console.log(`Distance: ${stats.distance_km.toFixed(2)} km`);console.log(`${stats.point_count} GPS points`);console.log(`Bounds: ${stats.bounding_box}`);// [min_lat, min_lng, max_lat, max_lng]// Validate coordinatesconstvalidation=awaitvalidateCoordinates(coordinates);console.log(`${validation.valid_count} out of ${validation.total_count} coordinates are valid`);if(validation.issues.length>0){console.log('Issues found:',validation.issues);}

Data Conversion

import{coordinatesToGeojson,exportToGpx}from'fastgeotoolkit';// Convert to GeoJSONconstgeojson=awaitcoordinatesToGeojson(coordinates,{name: 'My Route',activity: 'cycling'});// Export multiple tracks as GPXconsttracks=[track1_coordinates,track2_coordinates];constgpxString=awaitexportToGpx(tracks,{creator: 'My App',name: 'Route Collection'});

Real-world Example

Here's an example of how you might use this in a web app to show route popularity:

import{processGpxFiles}from'fastgeotoolkit';asyncfunctioncreateHeatmap(gpxFiles){// Convert files to Uint8ArrayconstfileBuffers=awaitPromise.all(gpxFiles.map(file=>file.arrayBuffer().then(buf=>newUint8Array(buf))));// Process into heatmapconstheatmap=awaitprocessGpxFiles(fileBuffers);// Render on map (example with any mapping library)heatmap.tracks.forEach(track=>{constintensity=track.frequency/heatmap.max_frequency;constcolor=`hsl(${(1-intensity)*240}, 100%, 50%)`;// blue to reddrawLineOnMap(track.coordinates,{color: color,weight: Math.max(2,intensity*8)});});}// Usagedocument.getElementById('file-input').addEventListener('change',async(e)=>{constfiles=Array.from(e.target.files);awaitcreateHeatmap(files);});

TypeScript Support

The library includes full TypeScript definitions:

importtype{Coordinate,// [number, number] - [lat, lng]HeatmapResult,//{tracks: HeatmapTrack[], max_frequency: number }HeatmapTrack,//{coordinates: Coordinate[], frequency: number }TrackStatistics,// distance, bounds, point count, etc.ValidationResult,// validation results with issuesFileInfo// file format information}from'fastgeotoolkit';

JavaScript Utilities

For simple operations that don't rely on WebAssembly:

import{utils}from'fastgeotoolkit';// Basic coordinate validationif(utils.isValidCoordinate(37.7749,-122.4194)){console.log('Valid GPS coordinate');}// Calculate distance between two pointsconstdistance=utils.haversineDistance(37.7749,-122.4194,37.7849,-122.4094);console.log(`Distance: ${distance.toFixed(2)} km`);// Get bounding boxconstbounds=utils.getBoundingBox(coordinates);console.log(`Bounds: ${bounds}`);// [min_lat, min_lng, max_lat, max_lng]

Browser vs Node.js

Works the same in both environments:

// Browserimport{processGpxFiles}from'fastgeotoolkit';// Node.js const{ processGpxFiles }=require('fastgeotoolkit');// or with ES modules:import{processGpxFiles}from'fastgeotoolkit';

Performance Notes

  • WebAssembly provides near-native performance for GPS processing
  • Large datasets (thousands of tracks) process quickly
  • First function call initializes WebAssembly (adds ~100ms startup time)

Common Issues

"Cannot resolve module" errors: Make sure your bundler supports WebAssembly. Modern bundlers (Vite, Webpack 5+, etc.) work out of the box.

TypeScript errors: Ensure you're using TypeScript 4.0+ for proper WebAssembly typing support.

File reading: Remember to convert File objects to Uint8Array:

constbuffer=awaitfile.arrayBuffer();constuint8Array=newUint8Array(buffer);

Development & Maintenance

This project consists of Rust code compiled to WebAssembly with JavaScript/TypeScript bindings.

Project Structure

  • /src/ - Rust source code
  • /dist/javascript/ - JavaScript/TypeScript bindings and NPM package
  • /dist/wasm/ - Generated WebAssembly files
  • /demo/ - Demo application (SvelteKit)
  • /docs/ - Generated documentation

Note

/dist/python and /dist/rust/ contain WIP releases for their respective ecosystems, but they're not in working order yet.

Compiling Rust to WebAssembly

To compile the Rust code to WebAssembly:

# Install wasm-pack if you haven't already cargo install wasm-pack # Build the WebAssembly module wasm-pack build --target web --out-dir dist/wasm

Building the NPM Package

To build the complete NPM package with all bindings:

# From the root directory npm run build # Or build individual components: npm run build:wasm # Build WebAssembly npm run build:js # Build JavaScript bindings npm run build:docs # Build documentation

Building Documentation

The documentation is generated using TypeDoc and can be built locally:

cd dist/javascript npm run docs

This will generate the documentation website in the docs/ directory.

Testing

# Run Rust tests cargo test# Run JavaScript testscd dist/javascript npm test

License

MIT