فروشگاهیاب یا همان store locator آن قابلیت کوچکی است که هر کسبوکار چندشعبهای دیر یا زود به آن نیاز پیدا میکند: باکس "نزدیکترین فروشگاه را پیدا کنید" که یک کد پستی را به فهرستی کوتاه و مرتبشده از فروشگاهها روی نقشه تبدیل میکند. از بیرون بیاهمیت به نظر میرسد و مسیر خوشبینانهاش واقعاً ساده است، اما یک locator خوب بیسروصدا سه کار را خوب انجام میدهد: ورودی مکانی نامرتب را میفهمد، شعبهها را بر اساس نزدیکی واقعی رتبهبندی میکند، و نتیجه را روی نقشهای نشان میدهد که آدم بتواند بر اساسش کاری بکند.
در این راهنما توضیح میدهم یک store locator واقعاً چطور کار میکند، چهار گام ساختنش با یک maps API چیست، و کدام جزئیات یک دموی ساده را از چیزی که واقعاً منتشرش میکنید جدا میکند. هر نقشهای در این مقاله با خود MapAtlas API رندر شده است.
یک Store Locator واقعاً چه کار میکند
استایل را کنار بگذارید، store locator یک pipeline با سه مرحله است:
- ورودی بازدیدکننده را geocode کنید. "1012 Amsterdam"، "SW1A 1AA" یا یک موقعیت GPS به اشتراک گذاشته شده، همه باید به یک latitude و longitude واحد تبدیل شوند.
- فروشگاههای نزدیک را رتبهبندی کنید. با آن مختصات و فهرست موقعیت شعبههایتان، نزدیکترینها را در یک شعاع منطقی پیدا کنید.
- نتیجه را render کنید. فروشگاههای مرتبشده را به شکل marker روی نقشه بگذارید، هرکدام با آدرس، ساعت کاری و لینکی به مسیریابی.
نقشه پایین دقیقاً همان مرحله سوم است، رندر شده با tiles های MapAtlas: شش شعبه در مرکز آمستردام که بر اساس فاصله از بازدیدکننده پین شدهاند. اینجا اتفاقاً سوپرمارکت هستند، ولی نقشه فرقی نمیکند که marker ها از یک دیتاست POI بیایند یا از فهرست فروشگاههای خودتان.

ترتیب رنگها همان رتبهبندی است. بازدیدکننده از مرکز نقشه جستجو کرده و marker ها به ترتیب نزدیکترین شعبهها هستند، نزدیکترین اول.
گام ۱: ورودی بازدیدکننده را Geocode کنید
بازدیدکننده یک کد پستی، یک شهر یا یک آدرس کامل تایپ میکند و شما به یک مختصات نیاز دارید. این همان forward geocoding است.
// Turn what the visitor types into a coordinate (autocomplete geocoding)
const res = await fetch(
`https://gateway.mapmetrics-atlas.net/autocomplete/` +
`?token=${API_TOKEN}&text=${encodeURIComponent(query)}` +
`&focus.point.lat=52.37&focus.point.lon=4.89` // bias toward your service area
);
const { features } = await res.json();
const [lon, lat] = features[0].geometry.coordinates; // [lon, lat]
const label = features[0].properties.label; // "Damrak, Amsterdam, North Holland, Netherlands"
دو جزئیات اینجا مهم است. یک focus.point نزدیک منطقه خدمترسانیتان پاس بدهید تا "Cambridge" به همان درستی که میخواهید resolve شود، و حالتی را هم مدیریت کنید که بازدیدکننده بهجای تایپ کردن GPS دستگاهش را به اشتراک میگذارد: آن وقت مختصات را از قبل دارید و این گام کلاً حذف میشود.
گام ۲: فروشگاههایتان را بر اساس فاصله رتبهبندی کنید
حالا مختصات بازدیدکننده را دارید. خود فروشگاهها داده خودتان هستند: فهرستی از شعبهها، هرکدام با یک latitude و longitude، که در دیتابیس شما زندگی میکند. رتبهبندیشان یک محاسبه فاصله خط مستقیم (haversine) است و هیچ API call ای لازم ندارد:
// Your branches, each with a lat/lon. Rank by distance from the visitor.
const ranked = stores
.map(s => ({ ...s, distance_m: haversine(lat, lon, s.lat, s.lon) }))
.sort((a, b) => a.distance_m - b.distance_m)
.slice(0, 6);
یک locator پایه بیشتر از این نمیخواهد. برای یک شبکه بزرگ اول به یک bounding box دور بازدیدکننده فیلتر میکنید تا در هر request فاصله تا تکتک شعبهها را اندازه نگیرید، بعد بازماندهها را مرتب میکنید. خروجی فهرست کوتاهی از نزدیکترین شعبههاست، هرکدام با یک distance_m.
گام ۳: اول فاصله، بعد پالایش با زمان سفر
فاصله خط مستقیم پیشفرض درستی است. سریع است، به call اضافی نیاز ندارد و برای شبکهای متراکم معمولاً درست هم هست. اما نزدیکترین فروشگاه در خط هوایی همیشه سریعترین برای رسیدن نیست: فروشگاهی که ۴۰۰ متر آنطرف رودخانه است میتواند ده دقیقه دور زدن تا نزدیکترین پل باشد.
برای locator ای که در آن "نزدیکترین" واقعاً یعنی "سریعترین برای رسیدن"، چند کاندید برتر را با یک call directions یا matrix بر اساس زمان سفر واقعی دوباره رتبهبندی کنید:
// Re-rank the closest stores by real drive time (MapAtlas Matrix API)
const res = await fetch(`https://gateway.mapmetrics-atlas.net/matrix/?token=${API_TOKEN}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sources: [{ lat, lon }],
targets: top3.map(s => ({ lat: s.lat, lon: s.lon })),
costing: 'auto', // 'auto' | 'bicycle' | 'pedestrian'
}),
});
const { sources_to_targets } = await res.json();
const row = sources_to_targets[0]; // one entry per target, each with .time (seconds)
const byTime = top3
.map((s, i) => ({ ...s, time: row[i].time }))
.sort((a, b) => a.time - b.time);
این کار را فقط برای همان چند کاندید نزدیک انجام میدهید، پس یک call ارزان باقی میماند، نه یکی به ازای هر فروشگاه.
گام ۴: فروشگاهها را روی نقشه Render کنید
گام آخر خود نقشه است. برای هر فروشگاه رتبهبندیشده یک marker بگذارید، یک popup با آدرس و ساعت کاری اضافه کنید، و view را طوری قاب بگیرید که همه نتایج دیده شوند. با یک maps API که tiles، geocoding و search را از یک provider سرو میکند، کل locator از این سر تا آن سر روی یک فروشنده و یک سیستم مختصات میچرخد، و نقشه ابتدای همین مقاله دقیقاً روی همین ساخته شده است.
به هر marker یک popup بدهید با همان چیزهای ضروری که بازدیدکننده برای اقدام لازم دارد: نام، آدرس، فاصله، ساعت کاری، و یک لینک "مسیریابی" که مختصات را تحویل موتور مسیریابی میدهد.
جزئیاتی که یک دمو را از محصول واقعی جدا میکند
نتیجه خالی. یک نفر از منطقهای جستجو میکند که شما هیچ شعبهای در آن ندارید. از همان اول تصمیم بگیرید که شعاع را خودکار بازتر میکنید، تنها نزدیکترین فروشگاه را هرچقدر هم دور باشد نشان میدهید، یا صادقانه میگویید "هیچ فروشگاهی تا ۵۰ کیلومتر نیست".
ساعت کاری. locator ای که فروشگاهی بسته را بهعنوان نزدیکترین گزینه نشان میدهد آزاردهنده است. بر اساس ساعت کاری فیلتر یا flag کنید تا "الان باز است" یک گزینه درجهیک باشد.
ورودی مبهم. "Cambridge" هم در انگلستان هست هم در ماساچوست؛ "Springfield" دهها بار وجود دارد. Country biasing در گام geocode بیشتر این مشکل را برمیدارد، و ارائه autocomplete هنگام تایپ بازدیدکننده باقیاش را.
GPS موبایل و رضایت. روی موبایل قویترین تجربه دکمه "از موقعیت من استفاده کن" است، اما خواندن GPS دستگاه یعنی داده موقعیت مکانی و رضایت لازم دارد. اول بپرسید، و اگر بازدیدکننده نپذیرفت به ورودی متنی برگردید.
حریم خصوصی. موقعیت بازدیدکننده همان لحظهای که به خودش گره بخورد داده شخصی است. on demand ژئوکد کنید، از ذخیره مختصات خام پرهیز کنید، و از یک API مستقر در EU استفاده کنید تا موقعیت هرگز از EEA خارج نشود. برای تصویر کامل راهنمای ما درباره نقشههای سازگار با GDPR را ببینید.
ساخت Store Locator با MapAtlas
MapAtlas کل این pipeline را از یک API و یک سیستم مختصات به شما میدهد. Geocoding API کدهای پستی و شهرها را با country biasing به مختصات تبدیل میکند؛ شما فهرست شعبههای خودتان را در برابر آن مختصات رتبهبندی میکنید؛ API های Directions و Matrix کاندیدهای برتر را بر اساس زمان سفر واقعی دوباره رتبهبندی میکنند؛ و tiles های Dynamic Maps نتیجه را رندر میکنند، دقیقاً همانطور که در این مقاله دیدید. چون همهاش بهصورت پیشفرض داخل EU اجرا میشود، موقعیت بازدیدکننده در EEA میماند و locator بدون کار اضافه سازگار با GDPR باقی میماند.
فرمت کامل request و response هر endpoint در مستندات API مپاطلس هست. Search API هم ارزش نگاه کردن دارد، اگر میخواهید locator نه فقط شعبههای خودتان بلکه points of interest اطراف بازدیدکننده را هم کشف کند.
یک store locator قابلیت کوچکی است با کلی قضاوت خاموش درونش: فهمیدن ورودی مبهم، رتبهبندی بر اساس نزدیکی واقعی، و احترام به این واقعیت که موقعیت مکانی داده شخصی است. این سه را درست انجام دهید و باکس "نزدیکترین فروشگاه را پیدا کنید" دیگر یک فکر بعدی نیست و تبدیل میشود به یکی از پرکاربردترین چیزهای سایتتان.
سوالات متداول
فروشگاهیاب یا store locator چیست؟
فروشگاهیاب همان قابلیت 'نزدیکترین شعبه را پیدا کنید' در سایتهای خردهفروشی و خدماتی است. بازدیدکننده یک کد پستی یا نام شهر وارد میکند یا موقعیتش را به اشتراک میگذارد، و locator نزدیکترین شعبهها را مرتبشده بر اساس فاصله برمیگرداند، هرکدام روی نقشه پین شده همراه با آدرس، ساعت کاری و لینک مسیر. زیر پوستش سه گام است: geocode کردن ورودی به یک مختصات، اجرای nearby search روی فهرست مکانهای شما، و render کردن نتیجه روی نقشه.
چطور یک store locator بسازیم؟
در چهار گام. اول، ورودی بازدیدکننده (کد پستی یا شهر) را با یک geocoding API به latitude و longitude تبدیل کنید. دوم، یک کوئری شعاعی یا nearest-neighbour روی مختصات فروشگاههایتان اجرا کنید تا نزدیکترین شعبهها به دست بیایند. سوم، نتایج را بر اساس فاصله و در صورت نیاز بر اساس زمان رانندگی مرتب کنید. چهارم، فروشگاههای مرتبشده را به شکل marker همراه popup روی نقشه render کنید. یک maps API که geocoding، nearby search و map tiles را از یک provider میدهد، اجازه میدهد هر چهار گام را بدون دوختن چند سرویس به هم انجام دهید.
آیا به store locator API نیاز دارم؟
به geocoding، map tiles و معمولاً رتبهبندی بر اساس زمان سفر نیاز دارید؛ خود فهرست فروشگاهها داده خودتان است. میتوانید فهرست کوتاهی از شعبهها را hardcode کنید و فاصله خط مستقیم را خودتان حساب کنید، اما همان لحظه که جستجوی کد پستی، مرتبسازی بر اساس drive time و یک نقشه render شده بخواهید، یک API که geocoding، matrix و map rendering را از یک provider میدهد شما را از سیمکشی سه فروشنده مختلف و آشتی دادن فرمتهای مختصاتشان نجات میدهد.
store locator چطور نزدیکترین فروشگاهها را رتبهبندی میکند؟
سادهترین رتبهبندی، فاصله خط مستقیم (great-circle) از مختصات بازدیدکننده تا هر فروشگاه است که صعودی مرتب میشود. سریع است و برای شبکههای شهری متراکم کافی. برای تجربه بهتر، چند کاندید برتر را با یک directions یا matrix API بر اساس زمان سفر واقعی دوباره رتبهبندی کنید، چون نزدیکترین فروشگاه در خط مستقیم همیشه سریعترین برای رسیدن نیست، بهخصوص وقتی رودخانه، بزرگراه و خیابانهای یکطرفه وسط کار میآیند.
آیا store locator با GDPR سازگار است؟
میتواند باشد، و جایی که بازدیدکننده در EU است باید باشد. یک store locator یک موقعیت مکانی را پردازش میکند، و موقعیت مکانی وقتی به یک کاربر گره بخورد داده شخصی است. برای سازگار ماندن، بهجای ذخیره مختصات بازدیدکننده آن را on demand ژئوکد کنید، از یک maps API مستقر در EU استفاده کنید تا موقعیت هرگز از EEA خارج نشود، و پیش از خواندن GPS دستگاه رضایت بگیرید. MapAtlas بهصورت پیشفرض کوئریهای موقعیت را داخل EU پردازش میکند.

