Immobilienangebote auf einer Karte
Wohnungen und Häuser mit ihrem Preis auf der Karte, eine Karte für jedes Objekt mit Link zum Angebot, und Filter für Miete oder Kauf und die Anzahl Zimmer. Derselbe Code funktioniert für Ferienwohnungen, Büros zur Miete oder Occasionen bei mehreren Händlern.
Drei Schritte
- Erstellen Sie ein kostenloses Konto, und erstellen Sie im Dashboard einen Schlüssel vom Typ «Nur Karten», mit Ihrer Website als erlaubtem Referer.
- Kopieren Sie den Code unten, und setzen Sie Ihren Schlüssel ein.
- Füllen Sie
listingsmit Ihren Wohnungen und Häusern, und fügen Sie den Code in Ihre Seite ein.
Der Code
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@6.13.0/dist/maplibre-gl.css">
<style>
#map { height: 520px; border-radius: 8px; }
.filters { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 8px 0; font: 15px system-ui, sans-serif; }
.price { padding: 3px 8px; border: 2px solid #fff; border-radius: 12px; background: #1f5fbf; color: #fff;
font: 600 13px system-ui, sans-serif; white-space: nowrap; cursor: pointer; box-shadow: 0 1px 3px rgb(0 0 0 / 0.3); }
.price.buy { background: #2e7d32; }
</style>
<div class="filters">
<label><input type="radio" name="deal" value="" checked> Alle</label>
<label><input type="radio" name="deal" value="rent"> Mieten</label>
<label><input type="radio" name="deal" value="buy"> Kaufen</label>
<label>Zimmer ab <select id="rooms"><option>1</option><option>2</option><option>3</option><option>4</option><option>5</option></select></label>
</div>
<div id="map"></div>
<script type="module">
import * as maplibregl from "https://unpkg.com/maplibre-gl@6.13.0/dist/maplibre-gl.mjs";
// Ihre Angebote, zum Beispiel aus Ihrer Datenbank oder Ihrem CMS
const listings = [
{ title: "3,5 Zimmer mit Balkon", deal: "rent", price: 2850, rooms: 3.5, url: "/angebote/101", lon: 8.5281, lat: 47.3936 },
{ title: "2,5 Zimmer am See", deal: "rent", price: 2400, rooms: 2.5, url: "/angebote/102", lon: 8.5547, lat: 47.3552 },
{ title: "4,5 Zimmer, Familienwohnung", deal: "rent", price: 3650, rooms: 4.5, url: "/angebote/103", lon: 8.4883, lat: 47.3874 },
{ title: "1,5-Zimmer-Studio", deal: "rent", price: 1690, rooms: 1.5, url: "/angebote/104", lon: 8.5181, lat: 47.3702 },
{ title: "5,5 Zimmer, Dachwohnung", deal: "rent", price: 4900, rooms: 5.5, url: "/angebote/105", lon: 8.5612, lat: 47.3714 },
{ title: "3,5 Zimmer, Neubau", deal: "buy", price: 1290000, rooms: 3.5, url: "/angebote/106", lon: 8.5452, lat: 47.4108 },
{ title: "4,5 Zimmer mit Garten", deal: "buy", price: 1850000, rooms: 4.5, url: "/angebote/107", lon: 8.4962, lat: 47.4031 },
{ title: "6,5-Zimmer-Haus", deal: "buy", price: 2750000, rooms: 6.5, url: "/angebote/108", lon: 8.5735, lat: 47.4061 },
{ title: "2,5 Zimmer, Altstadt", deal: "buy", price: 1150000, rooms: 2.5, url: "/angebote/109", lon: 8.5432, lat: 47.3715 },
{ title: "4,5 Zimmer, Seesicht", deal: "buy", price: 2390000, rooms: 4.5, url: "/angebote/110", lon: 8.5312, lat: 47.3641 }
];
const map = new maplibregl.Map({
container: "map",
style: "https://api.overpass.ch/v1/IHR_SCHLÜSSEL/maps/styles/light.json?lang=de",
center: [8.535, 47.385],
zoom: 12,
cooperativeGestures: true
});
map.addControl(new maplibregl.NavigationControl({ showCompass: false }));
const chf = (n) => "CHF " + n.toLocaleString("de-CH");
// eine Preisbeschriftung auf der Karte für jedes Angebot, mit einem Popup
const markers = listings.map((l) => {
const label = document.createElement("div");
label.className = `price ${l.deal}`;
label.textContent = l.deal === "rent" ? `${chf(l.price)}/Mt.` : `CHF ${(l.price / 1e6).toFixed(2)} Mio.`;
const card = document.createElement("div");
const title = document.createElement("strong");
title.textContent = l.title;
const facts = document.createElement("div");
facts.textContent = `${String(l.rooms).replace(".", ",")} Zimmer · ${chf(l.price)}${l.deal === "rent" ? " im Monat" : ""}`;
const link = document.createElement("a");
link.href = l.url;
link.textContent = "Details";
card.append(title, facts, link);
const marker = new maplibregl.Marker({ element: label })
.setLngLat([l.lon, l.lat])
.setPopup(new maplibregl.Popup({ offset: 18 }).setDOMContent(card));
return { l, marker };
});
// nur die Angebote, die zu den Filtern passen, sind auf der Karte
function filter() {
const deal = document.querySelector("input[name=deal]:checked").value;
const rooms = +document.getElementById("rooms").value;
for (const { l, marker } of markers) {
if ((!deal || l.deal === deal) && l.rooms >= rooms) marker.addTo(map);
else marker.remove();
}
}
for (const input of document.querySelectorAll("input[name=deal], #rooms")) {
input.addEventListener("change", filter);
}
filter();
</script>
Ihre Angebote
Auf einer echten Website kommen die Angebote aus Ihrer Datenbank oder Ihrem CMS. Kann es sie als JSON in derselben Form liefern, ersetzen Sie die Liste durch eine Zeile:
const listings = await (await fetch("/api/angebote.json")).json();
Jedes Angebot braucht title, deal (rent oder buy), price, rooms, url und seine Position als lat und lon (so finden Sie sie). Titel und Angaben kommen als Text in die Karte, nie als HTML; ein Titel kann also nicht als Code laufen.
Was es kostet
Die erste Ansicht von Zürich mit zehn Angeboten lud 6 Kartenkacheln, in einem Fenster von 1100 × 640 Pixeln mit MapLibre GL JS 6.13.0; jedes Verschieben der Karte kostet einige mehr.
| Tarif | Kartenkacheln im Monat | Für eine Firmenwebsite |
|---|---|---|
| Jedes Konto, kostenlos | 100'000 | ✗ Nein, nur für nicht kommerzielle Websites |
| Maps Small, CHF 9 im Monat | 2 Millionen | ✓ Ja |
| Maps Medium, CHF 29 im Monat | 10 Millionen | ✓ Ja |
Preise zuzüglich MWST. Alle Tarife: Maps-Tarife.
Gut zu wissen
- Preise als HTML-Elemente eignen sich für bis zu einige hundert Angebote auf einer Karte. Für tausende zeichnen Sie sie als GeoJSON-Layer mit Gruppen, wie im Filialfinder.
- Die Karte setzt keine Cookies: Weder MapLibre noch unser Kartenserver verwenden welche.
- Die Quellenangabe © OpenStreetMap muss auf der Karte bleiben. Die Schaltfläche (i) in der Ecke öffnet sie.