svelobe
v0.0.1
Published
Beautiful, interactive world map visualizations for Svelte 5. Glowing nodes, animated networks, and real-time data overlays—made simple.
Maintainers
Readme
Svelobe
Beautiful interactive world maps for Svelte 5
A clean, type-safe Svelte 5 wrapper around D3.js for stunning geo visualizations.
Why Svelobe?
- 🎯 Smart wrapper - Built on D3.js's battle-tested geo rendering, not reinvented
- ⚡ Svelte 5 native - Leverages runes (
$state,$derived,$effect) for reactive magic - 🔧 100% extensible - Zero hardcoded assumptions, completely data-driven
- 🎨 Beautiful by default - Glowing nodes, smooth animations, elegant interactions
- 📦 Fully typed - Complete TypeScript support with no
anytypes - 🔍 Professional zoom - Icons stay perfectly sized at all zoom levels (industry-standard behavior)
- 🚀 Production ready - Optimized rendering, proper layering, clean API
Installation
npm install svelobeQuick Start
<script>
import { WorldMap } from 'svelobe';
const locations = [
{
id: 'ny',
name: 'New York',
country: 'USA',
latitude: 40.7128,
longitude: -74.006
},
{
id: 'london',
name: 'London',
country: 'UK',
latitude: 51.5074,
longitude: -0.1278
}
];
const connections = [
{
id: 'route-1',
from: locations[0],
to: locations[1],
status: 'active',
transportMode: 'flight'
}
];
</script>
<WorldMap {locations} {connections} />That's it! You now have a gorgeous, interactive world map with:
- Animated flight path with airplane icon
- Glowing, pulsing nodes
- Zoom and pan
- Hover tooltips
- Click interactions
Features
🚀 Transport Icons
Built-in Font Awesome icons for common transport modes:
transportMode: 'flight'; // ✈️ Airplane
transportMode: 'ship'; // 🚢 Ship
transportMode: 'truck'; // 🚛 Truck
transportMode: 'train'; // 🚆 Train
transportMode: 'drive'; // 🚗 Car💬 Custom Tooltips
// Static tooltip
{
tooltip: 'Flight BA117 • 7h 30m';
}
// Dynamic function - access connection data
{
tooltip: (connection) =>
`${connection.from.name} → ${connection.to.name}\n` +
`Cost: $${connection.data.cost}\n` +
`ETA: ${connection.data.eta}`;
}🎨 Line Styles & Status
// Automatic status-based styling
status: 'active'; // → Blue, solid line, animated flow
status: 'pending'; // → Orange, dashed line
status: 'completed'; // → Green, dotted line
// Custom styling
lineStyle: 'dashed'; // Override line style
width: 3; // Custom line thickness🔍 Professional Zoom Behavior
Icons and UI elements stay perfectly sized at all zoom levels:
- Uses
vector-effect="non-scaling-stroke"for paths (SVG standard) - Counter-scales icons/nodes with smart clamping
- Subtle 10% size boost when zoomed in for better visibility
- Smooth zoom from 0.5x to 8x
Zoom controls:
- Mouse wheel - Zoom in/out
- Click & drag - Pan
- Double-click - Zoom to point
- Pinch - Mobile touch zoom
Configuration
interface WorldMapConfig {
width?: number; // Default: 1200
height?: number; // Default: 600
showGrid?: boolean; // Show lat/long grid lines
showLabels?: boolean; // Show location names on hover
interactive?: boolean; // Enable all interactions
animationSpeed?: number; // 1-10, controls flow animation
glowIntensity?: number; // 1-10, controls node glow
theme?: 'light' | 'dark'; // Color scheme
enableZoom?: boolean; // Enable zoom and pan
minZoom?: number; // Minimum zoom level (0.5)
maxZoom?: number; // Maximum zoom level (8)
}TypeScript Types
All types are fully extensible with [key: string]: any:
interface MapLocation {
id: string;
name: string;
country: string;
latitude: number;
longitude: number;
type?: 'origin' | 'destination' | 'hub';
[key: string]: any; // Add your own properties!
}
interface MapConnection {
id: string;
from: MapLocation;
to: MapLocation;
status?: 'active' | 'pending' | 'completed';
transportMode?: 'flight' | 'drive' | 'ship' | 'train' | 'truck';
lineStyle?: 'solid' | 'dashed' | 'dotted';
width?: number;
tooltip?: string | ((connection: MapConnection) => string);
[key: string]: any; // Store your custom data!
}Real-World Examples
Corporate Travel Dashboard
<script>
import { WorldMap } from 'svelobe';
const travelRequests = await fetch('/api/travel').then((r) => r.json());
const locations = extractUniqueLocations(travelRequests);
const connections = travelRequests.map((tr) => ({
id: tr.trNumber,
from: findLocation(tr.origin),
to: findLocation(tr.destination),
status: tr.status === 'approved' ? 'active' : 'pending',
transportMode: 'flight',
tooltip: `${tr.trNumber} • ${tr.traveler}\n${tr.purpose} • ${formatCurrency(tr.cost)}`,
lineStyle: tr.status === 'completed' ? 'dotted' : 'solid',
data: tr // Store full travel request
}));
</script>
<WorldMap
{locations}
{connections}
config={{ showGrid: true, theme: 'dark' }}
onconnectionclick={(conn) => showTravelDetails(conn.data)}
/>E-Commerce Logistics
<script>
const shipments = [
{
id: 'SH-2024-001',
from: { name: 'Shanghai', lat: 31.2304, lng: 121.4737 },
to: { name: 'Los Angeles', lat: 34.0522, lng: -118.2437 },
method: 'ship',
container: 'CN2024A',
eta: '25 days',
units: 10000
}
];
const connections = shipments.map((s) => ({
id: s.id,
from: s.from,
to: s.to,
transportMode: s.method,
status: 'active',
tooltip: `${s.container} • ${s.units} units\nETA: ${s.eta}`,
width: 3, // Thicker line for ocean freight
data: s
}));
</script>
<WorldMap {locations} {connections} />Interactive Clicks
<script>
function handleNodeClick(location) {
console.log('Clicked city:', location.name);
// Access custom data
showCityDashboard(location.id);
}
function handleConnectionClick(connection) {
// Access your stored data
const shipment = connection.data;
openTrackingPanel(shipment.trackingNumber);
}
</script>
<WorldMap
{locations}
{connections}
onnodeclick={handleNodeClick}
onconnectionclick={handleConnectionClick}
/>Architecture
User Data (locations, connections)
↓
WorldMap.svelte (Svelte 5 wrapper)
↓
D3.js (renders everything)
↓
Beautiful SVG visualizationSvelobe doesn't render - it orchestrates:
- Svelte 5 - State management with runes
- D3.js - Creates all SVG elements, handles projections, paths, zoom
- You - Provide the data, we handle the visualization
Development
Testing
npm run test:unit # Unit tests (watch mode)
npm test # All tests (unit + e2e)
npm run test:e2e # Playwright E2E tests
npm run check # Type checking33 tests covering:
- ✅ Utility functions (projections, paths, distances)
- ✅ Type definitions (fully type-safe)
- ✅ Component rendering (Svelte + browser tests)
Storybook
Explore live examples:
npm run storybookIncluded stories:
- Basic usage
- Transport modes
- Corporate travel dashboard
- Light theme
- High intensity glow
- Zoom controls
Tech Stack
| Library | Purpose |
| ------------------------------- | --------------------------------------- |
| d3-geo | Geographic projections (Mercator, etc.) |
| d3-selection | DOM manipulation |
| d3-zoom | Zoom and pan behavior |
| topojson-client | World map data conversion |
| @fortawesome/fontawesome-free | Transport icons |
| svelte@^5.0.0 | Component framework (peer dependency) |
Design Principles
- Leverage, don't rebuild - D3.js handles complex geo algorithms
- Wrapper, not reimplementation - Clean Svelte API around proven libraries
- Zero hardcoding - Users provide all data (locations, connections, tooltips)
- Fully extensible - All interfaces support custom properties
- Type-safe - No
anytypes, full TypeScript support - Professional UX - Icons/labels stay constant size during zoom (like Google Maps)
Browser Support
Works in all modern browsers with SVG support:
- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- Mobile browsers (iOS Safari, Chrome Mobile)
Performance
- ✅ Efficient D3 rendering
- ✅
vector-effect="non-scaling-stroke"for optimal zoom performance - ✅ Minimal re-renders (Svelte reactivity)
- ✅ No unnecessary DOM manipulations
Contributing
Contributions welcome! We believe in:
- Using battle-tested libraries over custom implementations
- Clean, typed code
- Extensibility over assumptions
License
MIT © 2024
Built with ❤️ on the shoulders of giants: D3.js + Svelte 5
