Her perakende markası, franchise ve hizmet işletmesi sonunda bir mağaza bulucu ihtiyacı duyar. Bu sayfa müşterilerin zaten satın almak istediklerinde ziyaret ettikleri sayfa, yalnızca hangi şubeye gireceğini bilmeleri gerekir. Bu sayfayı yanlış yapmak gerçek dönüşümlere mal olur. Doğru yapmak çoğu geliştirici beklendiğinden daha basittir.
Standart yaklaşım Google Maps olmuş, ancak bu ölçekte ısırgan bir maliyet yapısı ile gelir. Harita sayfası yükleyen 50.000 aylık ziyaretçiye sahip meşgul bir perakende sitesi, bir gecede yüzlerce Euro'yu harita yükleme ve coğrafya kodlama ücretlerine çekebilir. Artık üretim kullanımı için ücretsiz katman yoktur, fatura opaktır ve AB işletmeleri için ABD merkezli bir haritalama hizmeti kullanmanın GDPR durumu üste ek uyumluluk yükü ekler.
Bu eğitim, MapAtlas Maps API ve Geocoding API kullanarak tam bir mağaza bulucu, etkileşimli harita, adres araması, senkronize liste paneli, işaretleyici kümeleme ve tıklama detay açılır pencereler oluşturur. Framework gerekli değildir. Tam çalışan örnek, kabaca 80 satır HTML ve JavaScript'e uyar. Bunu bir WordPress özel HTML bloğuna, bir Shopify bölümüne veya bunu okuduğunuz aynı öğleden sonra herhangi bir CMS'e bırakabilirsiniz.
Sonunda olacak:
- Mağaza ağınıza odaklanmış oluşturulan bir vektör haritası
- Düşük yakınlaştırmada kümeleme ile bir JSON veri dizisinden yüklenen işaretleyiciler
- Geocoding API tarafından desteklenen bir adres arama çubuğu
- Harita tıklamasında vurgulanan senkronize bir liste paneli
- Mobil duyarlı iki sütunlu bir düzen
Mağaza Bulucu Gerçekten Ne Gerekiyor
Bir kod satırı yazmadan önce, gereksinimleri kesin olmak yardımcı olur. Çalışan bir mağaza bulucu dört hareketli parçaya sahiptir:
- Bir harita karoları işler, pan ve yakınlaştırmayı kabul eder ve işaretleyicileri gösterir.
- Bir arama girişi kullanıcının yazılan adresini koordinatlara coğrafya kodlar, sonra haritayı yeniden merkezler.
- Bir işaretleyici katmanı her mağaza konumunu çizer, düşük yakınlaştırmada yakındaki pimler kümeler ve tıklama yapıldığında detay açılır penceresi açar.
- Bir liste paneli arama yapılan konumdan uzaklığa göre sıralanmış mağazaları gösterir, etkin mağazayı vurgular ve harita ile senkronize olarak kaydırılır.
Bu kadar. Diğer her özellik, yönler, açılış saatleri, envanter stoku, bu dört kişinin üzerine katmanlı bir geliştirmedir. Önce çekirdeği oluşturun.
Adım 1: MapAtlas SDK'yı Yükleyin
MapAtlas Maps API, Mapbox GL JS arayüzü ile uyumludur, bu nedenle herhangi bir Mapbox GL JS eğitimi veya eklentisi doğrudan çalışır. CDN bağlantılarını sayfa <head> öğesine ekleyin:
<link
rel="stylesheet"
href="https://unpkg.com/@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css"
/>
<script src="https://unpkg.com/@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.js"></script>
Npm kullanıyorsanız:
npm install @mapmetrics/mapmetrics-gl
Portal.mapmetrics.org/signup adresinde ücretsiz bir API anahtarı alın. Bir anahtar harita karoları, coğrafya kodlama ve yönlendirmeyi kapsar, çelişmek için ayrı kimlik bilgileri yoktur.
Adım 2: Mağaza Verilerinizi Tanımlayın
Mağaza verileri sadece bir GeoJSON FeatureCollection'ıdır. Her özellik mağazanın koordinatlarını ve açılır pencerenin ihtiyaç duyduğu özellikler (ad, adres, telefon, açılış saatleri) taşır.
const stores = {
type: "FeatureCollection",
features: [
{
type: "Feature",
geometry: { type: "Point", coordinates: [4.9041, 52.3676] },
properties: {
id: 1,
name: "Amsterdam Central",
address: "Stationsplein 12, 1012 AB Amsterdam",
phone: "+31 20 123 4567",
hours: "Mon–Sat 09:00–20:00"
}
},
{
type: "Feature",
geometry: { type: "Point", coordinates: [4.4777, 51.9244] },
properties: {
id: 2,
name: "Rotterdam Lijnbaan",
address: "Lijnbaan 10, 3012 EL Rotterdam",
phone: "+31 10 987 6543",
hours: "Mon–Sat 09:00–21:00"
}
},
{
type: "Feature",
geometry: { type: "Point", coordinates: [5.1214, 52.0907] },
properties: {
id: 3,
name: "Utrecht Centrum",
address: "Oudegracht 45, 3511 AB Utrecht",
phone: "+31 30 555 1234",
hours: "Mon–Sun 10:00–19:00"
}
}
]
};
Üretimde bunu bir API bitiş noktası veya CMS'den alırsınız. Yapı aynı kalır, tek fark verilerin nerede kaynaklandığıdır.
Adım 3: Haritayı Oluşturun ve Kümelenme Ekleyin
Haritayı başlatın, mağaza verilerini kümeleme etkinleştirmeyle bir GeoJSON kaynağı olarak ekleyin ve küme daireleri ve bireysel pin katmanını boyayın. Mapbox GL JS kümeleme, kaynak tanımına yerleştirilmiştir, eklenti gerekmez.
const map = new mapmetricsgl.Map({
container: 'map',
style: 'https://tiles.mapatlas.eu/styles/basic/style.json?key=YOUR_API_KEY',
center: [5.2913, 52.1326], // Centre of the Netherlands
zoom: 7
});
map.on('load', () => {
// Add GeoJSON source with clustering
map.addSource('stores', {
type: 'geojson',
data: stores,
cluster: true,
clusterMaxZoom: 12,
clusterRadius: 50
});
// Cluster circles
map.addLayer({
id: 'clusters',
type: 'circle',
source: 'stores',
filter: ['has', 'point_count'],
paint: {
'circle-color': '#3B82F6',
'circle-radius': ['step', ['get', 'point_count'], 20, 10, 28, 30, 36]
}
});
// Cluster count labels
map.addLayer({
id: 'cluster-count',
type: 'symbol',
source: 'stores',
filter: ['has', 'point_count'],
layout: {
'text-field': '{point_count_abbreviated}',
'text-size': 13
},
paint: { 'text-color': '#ffffff' }
});
// Individual store pins
map.addLayer({
id: 'unclustered-point',
type: 'circle',
source: 'stores',
filter: ['!', ['has', 'point_count']],
paint: {
'circle-color': '#EF4444',
'circle-radius': 8,
'circle-stroke-width': 2,
'circle-stroke-color': '#ffffff'
}
});
});
Bir kümeyi tıklamak, bireysel mağazaları ortaya çıkarmak için yakınlaştırır. Kümelenmemiş bir pimi tıklamak açılır pencereyi açar.
Adım 4: Açılır Pencereleri ve Liste Panelini Bağlayın
Bir kullanıcı bir mağaza pinini tıkladığında, haritada açılır pencereyi gösterin ve liste panelindeki eşleşen kartı vurgulayın. Her iki etkileşim de çift yönlü olmalıdır, bir liste kartını tıklamak da haritayı o mağazaya uçturmalıdır.
// Click unclustered store → open popup + highlight list card
map.on('click', 'unclustered-point', (e) => {
const { coordinates } = e.features[0].geometry;
const { name, address, phone, hours, id } = e.features[0].properties;
new mapmetricsgl.Popup()
.setLngLat(coordinates)
.setHTML(`
<strong>${name}</strong>
<p>${address}</p>
<p>${phone}</p>
<p>${hours}</p>
`)
.addTo(map);
highlightCard(id);
});
// Click cluster → zoom in
map.on('click', 'clusters', (e) => {
const features = map.queryRenderedFeatures(e.point, { layers: ['clusters'] });
const clusterId = features[0].properties.cluster_id;
map.getSource('stores').getClusterExpansionZoom(clusterId, (err, zoom) => {
if (err) return;
map.easeTo({ center: features[0].geometry.coordinates, zoom });
});
});
function highlightCard(id) {
document.querySelectorAll('.store-card').forEach(card => {
card.classList.toggle('active', card.dataset.id === String(id));
});
}
// Build list panel from store data
function buildListPanel() {
const list = document.getElementById('store-list');
stores.features.forEach(({ properties, geometry }) => {
const card = document.createElement('div');
card.className = 'store-card';
card.dataset.id = properties.id;
card.innerHTML = `
<strong>${properties.name}</strong>
<p>${properties.address}</p>
<small>${properties.hours}</small>
`;
card.addEventListener('click', () => {
map.flyTo({ center: geometry.coordinates, zoom: 14 });
highlightCard(properties.id);
});
list.appendChild(card);
});
}
Adım 5: Geocoding API'si ile Adres Araması Ekleyin
Arama çubuğu, kullanıcının yazılan konumunu alır, Geocoding API aracılığıyla coğrafya kodlar, haritayı o noktaya uçturur ve liste panelini mesafeye göre yeniden sıralar.
async function searchLocation(query) {
const url = new URL('https://api.mapatlas.eu/geocoding/v1/search');
url.searchParams.set('text', query);
url.searchParams.set('key', 'YOUR_API_KEY');
const res = await fetch(url);
const data = await res.json();
if (!data.features.length) {
alert('Address not found. Try a city or postcode.');
return;
}
const [lng, lat] = data.features[0].geometry.coordinates;
// Fly map to searched location
map.flyTo({ center: [lng, lat], zoom: 10 });
// Sort list by distance from searched point
const sorted = [...stores.features].sort((a, b) => {
const distA = haversine(lat, lng, a.geometry.coordinates[1], a.geometry.coordinates[0]);
const distB = haversine(lat, lng, b.geometry.coordinates[1], b.geometry.coordinates[0]);
return distA - distB;
});
document.getElementById('store-list').innerHTML = '';
sorted.forEach(feature => {
// Re-render each card (reuse buildListPanel logic)
});
}
function haversine(lat1, lon1, lat2, lon2) {
const R = 6371;
const dLat = ((lat2 - lat1) * Math.PI) / 180;
const dLon = ((lon2 - lon1) * Math.PI) / 180;
const a =
Math.sin(dLat / 2) ** 2 +
Math.cos((lat1 * Math.PI) / 180) *
Math.cos((lat2 * Math.PI) / 180) *
Math.sin(dLon / 2) ** 2;
return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}
document.getElementById('search-btn').addEventListener('click', () => {
const query = document.getElementById('search-input').value.trim();
if (query) searchLocation(query);
});
Adım 6: Mobil Duyarlı Düzen
Mobil cihazda bir mağaza bulucu, yan yana yerine dikey olarak yığılmalıdır, harita üstte, list aşağıda. Yirmi satır CSS, bunu tek bir medya sorgusu kırılma noktası ile işler.
#locator-wrapper {
display: flex;
height: 600px;
gap: 0;
}
#store-list {
width: 300px;
overflow-y: auto;
border-right: 1px solid #e5e7eb;
padding: 12px;
}
#map {
flex: 1;
}
.store-card {
padding: 12px;
border-radius: 8px;
cursor: pointer;
margin-bottom: 8px;
border: 2px solid transparent;
transition: border-color 0.2s;
}
.store-card.active {
border-color: #3B82F6;
background: #EFF6FF;
}
@media (max-width: 640px) {
#locator-wrapper {
flex-direction: column;
height: auto;
}
#store-list {
width: 100%;
border-right: none;
border-top: 1px solid #e5e7eb;
height: 280px;
}
#map {
height: 350px;
}
}
Google Maps ile Faturalama ve GDPR Karşılaştırması
Perakende sitesinde Google Maps çalıştırıyorsanız ve bu ayın faturası neden beklenenden daha yüksek geldiğini merak ediyorsanız, yalnız değilsiniz. Maps JavaScript API, harita yüklemesi başına ücretlendirilir. Places API, otomatik tamamlama oturumu başına ve coğrafya kodlama isteği başına ücretlendirilir. Bu maliyetler hızla bileşikleşir. Ayda 50.000 ziyaretçi yapan ve her ziyarette mağaza bulucu sayfasını bir kez yükleyen bir site, tek bir coğrafya kodlama çağrısından önce yalnızca harita yüklemelerine yaklaşık €140/ay harcayan harcıyor.
MapAtlas sabit aylık planları kullanır. Uyarısız artan yükleme başına veya istek başına ücret yoktur. 2026'da Google Maps API Fiyatlandırması: Gerçek Maliyet Dökümü ve MapAtlas vs. Google Maps karşılaştırması adresinde tam dökümü okuyabilirsiniz.
AB geliştiricileri için GDPR açısı da önemlidir. Google Maps verileri ABD altyapısından yönlendirir. MapAtlas, AB'de barındırılıyor, ISO 27001 sertifikalı ve tüm istekleri AB'de işliyor. Müşteri onayını dikkatle yönetmekte olan perakende işletmeleri için, AB'de yerel bir haritalama sağlayıcısı kullanmak, gizlilik politikanızdan bir tane daha üçüncü taraf transferini kaldırır.
Hepsini Bir Araya Getirmek
Tam mağaza bulucu, HTML yapısı, CSS düzeni, harita başlatma, kümeleme, açılır pencere işleme, liste paneli, arama ve mesafe sıralaması, rahatça bir dosyaya sığar. Yapı şuna benziyor:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Store Locator</title>
<link rel="stylesheet"
href="https://unpkg.com/@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css" />
<script src="https://unpkg.com/@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.js"></script>
<style>
/* paste the CSS from Step 6 here */
</style>
</head>
<body>
<div id="search-bar">
<input id="search-input" type="text" placeholder="Enter your city or postcode…" />
<button id="search-btn">Search</button>
</div>
<div id="locator-wrapper">
<div id="store-list"></div>
<div id="map"></div>
</div>
<script>
// paste store data, map init, clustering, popup, list panel, and search from Steps 2–5
</script>
</body>
</html>
Sonuç, MapAtlas SDK'nın ötesinde sıfır dış bağımlılıkları olan üretime hazır bir mağaza bulucu'dur. Hiçbir yapı adımı, çerçeve ve devam eden faturalama sürprizleri yoktur.
Yönlendirme eklemeniz gerekiyorsa, "konumum'dan bu mağazaya yönelimi al", Routing API kullanıcının koordinatlarını ve mağazanın koordinatlarını alır ve haritada bir çizgi katmanı olarak çizebileceğiniz tam bir ayrıntılı rota döndürür. Web Sitenize Etkileşimli Haritalar Nasıl Eklenir eğitimi bu sonraki adımı ayrıntılı olarak kapsar.
Sonraki Adımlar
- Ücretsiz bir MapAtlas API anahtarı için kaydolun, kredi kartı gerekmez
- Kümeleme, özel stil ve katman seçenekleri için Maps API belgesine göz atın
- Posta kodu araması, ters coğrafya kodlama ve adres otomatik tamamlaması için Geocoding API keşfedin
Sıkça Sorulan Sorular
Google Maps olmadan bir mağaza bulucu inşa edebilir miyim?
Evet. MapAtlas, bir mağaza bulucu'nun ihtiyaç duyduğu her özelliği kapsayan bir Mapbox GL JS uyumlu Maps API ve bir Geocoding API sağlar, etkileşimli harita, adres araması, işaretleyici kümeleme ve açılır pencereler, yükleme başına faturalama olmaksızın ve tam GDPR uyumluluğu ile.
MapAtlas vs Google Maps üzerinde bir mağaza bulucu çalıştırmanın maliyeti nedir?
MapAtlas, eşdeğer kullanım için Google Maps'ten kabaca yüzde 75 daha ucuzdur. Google Maps, harita yükü başına ve coğrafya kodlama isteği başına ücretlendir, bu da meşgul bir perakende sitesinde hızla birikir. MapAtlas, istek başına sürprizler olmadan sabit aylık planları kullanır.
MapAtlas, WordPress ve Shopify'da çalışır mı?
Evet. MapAtlas, hiçbir çerçeve bağımlılığı olmayan saf JavaScript olduğundan, onu bir WordPress özel HTML bloğuna, bir Shopify tema bölümüne veya bir komut dosyası etiketi ve bir div eklemenize izin veren herhangi bir CMS'ye gömebilirsiniz.

