@synapxlab/atlas
v0.1.0
Published
Zero-dependency SVG world map — pan, zoom, markers. Designed as a building block for ChronoMap (historical atlas).
Downloads
61
Maintainers
Readme
@synapxlab/atlas
Zero-dependency SVG world map — pan, zoom, markers, level-of-detail. TypeScript + SCSS.
Atlas renders any GeoJSON FeatureCollection as an interactive SVG world
map. It handles pan (drag), zoom (wheel + pinch), markers
(lat/lng points with click callbacks) and LOD (auto-swap between
multiple geometry resolutions based on the current zoom). No D3, no
Leaflet, no MapLibre — just SVG and vanilla TS.
Designed as a building block for ChronoMap (historical atlas) but usable standalone for any geo-visualisation.
Install
npm install @synapxlab/atlasQuick start
import { Atlas } from '@synapxlab/atlas';
import '@synapxlab/atlas/style';
const atlas = new Atlas({
container: document.getElementById('atlas')!,
world: myGeoJSON, // optional
markers: [
{ lat: 48.85, lng: 2.35, label: 'Paris', color: '#dc2626' },
{ lat: 35.68, lng: 139.69, label: 'Tokyo', color: '#16a34a' },
],
onMarkerClick: m => console.log('clicked', m),
onView: v => console.log('view', v), // fired on pan/zoom
});Features
Level of Detail (LOD)
Pass multiple geometry sources sorted by minZoom. Atlas auto-swaps
to the highest-resolution source whose threshold is reached.
new Atlas({
container,
worlds: [
{ minZoom: 1, data: world110m }, // always active
{ minZoom: 3, data: world50m }, // swaps in at zoom ≥ 3
{ minZoom: 6, data: world10m }, // swaps in at zoom ≥ 6
],
});
// Later — replace LOD set entirely
atlas.setWorlds([{ minZoom: 1, data: customGeoJSON }]);Projections
Currently supported: equirectangular (default, linear lng/lat → x/y)
and mercator (Web Mercator, clipped at ±85° latitude).
new Atlas({ container, projection: 'mercator' });Pan & zoom
- Drag = pan (mouse, touch, pen via Pointer Events)
- Mouse wheel = zoom in/out
- Two-finger pinch = zoom on touch
atlas.setView({ center: [lng, lat], zoom })for programmatic moves
Markers
atlas.setMarkers([{ lat, lng, label, color, id, radius }]);
atlas.addMarker({ lat, lng, label, id: 'tambora' });
atlas.removeMarker('tambora');
atlas.getMarkers();Click emits both the onMarkerClick(m) callback and a bubbling
CustomEvent('markerclick', { detail: m }) on the container.
Theme
'light' (default), 'dark', or 'auto' (follows prefers-color-scheme).
API
class Atlas {
constructor(options: AtlasOptions);
// Pan/zoom
setView(view: Partial<AtlasView>): void;
setCenter(center: LngLat): void;
setZoom(zoom: number): void;
getView(): AtlasView;
// Geometry
setWorld(world: GeoJSONFeatureCollection | null): void;
setWorlds(worlds: AtlasWorldSource[]): void;
// Markers
setMarkers(markers: AtlasMarker[]): void;
addMarker(m: AtlasMarker): void;
removeMarker(id: string): void;
getMarkers(): AtlasMarker[];
// Lifecycle
render(): void;
destroy(): void;
}Where to get world data
Atlas is geometry-agnostic. Common sources:
world-atlas— 110m / 50m / 10m TopoJSON (Natural Earth)- Natural Earth — free vector + raster
- CShapes 2.0 — historical borders 1886-present
- GADM — modern administrative areas
TopoJSON can be converted to GeoJSON using
topojson-client — Atlas
expects GeoJSON.
Status
Early release — public API may evolve. Markers stable, pan/zoom stable, LOD stable. Time-varying geometries (borders that change over a date cursor) are planned for v0.3.
License
MIT © synapxLab
