📚معرفی و نصب

Leaflet.js یکی از محبوب‌ترین کتابخانه‌های جاوااسکریپت برای نمایش نقشه‌های تعاملی در مرورگر است. برخلاف Google Maps که نیازمند API key است، Leaflet با منابع باز مثل OpenStreetMap کار می‌کند.

~42KBحجم gzip شده
📱
Mobile-Firstبهینه برای موبایل
🔌
+200 Pluginاکوسیستم غنی
🔒
بدون API Keyکاملاً رایگان

مقایسه با Google Maps

ویژگیLeafletGoogle Maps
قیمترایگان کاملپولی بعد از سهمیه
حریم خصوصیبدون trackingGoogle tracking
حجم~42KB~300KB+
سفارشی‌سازیبسیار بالامحدود
Tile Sourcesهر منبعیفقط Google
API Keyنیاز ندارداجباری

نصب

<!-- ۱. CSS حتماً قبل از JS -->
<link rel="stylesheet" href="leaflet.min.css">

<!-- ۲. JS -->
<script src="leaflet.min.js"></script>

ساختار اولیه

<!-- div با ارتفاع مشخص -- اجباری! -->
<div id="map" style="height: 400px;"></div>

<script>
// ایجاد نقشه روی تهران
const map = L.map('map').setView([35.6892, 51.3890], 13);

// افزودن لایه tile از OpenStreetMap
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: '© OpenStreetMap contributors'
}).addTo(map);
</script>
💡 نکته: div نقشه حتماً باید ارتفاع مشخص داشته باشد — height: 400px — وگرنه نقشه نمایش داده نمی‌شود!
⚠ آفلاین: کتابخانه Leaflet کاملاً آفلاین کار می‌کند. اما Tile‌های OpenStreetMap نیاز به اینترنت دارند. برای استفاده کاملاً آفلاین می‌توان tile‌های محلی دانلود کرد.

🌎نقشه پایه

مختصات و سطح Zoom

// setView([latitude, longitude], zoomLevel)
const map = L.map('map').setView([35.6892, 51.3890], 13);
// تهران: lat=35.6892, lng=51.3890
// zoom: 1 (کل جهان) تا 19 (ساختمان)
Zoomنمایش
1 – 3کل جهان / قاره‌ها
4 – 6کشورها
7 – 10استان‌ها و شهرها
11 – 14بخش‌های شهر
15 – 17خیابان‌ها
18 – 19ساختمان‌ها

Tile Layer‌های رایج

// OpenStreetMap (رایگان)
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: '© OpenStreetMap contributors',
  maxZoom: 19
}).addTo(map);

// OpenTopoMap — نقشه توپوگرافی (رایگان)
L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
  attribution: '© OpenTopoMap',
  maxZoom: 17
}).addTo(map);

// CartoDB Dark (رایگان)
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
  attribution: '© CartoDB'
}).addTo(map);
▶ دمو: نقشه ایران — شهرهای مهم (نیاز به اینترنت برای Tiles)

📍Markers و Popups

Marker پایه

// اضافه کردن marker
const marker = L.marker([35.6892, 51.3890]).addTo(map);

// Popup به marker
marker.bindPopup('<b>تهران</b><br>پایتخت ایران').openPopup();

// یا chain style
L.marker([35.6892, 51.3890])
  .addTo(map)
  .bindPopup('<b>تهران</b>')
  .openPopup();

// Popup مستقل (بدون marker)
L.popup()
  .setLatLng([35.6892, 51.3890])
  .setContent('سلام از تهران!')
  .openOn(map);

// Tooltip (نمایش دائم)
marker.bindTooltip('تهران', { permanent: true });

Custom Icon

const myIcon = L.icon({
  iconUrl:     'marker-icon.png',
  iconSize:    [38, 95],    // عرض، ارتفاع
  iconAnchor:  [19, 95],    // نقطه اتصال (پایین وسط)
  popupAnchor: [0, -95]     // موقعیت popup
});

L.marker([35.6892, 51.3890], { icon: myIcon }).addTo(map);

// DivIcon — آیکون با HTML/CSS دلخواه
const divIcon = L.divIcon({
  html: '<div style="background:#e74c3c;color:white;padding:4px 8px;border-radius:4px">📍</div>',
  iconSize: [30, 30],
  className: ''
});
▶ دمو: ۵ شهر ایران با Marker و Popup

روی هر marker کلیک کنید تا اطلاعات شهر نمایش داده شود.

🔷اشکال هندسی

// دایره (Circle)
L.circle([35.6892, 51.3890], {
  radius:      5000,         // شعاع به متر
  color:       '#e74c3c',
  fillColor:   '#e74c3c',
  fillOpacity: 0.3
}).addTo(map).bindPopup('دایره ۵ کیلومتری');

// Polyline — خط شکسته
L.polyline([
  [35.6892, 51.3890],   // تهران
  [35.7200, 51.4000],   // شمال
  [35.7448, 51.3753]    // شمال‌غرب
], { color: '#3498db', weight: 3, dashArray: '8,4' }).addTo(map);

// Polygon — چندضلعی
L.polygon([
  [35.7, 51.3], [35.7, 51.5],
  [35.6, 51.5], [35.6, 51.3]
], { color: '#27ae60', fillOpacity: 0.25 }).addTo(map);

// Rectangle — مستطیل
L.rectangle([[35.6, 51.3], [35.8, 51.6]], {
  color: '#9b59b6', fillOpacity: 0.15
}).addTo(map);

// CircleMarker — دایره با اندازه ثابت (px نه متر)
L.circleMarker([35.6892, 51.3890], {
  radius: 10, color: '#e67e22', fillOpacity: 0.8
}).addTo(map);
▶ دمو: اشکال هندسی روی تهران

Events و تعامل

رویدادهای نقشه

// کلیک روی نقشه
map.on('click', function(e) {
  const lat = e.latlng.lat.toFixed(6);
  const lng = e.latlng.lng.toFixed(6);
  L.popup().setLatLng(e.latlng)
    .setContent(`📍 ${lat}, ${lng}`)
    .openOn(map);
});

// تغییر zoom
map.on('zoomend', function() {
  console.log('Zoom:', map.getZoom());
});

// حرکت نقشه
map.on('moveend', function() {
  const c = map.getCenter();
  console.log('مرکز:', c.lat, c.lng);
});

// رویداد روی Marker
marker.on('click', function(e) { console.log('marker کلیک شد'); });
marker.on('mouseover', function() { this.openPopup(); });
marker.on('mouseout',  function() { this.closePopup(); });
▶ دمو: کلیک روی نقشه — مختصات نمایش داده می‌شود
روی نقشه کلیک کنید...

📚Layers و Controls

LayerGroup و FeatureGroup

// LayerGroup — گروه‌بندی چند لایه
const cityLayer = L.layerGroup([
  L.marker([35.6892, 51.3890]).bindPopup('تهران'),
  L.marker([32.6539, 51.6660]).bindPopup('اصفهان')
]).addTo(map);

// FeatureGroup — عملیات مشترک روی همه
const group = L.featureGroup([
  L.marker([35.6892, 51.3890]),
  L.circle([35.6892, 51.3890], { radius: 3000 })
]).addTo(map);

// zoom به کل group
map.fitBounds(group.getBounds());

Layer Control و Scale

const streets = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
const topo    = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png');

// کنترل سوئیچ لایه‌ها
L.control.layers({
  '🗺️ نقشه خیابانی': streets,
  '🏔️ توپوگرافی': topo
}).addTo(map);

// Scale control
L.control.scale({ imperial: false }).addTo(map);
▶ دمو: Layer Control + Scale — سوئیچ نقشه‌ها

از کنترل گوشه بالا‌راست برای سوئیچ بین نقشه خیابانی و توپوگرافی استفاده کنید.

📄GeoJSON

GeoJSON یک فرمت استاندارد JSON برای داده‌های جغرافیایی است. Leaflet از آن به‌صورت بومی پشتیبانی می‌کند.

⚠ ترتیب مختصات: در GeoJSON ترتیب [longitude, latitude] است اما در Leaflet [latitude, longitude] است. دقت کنید!
const geojsonData = {
  type: "FeatureCollection",
  features: [
    {
      type: "Feature",
      properties: { name: "تهران", population: 15000000 },
      geometry: {
        type: "Point",
        coordinates: [51.3890, 35.6892]  // [lng, lat]
      }
    },
    {
      type: "Feature",
      properties: { name: "ناحیه مرکزی" },
      geometry: {
        type: "Polygon",
        coordinates: [[[50,34],[56,34],[56,38],[50,38],[50,34]]]
      }
    }
  ]
};

L.geoJSON(geojsonData, {
  // popup برای هر feature
  onEachFeature: function(feature, layer) {
    if (feature.properties.name)
      layer.bindPopup(feature.properties.name);
  },
  // تبدیل Point به CircleMarker
  pointToLayer: function(feature, latlng) {
    return L.circleMarker(latlng, {
      radius: 10, fillColor: '#e74c3c', fillOpacity: 0.8
    });
  },
  // استایل Polygon
  style: function(feature) {
    if (feature.geometry.type === 'Polygon')
      return { color: '#3498db', fillOpacity: 0.1 };
  }
}).addTo(map);
▶ دمو: نمایش GeoJSON

پلاگین‌های محبوب

پلاگینکاربرد
Leaflet.markerclusterگروه‌بندی marker در zoom پایین
Leaflet.heatنقشه حرارتی (heatmap)
Leaflet-Routing-Machineمسیریابی بین نقاط
Leaflet.drawرسم اشکال روی نقشه
Leaflet.Searchجستجوی مکان
Leaflet.fullscreenتمام‌صفحه کردن نقشه

متدهای مفید

متدهای نقشه

// دریافت اطلاعات فعلی
map.getCenter()            // مرکز نقشه — {lat, lng}
map.getZoom()              // سطح zoom فعلی
map.getBounds()            // محدوده نمایش — LatLngBounds

// تغییر نما
map.setView([35.69, 51.39], 13)
map.panTo([35.69, 51.39])  // حرکت بدون تغییر zoom
map.flyTo([35.69, 51.39], 13) // انیمیشن پرواز
map.setZoom(15)
map.zoomIn() / map.zoomOut()
map.fitBounds([[29,44],[39,63]])  // zoom خودکار به محدوده ایران

// مختصات ↔ pixel
map.latLngToContainerPoint([35.69, 51.39])
map.containerPointToLatLng([100, 200])

فاصله بین دو نقطه

const tehran   = L.latLng(35.6892, 51.3890);
const esfahan  = L.latLng(32.6539, 51.6660);

const dist = tehran.distanceTo(esfahan);
console.log(Math.round(dist / 1000) + ' کیلومتر'); // ~340 کیلومتر

// محاسبه zoom مناسب برای fit کردن دو نقطه
const bounds = L.latLngBounds(tehran, esfahan);
map.fitBounds(bounds, { padding: [50, 50] });
💡 خلاصه Leaflet در یک نگاه:
  • L.map('id').setView([lat,lng], zoom) — ساخت نقشه
  • L.tileLayer(url).addTo(map) — لایه پایه
  • L.marker([lat,lng]).addTo(map) — نشانگر
  • L.circle / L.polygon / L.polyline — اشکال
  • L.geoJSON(data).addTo(map) — داده جغرافیایی
  • map.on('click', fn) — رویداد
  • L.control.layers({...}).addTo(map) — سوئیچ لایه

🚀زمین بازی کد (Playground)

کد Leaflet را همین‌جا اجرا کن و نقشه را زنده ببین. مارکر، اشکال و رویدادها را تغییر بده و ▶ اجرا را بزن. نسخهٔ ۱.۹.۴ آفلاین است؛ تایل‌های نقشه به اینترنت نیاز دارند (آفلاین خاکستری می‌ماند) ولی مارکرها و اشکال در هر حالت نمایش داده می‌شوند.