static-map-generator
v0.0.2
Published
Node.js library for generating static map images using OpenStreetMap tiles with markers, paths, and smart bounds fitting
Maintainers
Readme
Static Map Generator
A Node.js library for generating static map images using OpenStreetMap tiles with markers, paths, and smart bounds fitting.
Features
- 🗺️ Generate static map images from OpenStreetMap tiles
- 📍 Add custom markers with labels and colors
- 🛣️ Draw paths/routes from coordinate arrays
- 📏 Smart bounds fitting with auto-calculated center and zoom
- 🖼️ Support for different image formats (PNG, JPG)
- 📱 High-resolution output (Retina support)
- 💻 Full TypeScript support
- ⚙️ Customizable map size and zoom levels
Installation
npm install static-map-generatorUsage
Basic Usage
import { StaticMap } from 'static-map-generator';
const map = new StaticMap({
center: { lat: 35.6762, lng: 139.6503 }, // Tokyo
zoom: 12,
size: { width: 800, height: 600 },
format: 'png'
});
const imageBuffer = await map.render();
// Save or use the image bufferWith Markers
import { StaticMap } from 'static-map-generator';
const map = new StaticMap({
center: { lat: 35.6762, lng: 139.6503 },
zoom: 12,
size: { width: 800, height: 600 },
markers: [
{
coordinate: { lat: 35.6762, lng: 139.6503 },
color: '#FF0000',
size: 'large',
label: 'Tokyo'
},
{
coordinate: { lat: 35.6585, lng: 139.7454 },
color: '#00FF00',
size: 'medium',
label: 'Skytree'
}
]
});
const imageBuffer = await map.render();Auto-fit with Bounds (New!)
Automatically calculate center and zoom to fit a specified area:
import { StaticMap } from 'static-map-generator';
const map = new StaticMap({
bounds: {
north: 35.7000, // Northern latitude
south: 35.6000, // Southern latitude
east: 139.8000, // Eastern longitude
west: 139.7000 // Western longitude
},
size: { width: 800, height: 600 },
padding: 20, // Padding from bounds (pixels)
markers: [
{ coordinate: { lat: 35.6762, lng: 139.6503 }, label: 'Tokyo' }
]
});
const imageBuffer = await map.render();
// Get auto-calculated values
console.log('Center:', map.getCalculatedCenter());
console.log('Zoom:', map.getCalculatedZoom());API
StaticMap(options)
Creates a new StaticMap instance.
Two Usage Patterns
Pattern 1: Manual Center & Zoom
const map = new StaticMap({
center: { lat: 35.6762, lng: 139.6503 },
zoom: 12,
size: { width: 800, height: 600 }
});Pattern 2: Auto-fit with Bounds
const map = new StaticMap({
bounds: {
north: 35.7000,
south: 35.6000,
east: 139.8000,
west: 139.7000
},
size: { width: 800, height: 600 }
});Options
Required (choose one):
center+zoom: Manual positioningbounds: Auto-calculated positioning
Common Options:
size(Size): Width and height of the output imageformat(string, optional): Output format ('png' or 'jpg', default: 'png')scale(number, optional): Scale factor (1 or 2, default: 1)markers(Marker[], optional): Array of markers to displaytileServer(string, optional): Custom tile server URL
Bounds-specific Options:
padding(number, optional): Padding from bounds in pixels (default: 20)
Types
interface Coordinate {
lat: number;
lng: number;
}
interface Size {
width: number;
height: number;
}
interface Bounds {
north: number; // Northern latitude
south: number; // Southern latitude
east: number; // Eastern longitude
west: number; // Western longitude
}
interface Marker {
coordinate: Coordinate;
color?: string;
size?: 'small' | 'medium' | 'large';
label?: string;
}
interface StaticMapOptions {
center?: Coordinate; // Required when bounds not specified
zoom?: number; // Required when bounds not specified (0-18)
bounds?: Bounds; // Alternative to center/zoom
size: Size;
format?: 'png' | 'jpg';
scale?: 1 | 2;
markers?: Marker[];
tileServer?: string;
padding?: number; // Used with bounds (default: 20)
}Methods
render(): Promise<Buffer>
Renders the map and returns a Promise that resolves to an image buffer.
getCalculatedCenter(): Coordinate
Returns the center point used for rendering (useful when using bounds).
getCalculatedZoom(): number
Returns the zoom level used for rendering (useful when using bounds).
Examples
Complete Usage Examples
1. Basic Map with Manual Center/Zoom
const { StaticMap } = require('static-map-generator');
const fs = require('fs');
const map = new StaticMap({
center: { lat: 35.6762, lng: 139.6503 }, // Tokyo Station
zoom: 12,
size: { width: 800, height: 600 },
format: 'png'
});
const imageBuffer = await map.render();
fs.writeFileSync('tokyo.png', imageBuffer);2. Auto-fit Map using Bounds
const { StaticMap } = require('static-map-generator');
const fs = require('fs');
const map = new StaticMap({
bounds: {
north: 35.7000, // Northern boundary
south: 35.6000, // Southern boundary
east: 139.8000, // Eastern boundary
west: 139.7000 // Western boundary
},
size: { width: 800, height: 600 },
padding: 30, // 30px padding from boundaries
markers: [
{
coordinate: { lat: 35.6762, lng: 139.6503 },
color: '#FF0000',
size: 'large',
label: 'Tokyo'
}
]
});
const imageBuffer = await map.render();
fs.writeFileSync('tokyo-bounds.png', imageBuffer);
// Get the auto-calculated values
console.log('Auto-calculated center:', map.getCalculatedCenter());
console.log('Auto-calculated zoom:', map.getCalculatedZoom());3. High-Resolution Map with Multiple Markers
const { StaticMap } = require('static-map-generator');
const fs = require('fs');
const map = new StaticMap({
center: { lat: 35.6762, lng: 139.6503 },
zoom: 14,
size: { width: 400, height: 300 },
scale: 2, // High-resolution (800x600 actual pixels)
format: 'png',
markers: [
{
coordinate: { lat: 35.6762, lng: 139.6503 },
color: '#FF0000',
size: 'large',
label: 'Tokyo Station'
},
{
coordinate: { lat: 35.6585, lng: 139.7454 },
color: '#00FF00',
size: 'medium',
label: 'Skytree'
},
{
coordinate: { lat: 35.6586, lng: 139.7016 },
color: '#0000FF',
size: 'small',
label: 'Asakusa'
}
]
});
const imageBuffer = await map.render();
fs.writeFileSync('tokyo-hd.png', imageBuffer);4. Area Coverage Map (Tourist Route)
const { StaticMap } = require('static-map-generator');
const fs = require('fs');
// Define tourist spots
const touristSpots = [
{ lat: 35.6762, lng: 139.6503, name: 'Tokyo Station' },
{ lat: 35.6585, lng: 139.7454, name: 'Skytree' },
{ lat: 35.6586, lng: 139.7016, name: 'Asakusa' },
{ lat: 35.6785, lng: 139.6823, name: 'Imperial Palace' }
];
// Calculate bounds to include all spots
const lats = touristSpots.map(spot => spot.lat);
const lngs = touristSpots.map(spot => spot.lng);
const map = new StaticMap({
bounds: {
north: Math.max(...lats) + 0.005, // Add small margin
south: Math.min(...lats) - 0.005,
east: Math.max(...lngs) + 0.005,
west: Math.min(...lngs) - 0.005
},
size: { width: 1000, height: 800 },
padding: 40,
markers: touristSpots.map((spot, index) => ({
coordinate: { lat: spot.lat, lng: spot.lng },
color: ['#FF0000', '#00FF00', '#0000FF', '#FF6600'][index],
size: 'large',
label: spot.name
}))
});
const imageBuffer = await map.render();
fs.writeFileSync('tokyo-tourist-route.png', imageBuffer);
console.log(`Map covers area from zoom level: ${map.getCalculatedZoom()}`);
console.log(`Centered at: ${map.getCalculatedCenter().lat}, ${map.getCalculatedCenter().lng}`);Running the Examples
# Install dependencies
npm install
# Build the library
npm run build
# Run basic demo
node generate-image-now.js
# Run bounds demo
node bounds-demo.js
# Run zoom level test
node zoom-test.jsDemo Files
generate-image-now.js- Basic image generation demobounds-demo.js- Bounds-based auto-calculation demozoom-test.js- Zoom level testingdemo-viewer.html- Browser preview (no execution required)
Tips
Choosing Zoom Levels
- 0-2: Continental/country level
- 3-6: City/region level
- 7-12: Urban area level
- 13-16: Neighborhood/building level
- 17-18: Building detail level (maximum)
Using Bounds vs Center/Zoom
- Use bounds when you want to ensure specific areas are visible
- Use center/zoom when you want precise control over the view
- Bounds automatically calculates the optimal zoom to fit the area
Performance Tips
- Smaller image sizes render faster
- Lower zoom levels require fewer tiles
- Use appropriate padding with bounds to avoid edge cropping
License
MIT
