This is from chatgpt (this is the unedited paste, it is not formatted correctly)
1) Fastest: native OSM iframe (single pin)
<!-- 600×450 map centered on lat,lon with one pin -->
<iframe
width="600"
height="450"
frameborder="0"
scrolling="no"
src="https://www.openstreetmap.org/export/embed.html?layer=mapnik&marker=37.7749,-122.4194#map=12/37.7749/-122.4194">
</iframe>
<br>
<small><a href="https://www.openstreetmap.org/?mlat=37.7749&mlon=-122.4194#map=12/37.7749/-122.4194">View on OSM</a></small>
Notes: one marker only; popup shows on click. No multi-pin. No custom labels. Minimal control. Cheap and dirty.
2) Multiple pins + labels, still iframe: uMap
Go to umap.openstreetmap.fr → “Create a map”, add markers with names/descriptions, style them, save.
“Share” → copy the iframe.
Result: many pins, popups, per-pin titles, even GeoJSON import. Zero code. Not ugly.
3) Proper control (multi pins, autolabels, styling): Leaflet (not iframe)
<!doctype html>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<div id="map" style="height:480px;"></div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
// respect OSM tile usage policy; add attribution
const map = L.map('map').setView([37.7749, -122.4194], 12);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution:
'© <a href="https://www.openstreetmap.org/copyright">OSM</a> contributors'
}).addTo(map);
const places = [
{name:'Mission', coords:[37.7597,-122.4148], label:'Mission District'},
{name:'Presidio', coords:[37.7989,-122.4662], label:'The Presidio'},
{name:'SoMa', coords:[37.7813,-122.4056], label:'SoMa'}
];
// marker + always-visible label via DivIcon
places.forEach(p => {
const marker = L.marker(p.coords).addTo(map).bindPopup(`<b>${p.name}</b><br>${p.label}`);
L.marker(p.coords, {
interactive:false,
icon: L.divIcon({
className:'osm-label',
html:`<span>${p.label}</span>`,
iconSize:null
})
}).addTo(map);
});
const css = document.createElement('style');
css.textContent = `
.osm-label span{
position:relative; left:10px; top:-8px;
background:#fff; padding:2px 6px; border-radius:4px;
font:13px/1.2 system-ui; box-shadow:0 1px 3px rgba(0,0,0,.25)
}
`;
document.head.appendChild(css);
</script>
You get: multiple pins, popups, always-visible labels, full styling. Yeah, it’s not an iframe—because iframes are training wheels.
Do you like what you are reading?. Subscribe to receive updates.
Unsubscribe anytime
Powered by Seed HypermediaOpen App