Quick start
Pick the adapter for your map library, hand the tracker a stream of positions, and call start(). You will have smooth motion in three lines — the rest has production defaults.
Installation
Requires Node.js ≥ 20. Install the core plus the adapter for your map. Each package ships ESM + CJS and full type definitions.
| You're using | Install | Peer |
|---|---|---|
| OpenLayers | npm i @kinesisjs/core @kinesisjs/openlayers | ol ≥ 8 |
| Leaflet | npm i @kinesisjs/core @kinesisjs/leaflet | leaflet ≥ 1.7 |
| Angular | npm i @kinesisjs/angular @kinesisjs/core | @angular/core ≥ 17 |
| Core only | npm i @kinesisjs/core | none |
Vanilla TypeScript + OpenLayers
Build the map, construct an adapter, wrap it in a Tracker, then feed positions from your socket. The Position objects need only an id, lng and lat.
import Map from 'ol/Map';
import View from 'ol/View';
import { Tracker } from '@kinesisjs/core';
import { OpenLayersAdapter, createVehicleStyle } from '@kinesisjs/openlayers';
const map = new Map({ target: 'map', view: new View({ center: [29, 41], zoom: 11 }) });
const tracker = new Tracker({
adapter: new OpenLayersAdapter(map, {
style: createVehicleStyle({ icon: '/car.png', iconScale: 0.7 }),
}),
interpolation: 'adaptive',
ingestThrottle: 100,
});
tracker.start();
const ws = new WebSocket('wss://your-backend/vehicles');
ws.onmessage = (e) => tracker.ingest(JSON.parse(e.data));Leaflet
The Leaflet adapter is a drop-in swap. Two things to remember:
- Import Leaflet's stylesheet:
import 'leaflet/dist/leaflet.css'. - You still pass
{ lng, lat }in your positions — the adapter swaps to Leaflet's[lat, lng]order for you.
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { Tracker } from '@kinesisjs/core';
import { LeafletAdapter } from '@kinesisjs/leaflet';
const map = L.map('map').setView([41, 29], 11); // Leaflet uses [lat, lng]
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
const tracker = new Tracker({
adapter: new LeafletAdapter(map, { warningOpacity: 0.35 }),
interpolation: 'adaptive',
});
tracker.start();Angular
The Angular wrapper hides the manual wiring behind a standalone kinesisMap directive. Bind a Signal or Observable of positions; teardown is handled by DestroyRef.
import { Component, inject } from '@angular/core';
import { KinesisMapDirective } from '@kinesisjs/angular';
@Component({
standalone: true,
imports: [KinesisMapDirective],
template: `<div kinesisMap [positions]="positions" [interpolation]="'adaptive'"
[center]="[29, 41]" [zoom]="11" class="map"></div>`,
})
export class LiveMapComponent {
positions = inject(FeedService).positions; // Signal<Position[]>
}Cleanup
In a plain setup, call tracker.destroy() when the view goes away — it clears slots, tells the adapter to tear down its features, and removes listeners.
window.addEventListener('beforeunload', () => {
tracker.destroy();
map.dispose();
});With the directive you don't call destroy() — it is wired to the component's DestroyRef automatically.