Skip to content

Commit a4f1a08

Browse files
committed
chore: wip
1 parent 12f0cad commit a4f1a08

192 files changed

Lines changed: 2073 additions & 18926 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## About
44

5-
A zero-dependency TypeScript library for creating interactive SVG-based vector maps with data visualization support (choropleth maps, heat maps, bubble charts). It provides multiple map projections (Mercator, Equal Earth), built-in world and country maps, interactive legends and tooltips, and official React, Vue, and Nuxt bindings. Inspired by jsvectormap.
5+
A zero-dependency, TypeScript-native interactive mapping library. Mapbox-class feature set (vector tiles + Mapbox GL Style Spec subset, expressions, 3D fill-extrusion + terrain + fog/sky, globe projection, collision-aware symbol labels, WebGL renderer) with a Leaflet-style ergonomic API. Ships geocoding / directions / matrix adapters, offline tile caching, and official React, Vue, Svelte, Solid, Nuxt, and React-Native bindings.
66

77
## Linting
88

README.md

Lines changed: 61 additions & 209 deletions
Original file line numberDiff line numberDiff line change
@@ -6,52 +6,48 @@
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
7066
bun 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
9282
import '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 })
148143
const m = map.queryTerrainElevation({ lng: -74, lat: 40.7 })
149144
```
150145

151-
### Services — geocoding, directions
146+
### Services — geocoding, directions, matrix
152147

153148
```ts
154149
import { 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
187195
import { defaultGeocoder } from 'ts-maps/services'
@@ -191,164 +199,7 @@ import { LatLng, LatLngBounds } from 'ts-maps/geo'
191199
```
192200

193201
Available 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
371222
2. Install dependencies:
372223

373224
```bash
374-
pnpm install
225+
bun install
375226
```
376227

377228
3. 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

405256
Our 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.
424278
Made 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

Comments
 (0)