66
77# ts-maps
88
9- > Modern TypeScript library for creating stunning vector maps
9+ > A zero-dependency, TypeScript-native, interactive mapping library — Mapbox-class features with a Leaflet-style API.
1010
1111## Features
1212
13- - 🗺️ ** Interactive slippy maps** — ` TsMap ` , a modern TypeScript port of
14-
15- Leaflet with fractional zoom, bearing (rotation), pitch (tilt), and
16- unified ` flyTo ` / ` easeTo ` / ` jumpTo ` camera animations.
13+ - 🗺️ ** Interactive slippy maps** — ` TsMap ` gives you fractional zoom, bearing
14+ (rotation), pitch (tilt), and unified ` flyTo ` / ` easeTo ` / ` jumpTo ` camera
15+ animations.
1716
1817- 🧱 ** Vector tiles + style spec** — in-house MVT (` .pbf ` ) decoder, full
19-
2018 subset of the Mapbox GL Style Specification, and an expression engine
2119 that understands ` interpolate ` / ` step ` / ` case ` / ` match ` / ` coalesce `
22- and friends. ` setStyle ` , ` addSource ` , ` addStyleLayer ` , ` setPaintProperty ` ,
23- ` setFilter ` — the works.
20+ and friends. ` setStyle ` , ` addSource ` , ` addLayer ` , ` setPaintProperty ` ,
21+ ` setFilter ` , ` queryRenderedFeatures ` , ` querySourceFeatures ` — the works.
2422
2523- 🏔️ ** 3D** — ` fill-extrusion ` , atmospheric ` setFog ` , a sky layer via
26-
2724 ` setSky ` , and DEM-based terrain via ` setTerrain ` (auto-loads tiles from
2825 a ` raster-dem ` source). A ` CustomLayerInterface ` lets apps render raw
2926 WebGL2 alongside the built-in layers.
3027
31- - 🧭 ** Services** — geocoding (Nominatim, Photon, Mapbox, Maptiler,
28+ - 🌍 ** Globe** — seamless transition between Mercator and globe projection
29+ around zoom 5.5, with an atmosphere halo.
3230
33- Google), directions (OSRM, Valhalla, Mapbox, Google), isochrones, and
34- matrix adapters behind a common interface. Defaults are keyless.
31+ - 🧭 ** Services** — geocoding (Nominatim, Photon, Mapbox, Maptiler,
32+ Google), directions (OSRM, Valhalla, Mapbox, Google), isochrones,
33+ and distance matrix adapters behind a common interface. Defaults are
34+ keyless.
3535
3636- 📴 ** Offline** — IndexedDB-backed ` TileCache ` , ` saveOfflineRegion ` for
37-
3837 pre-fetching bboxes, and a worker pool for off-main-thread tile decode.
3938
40- - 🗺️ ** Legacy ` VectorMap ` ** — choropleth + bubble + heatmap API for the
41-
42- classic "static country map with data overlay" use case .
39+ - 🧩 ** Layer-scoped events ** — ` map.on('click', 'layer-id', handler) ` ,
40+ Mapbox-style: handler only fires when a feature on the named style
41+ layer is hit .
4342
44- - 🎯 ** Zero runtime dependencies, 138 KB gzipped.** Subpath exports
45-
46- (` ts-maps/services ` , ` ts-maps/style-spec ` , …) let you import just the
47- slice you need.
43+ - 🎯 ** Zero runtime dependencies.** Subpath exports (` ts-maps/services ` ,
44+ ` ts-maps/style-spec ` , …) let you import just the slice you need.
4845
4946- 🧩 ** Framework bindings** — ` @ts-maps/react ` , ` @ts-maps/vue ` ,
50-
47+ ` @ts-maps/svelte ` , ` @ts-maps/solid ` , ` @ts-maps/nuxt ` ,
5148 ` @ts-maps/react-native ` (WebView-hosted).
5249
5350- 🔒 ** TypeScript-native** — full ` isolatedDeclarations ` compliance,
54-
5551 strict types, and declaration files for every public module.
5652
5753## Installation
@@ -70,23 +66,17 @@ yarn add ts-maps
7066bun add ts-maps
7167```
7268
73- ### Framework Bindings
69+ ### Framework bindings
7470
7571``` bash
76- # React
77- npm install ts-maps ts-maps-react
78-
79- # Vue
80- npm install ts-maps ts-maps-vue
81-
82- # Nuxt
83- npm install ts-maps-nuxt
72+ npm install ts-maps ts-maps-react # React
73+ npm install ts-maps ts-maps-vue # Vue
74+ npm install ts-maps ts-maps-svelte # Svelte
75+ npm install ts-maps ts-maps-solid # SolidJS
76+ npm install ts-maps-nuxt # Nuxt module
8477```
8578
86- ## Quick Start — modern ` TsMap `
87-
88- The modern API is an interactive slippy map with fractional zoom, bearing,
89- pitch, and layer-based rendering.
79+ ## Quick start
9080
9181``` typescript
9282import ' ts-maps/styles.css'
@@ -126,6 +116,11 @@ vectorTileLayer({
126116 paint: { ' line-color' : ' #6b7280' , ' line-width' : [' interpolate' , [' linear' ], [' zoom' ], 10 , 0.5 , 16 , 3 ] } },
127117 ],
128118}).addTo (map )
119+
120+ // Layer-scoped events (Mapbox-style):
121+ map .on (' click' , ' primary-roads' , (e ) => {
122+ console .log (' road clicked' , e .features [0 ].properties )
123+ })
129124```
130125
131126### 3D — terrain, sky, fog, fill-extrusion
@@ -148,7 +143,7 @@ map.setFog({ color: 'rgb(245, 247, 250)', 'horizon-blend': 0.1 })
148143const m = map .queryTerrainElevation ({ lng: - 74 , lat: 40.7 })
149144```
150145
151- ### Services — geocoding, directions
146+ ### Services — geocoding, directions, matrix
152147
153148``` ts
154149import { services } from ' ts-maps'
@@ -161,6 +156,12 @@ const routes = await directions.getDirections(
161156 [{ lat: 51.5055 , lng: - 0.0754 }, { lat: 51.5074 , lng: - 0.1278 }],
162157 { profile: ' driving' },
163158)
159+
160+ const matrix = services .defaultMatrix () // OSRM /table endpoint
161+ const m = await matrix .getMatrix (
162+ [{ lat: 51.5055 , lng: - 0.0754 }, { lat: 51.5074 , lng: - 0.1278 }, { lat: 51.5155 , lng: - 0.1408 }],
163+ { profile: ' driving' },
164+ )
164165```
165166
166167### Offline tiles
@@ -178,10 +179,17 @@ await saveOfflineRegion({
178179// Later: await cache.close() when the map is torn down.
179180```
180181
182+ ### Static image export
183+
184+ ``` ts
185+ const dataUrl = await map .toDataURL () // PNG data URL of the current view
186+ const blob = await map .toBlob (' image/png' ) // or a Blob
187+ ```
188+
181189### Tree-shaking with subpath imports
182190
183- Only need the services layer? Import from the subpath — about 8 KB
184- gzipped instead of pulling the full 138 KB bundle:
191+ Only need the services layer? Import from the subpath — a small slice
192+ instead of the full bundle:
185193
186194``` ts
187195import { defaultGeocoder } from ' ts-maps/services'
@@ -191,164 +199,7 @@ import { LatLng, LatLngBounds } from 'ts-maps/geo'
191199```
192200
193201Available subpaths: ` services ` , ` style-spec ` , ` storage ` , ` geo ` ,
194- ` geometry ` , ` symbols ` , ` analytics ` , plus each built-in country map
195- (` ts-maps/world ` , ` ts-maps/canada ` , …).
196-
197- ## Legacy ` VectorMap ` (static choropleth maps)
198-
199- ``` typescript
200- import type { VectorMapOptions } from ' ts-maps'
201- import { VectorMap } from ' ts-maps'
202-
203- // Create a map instance
204- const map = new VectorMap ({
205- container: ' map' ,
206- map: ' world' ,
207- theme: ' light' ,
208- style: {
209- regions: {
210- fill: ' #e4e4e4' ,
211- stroke: ' #ffffff' ,
212- strokeWidth: 1 ,
213- },
214- hover: {
215- fill: ' #2ca25f' ,
216- },
217- },
218- })
219-
220- // Add interactivity
221- map .on (' regionClick' , (event , region ) => {
222- console .log (` Clicked: ${region .id } ` )
223- })
224- ```
225-
226- ### Data Visualization
227-
228- ``` typescript
229- import type { DataVisualizationOptions } from ' ts-maps'
230- import { VectorMap } from ' ts-maps'
231-
232- const map = new VectorMap ({
233- container: ' map' ,
234- map: ' world' ,
235- })
236-
237- // Add data visualization
238- const options: DataVisualizationOptions = {
239- scale: [' #e5f5f9' , ' #2ca25f' ], // Color gradient from light blue to green
240- values: {
241- US: 100 ,
242- CA: 80 ,
243- GB: 65 ,
244- },
245- }
246-
247- map .visualizeData (options )
248- ```
249-
250- ### React Component
251-
252- ``` tsx
253- import type { VectorMapProps } from ' ts-maps-react'
254- import { useVectorMap } from ' ts-maps-react'
255-
256- function WorldMap() {
257- const { map, isLoading } = useVectorMap ({
258- map: ' world' ,
259- theme: ' light' ,
260- })
261-
262- return (
263- <div className = " map-container" >
264- { isLoading
265- ? (
266- <div >Loading...</div >
267- )
268- : (
269- <div id = " map" />
270- )}
271- </div >
272- )
273- }
274- ```
275-
276- ### Vue Component
277-
278- ``` vue
279- <script setup lang="ts">
280- import type { VectorMapOptions } from 'ts-maps'
281- import { useVectorMap } from 'ts-maps-vue'
282-
283- const { map, isLoading } = useVectorMap({
284- map: 'world',
285- theme: 'light',
286- })
287- </script>
288-
289- <template>
290- <div class="map-container">
291- <div v-if="isLoading">
292- Loading...
293- </div>
294- <div v-else id="map" />
295- </div>
296- </template>
297- ```
298-
299- ### Nuxt Component
300-
301- For Nuxt applications, first add the module to your ` nuxt.config.ts ` :
302-
303- ``` ts
304- export default defineNuxtConfig ({
305- modules: [
306- ' ts-maps-nuxt'
307- ]
308- })
309- ```
310-
311- Then use the components directly in your Vue templates:
312-
313- ``` vue
314- <script setup lang="ts">
315- import type { MapOptions } from 'ts-maps'
316-
317- const mapOptions: Omit<MapOptions, 'selector'> = {
318- backgroundColor: '#f0f0f0',
319- zoomOnScroll: true,
320- style: {
321- regions: {
322- fill: '#e4e4e4',
323- stroke: '#ffffff',
324- strokeWidth: 1,
325- },
326- },
327- }
328- </script>
329-
330- <template>
331- <VectorMap
332- :options="mapOptions"
333- map-name="world"
334- height="500px"
335- />
336- </template>
337- ```
338-
339- Available components include:
340-
341- - ` VectorMap ` - Generic map component
342- - ` WorldMap ` - World map
343- - ` UnitedStates ` - United States map
344- - ` Canada ` - Canada map
345- - ` Brasil ` - Brazil map
346- - ` Spain ` - Spain map
347- - ` Italy ` - Italy map
348- - ` Russia ` - Russia map
349- - ` Iraq ` - Iraq map
350-
351- See [ Nuxt Components Documentation] [ nuxt-components-documentation ] for detailed usage.
202+ ` geometry ` , ` symbols ` .
352203
353204## Documentation
354205
@@ -371,13 +222,13 @@ cd ts-maps
3712222 . Install dependencies:
372223
373224``` bash
374- pnpm install
225+ bun install
375226```
376227
3772283 . Start development:
378229
379230``` bash
380- pnpm dev
231+ bun run dev
381232```
382233
383234## Changelog
@@ -400,7 +251,7 @@ For casual chit-chat with others using this package:
400251
401252## Postcardware
402253
403- “ Software that is free, but hopes for a postcard.” We love receiving postcards from around the world showing where ` ts-maps ` is being used! We showcase them on our website too.
254+ " Software that is free, but hopes for a postcard." We love receiving postcards from around the world showing where ` ts-maps ` is being used! We showcase them on our website too.
404255
405256Our address: Stacks.js, 12665 Village Ln #2306 , Playa Vista, CA 90094, United States 🌎
406257
@@ -413,7 +264,10 @@ We would like to extend our thanks to the following sponsors for funding Stacks
413264
414265## Credits
415266
416- - [ jsvectormap] [ jsvectormap ]
267+ - [ Leaflet] [ leaflet ] — the module layout and public API shape of the
268+ interactive map API follow its design.
269+ - [ Mapbox GL JS] [ mapbox-gl-js ] — the style spec, expression engine, and
270+ vector-tile renderer are modeled after its design.
417271- [ Chris Breuer] [ chris-breuer ]
418272- [ All Contributors] [ all-contributors ]
419273
@@ -424,14 +278,11 @@ The MIT License (MIT). Please see [LICENSE][license] for more information.
424278Made with 💙
425279
426280<!-- Badges -->
427- [ npm-version-src ] : https://img.shields.io/npm/v/@stacksjs/clarity?style=flat-square
428- [ npm-version-href ] : https://npmjs.com/package/@stacksjs/clarity
429- [ github-actions-src ] : https://img.shields.io/github/actions/workflow/status/stacksjs/clarity/ci.yml?style=flat-square&branch=main
430- [ github-actions-href ] : https://github.com/stacksjs/clarity/actions?query=workflow%3Aci
431-
432- <!-- [codecov-src]: https://img.shields.io/codecov/c/gh/stacksjs/clarity/main?style=flat-square -->
281+ [ npm-version-src ] : https://img.shields.io/npm/v/ts-maps?style=flat-square
282+ [ npm-version-href ] : https://npmjs.com/package/ts-maps
283+ [ github-actions-src ] : https://img.shields.io/github/actions/workflow/status/stacksjs/ts-maps/ci.yml?style=flat-square&branch=main
284+ [ github-actions-href ] : https://github.com/stacksjs/ts-maps/actions?query=workflow%3Aci
433285[ commitizen-friendly ] : https://img.shields.io/badge/commitizen-friendly-brightgreen.svg
434- [ nuxt-components-documentation ] : https://ts-maps.com/components/nuxt
435286[ introduction ] : https://ts-maps.dev/intro
436287[ installation ] : https://ts-maps.dev/install
437288[ usage-guide ] : https://ts-maps.dev/usage
@@ -444,8 +295,9 @@ Made with 💙
444295[ join-the-stacks-discord-server ] : https://discord.gg/stacksjs
445296[ jetbrains ] : https://www.jetbrains.com/
446297[ the-solana-foundation ] : https://solana.com/
447- [ jsvectormap ] : https://github.com/themustafaomar/jsvectormap
298+ [ leaflet ] : https://leafletjs.com/
299+ [ mapbox-gl-js ] : https://github.com/mapbox/mapbox-gl-js
448300[ chris-breuer ] : https://github.com/chrisbbreuer
449301[ all-contributors ] : https://github.com/stacksjs/ts-maps/contributors
450- [ license ] : https://github.com/stacksjs/clarity /blob/main/LICENSE.md
302+ [ license ] : https://github.com/stacksjs/ts-maps /blob/main/LICENSE.md
451303[ commitizen-href ] : http://commitizen.github.io/cz-cli/
0 commit comments