Fuzzy Location
Display approximate location as a circle area instead of an exact pin Each library has its own approach: here's how they compare.
Quick Recommendations
Leaflet — The better fit for simple privacy circles using L.circle with radius in meters: the API directly supports geographic circles.
MapLibre GL JS — Ideal when the fuzzy area needs data-driven styling or must integrate with other GeoJSON layers in a WebGL-rendered map.
MapTiler SDK — Gives MapTiler SDK users MapLibre's circle polygon approach, plus simplified initialization.
At a Glance
| Leaflet | MapLibre | SDK | |
|---|---|---|---|
| Coordinates | [lat, lng] | [lng, lat] | [lng, lat] |
| Rendering | DOM + Canvas (2D) | WebGL (GPU, 60fps) | WebGL (GPU, 60fps) |
| Bundle size | ~42 KB gzipped | ~250 KB gzipped | ~280 KB gzipped (includes MapLibre) |
| Learning curve | Easiest (simple API, great tutorials) | Moderate (source/layer model, expressions) | Easy (MapLibre API with convenience helpers) |
| 3D support | No native 3D (2D only) | Full: terrain, fill-extrusion, globe, sky | Full (same as MapLibre) |
| Code lines | 15 | 24 | 24 |
Code Snippets
Click a library to expand its code. Each snippet shows only the core logic: the scaffold handles HTML boilerplate.
Leaflet15 linesShow code
const map = L.map('map').setView([51.5074, -0.1278], 13);
L.tileLayer('https://api.maptiler.com/maps/streets-v4/256/{z}/{x}/{y}.png?key=YOUR_MAPTILER_KEY', {
tileSize: 256,
attribution: '© <a href="https://www.maptiler.com/">MapTiler</a> © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap contributors</a>'
}).addTo(map);
const realLat = 51.5074, realLng = -0.1278;
const offsetLat = realLat + (Math.random() - 0.5) * 0.01;
const offsetLng = realLng + (Math.random() - 0.5) * 0.01;
L.circle([offsetLat, offsetLng], {
radius: 500,
color: '#2196F3',
fillColor: '#2196F3',
fillOpacity: 0.15,
weight: 2
}).addTo(map).bindPopup('Approximate location');MapLibre GL JS24 linesShow code
const map = new maplibregl.Map({
container: 'map',
style: 'https://api.maptiler.com/maps/streets-v4/style.json?key=YOUR_MAPTILER_KEY',
center: [14.42, 50.08],
zoom: 13
});
map.addControl(new maplibregl.NavigationControl());
function makeCircle(center, radiusKm, steps = 64) {
const coords = [];
for (let i = 0; i <= steps; i++) {
const angle = (i / steps) * Math.PI * 2;
const dx = radiusKm / (111.32 * Math.cos(center[1] * Math.PI / 180));
const dy = radiusKm / 110.574;
coords.push([center[0] + Math.cos(angle) * dx, center[1] + Math.sin(angle) * dy]);
}
return { type: 'Feature', geometry: { type: 'Polygon', coordinates: [coords] } };
}
map.on('load', () => {
map.addSource('fuzzy', { type: 'geojson', data: makeCircle([14.42, 50.08], 0.5) });
map.addLayer({ id: 'fuzzy-fill', type: 'fill', source: 'fuzzy',
paint: { 'fill-color': '#2196F3', 'fill-opacity': 0.15 } });
map.addLayer({ id: 'fuzzy-border', type: 'line', source: 'fuzzy',
paint: { 'line-color': '#2196F3', 'line-width': 2, 'line-dasharray': [4, 2] } });
});MapTiler SDK24 linesShow code
maptilersdk.config.apiKey = 'YOUR_MAPTILER_KEY';
const map = new maptilersdk.Map({
container: 'map',
style: maptilersdk.MapStyle.STREETS,
center: [2.3522, 48.8566],
zoom: 13
});
function fuzzyCircle(center, radiusKm, points = 64) {
const coords = [];
for (let i = 0; i <= points; i++) {
const angle = (i / points) * 2 * Math.PI;
const dx = radiusKm / (111.32 * Math.cos(center[1] * Math.PI / 180));
const dy = radiusKm / 110.574;
coords.push([center[0] + dx * Math.cos(angle), center[1] + dy * Math.sin(angle)]);
}
return { type: 'Feature', geometry: { type: 'Polygon', coordinates: [coords] } };
}
map.on('load', () => {
map.addSource('zone', { type: 'geojson', data: fuzzyCircle([2.3522, 48.8566], 0.5) });
map.addLayer({ id: 'zone-fill', type: 'fill', source: 'zone',
paint: { 'fill-color': '#9C27B0', 'fill-opacity': 0.2 } });
map.addLayer({ id: 'zone-border', type: 'line', source: 'zone',
paint: { 'line-color': '#9C27B0', 'line-width': 2, 'line-dasharray': [4, 2] } });
});Things to Know
Implementation-specific details that matter for fuzzy location.
L.circle() natively accepts a radius in meters and renders a geographic circle; no need to generate polygon geometry.
MapLibre has no native geographic circle: you must generate a polygon approximation (e.g., 64-sided) from center and radius.
Same polygon-based circle approach as MapLibre; the circle must be generated as GeoJSON geometry.
Which Library to Use?
Display an approximate location as a fuzzy L.circle area instead of an exact marker pin for privacy protection.
The better fit for simple privacy circles using L.circle with radius in meters: the API directly supports geographic circles.
Show an approximate location as a fuzzy circle polygon layer instead of an exact point for privacy protection.
Ideal when the fuzzy area needs data-driven styling or must integrate with other GeoJSON layers in a WebGL-rendered map.
Display an approximate location as a fuzzy circle polygon layer instead of an exact point for privacy.
Gives MapTiler SDK users MapLibre's circle polygon approach, plus simplified initialization.
Build Maps with AI
Generate code like these examples using mapping library skills in your IDE.