Skip to main content
JavaScript में क्लस्टरिंग के साथ रियल एस्टेट प्रॉपर्टी मैप बनाएं
Tutorials

JavaScript में क्लस्टरिंग के साथ रियल एस्टेट प्रॉपर्टी मैप बनाएं

MapAtlas Maps API की मदद से सादे JavaScript या React में प्राइस लेबल मार्कर, क्लस्टरिंग, पता खोज और प्राइस रेंज फ़िल्टर वाला प्रॉपर्टी लिस्टिंग मैप बनाएं।

Brent van der Heiden10 min read
#real estate map#property map#map clustering#javascript#proptech#maps api

संपत्ति खोज एक स्थानिक समस्या है। खरीदार और किरायेदार पड़ोस, यात्रा के समय और स्कूलों की निकटता के संदर्भ में सोचते हैं, न कि पिन कोड और सड़क की सूची के। मानचित्र-पहले इंटरफेस लोगों के खोजने के तरीके से मेल खाता है, क्योंकि यह उपयोगकर्ताओं को मूल्य, बेडरूम या किसी अन्य विशेषता से फ़िल्टर करने से पहले अपनी खोज को स्थानिक रूप से लंगर करने देता है।

यह ट्यूटोरियल एक उत्पादन-तैयार संपत्ति सूची मानचित्र बनाता है: कम ज़ूम पर क्लस्टर किए गए मार्कर, व्यक्तिगत मार्कर पर मूल्य लेबल, सूची विवरण के साथ क्लिक-टू-पॉपअप, एक पोस्टकोड खोज जो मानचित्र को फिर से केंद्रित करती है, और एक मूल्य श्रेणी स्लाइडर जो दृश्यमान सूचियों को वास्तविक समय में फ़िल्टर करता है। React घटक खुद लगभग 65 लाइनों का है, और परतों तथा क्लिक हैंडलर के साथ पूरा निर्माण लगभग 150 लाइनों तक पहुंचता है। यदि आप कोई ढांचा नहीं चाहते हैं तो वही तर्क वेनिला JavaScript में काम करता है।

आपको EU PropTech प्लेटफॉर्म के लिए GDPR दायित्वों के बारे में एक नोट भी मिलेगा, क्योंकि संपत्ति खोज द्वारा उत्पन्न स्थान डेटा व्यक्तिगत डेटा है और इसे उचित रूप से संभाला जाना चाहिए।

यदि आप मानचित्र API के लिए नए हैं, तो अपनी वेबसाइट में इंटरैक्टिव मानचित्र कैसे जोड़ें ट्यूटोरियल इससे पहले की मूल बातें कवर करता है।

संपत्ति डेटा संरचना

प्रत्येक सूची को निर्देशांक, एक मूल्य और पॉपअप के लिए पर्याप्त मेटाडेटा की आवश्यकता है। इसे GeoJSON FeatureCollection के रूप में रखें, यह बिना रूपांतरण के सीधे मानचित्र स्रोत में प्लग होता है।

const properties = {
  type: "FeatureCollection",
  features: [
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [4.8952, 52.3702] },
      properties: {
        id: "prop-001",
        price: 485000,
        bedrooms: 3,
        sqm: 112,
        address: "Keizersgracht 142, Amsterdam",
        type: "apartment",
        status: "for-sale"
      }
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [4.9123, 52.3601] },
      properties: {
        id: "prop-002",
        price: 1250,
        bedrooms: 2,
        sqm: 78,
        address: "Sarphatistraat 58, Amsterdam",
        type: "apartment",
        status: "for-rent"
      }
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [4.8801, 52.3780] },
      properties: {
        id: "prop-003",
        price: 720000,
        bedrooms: 4,
        sqm: 195,
        address: "Herengracht 380, Amsterdam",
        type: "house",
        status: "for-sale"
      }
    }
  ]
};

एक वास्तविक प्लेटफॉर्म में यह सरणी आपकी सूची API से आती है, मानचित्र लोड पर एक fetch कॉल या क्वेरी पैरामीटर परिवर्तन।

मानचित्र सेटअप करना

अपनी संपत्ति बाजार पर एक केंद्रीय दृश्य के साथ मानचित्र को प्रारंभ करें। MapAtlas Maps API Mapbox GL JS के अनुकूल है, इसलिए प्रारंभिकरण कॉल Mapbox के लिए लिखे गए समान है, MapAtlas टाइल URL के साथ।

import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';

const map = new mapmetricsgl.Map({
  container: 'map',
  style: 'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_STYLE_ID/style.json&token=YOUR_API_KEY',
  center: [4.9041, 52.3676],
  zoom: 13
});

एक चमकीली, कम-कंट्रास्ट शैली विशेष रूप से संपत्ति मानचित्रों के लिए अच्छी तरह से काम करती है, हल्का आधार मूल्य लेबल और रंगीन मार्कर को दृश्य अव्यवस्था के बिना अलग होने देता है।

मूल्य लेबल के साथ क्लस्टरिंग

संपत्ति मानचित्र के लिए मुख्य UI पैटर्न व्यक्तिगत मार्कर पर मूल्य लेबल और क्लस्टर सर्कल पर गणना बुलबुले दिखाना है। cluster: true स्रोत विकल्प स्वचालित रूप से पास के बिंदुओं को समूहित करता है। आप क्लस्टर और व्यक्तिगत मार्कर के लिए अलग-अलग परतें जोड़ते हैं।

map.on('load', () => {
  map.addSource('properties', {
    type: 'geojson',
    data: properties,
    cluster: true,
    clusterMaxZoom: 14,
    clusterRadius: 60
  });

  // Cluster circles, size scales with listing count
  map.addLayer({
    id: 'clusters',
    type: 'circle',
    source: 'properties',
    filter: ['has', 'point_count'],
    paint: {
      'circle-color': '#2563EB',
      'circle-radius': [
        'step', ['get', 'point_count'],
        22, 5, 30, 20, 38
      ],
      'circle-stroke-width': 3,
      'circle-stroke-color': '#ffffff'
    }
  });

  // Cluster count labels
  map.addLayer({
    id: 'cluster-label',
    type: 'symbol',
    source: 'properties',
    filter: ['has', 'point_count'],
    layout: {
      'text-field': '{point_count_abbreviated}',
      'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],
      'text-size': 14
    },
    paint: { 'text-color': '#ffffff' }
  });

  // Individual property markers, white circle with price text
  map.addLayer({
    id: 'property-price',
    type: 'symbol',
    source: 'properties',
    filter: ['!', ['has', 'point_count']],
    layout: {
      'text-field': [
        'concat',
        '€',
        ['to-string', ['round', ['/', ['get', 'price'], 1000]]],
        'k'
      ],
      'text-font': ['DIN Offc Pro Bold', 'Arial Unicode MS Bold'],
      'text-size': 12
    },
    paint: {
      'text-color': '#1e293b',
      'text-halo-color': '#ffffff',
      'text-halo-width': 2
    }
  });
});

क्लिक इंटरैक्शन

क्लस्टर पर क्लिक करने से मानचित्र अपनी व्यक्तिगत सूचियों को प्रकट करने के लिए ज़ूम हो जाता है। किसी व्यक्तिगत संपत्ति पर क्लिक करने से एक विस्तृत पॉपअप खुलता है।

// Zoom into clicked cluster
map.on('click', 'clusters', (e) => {
  const [feature] = map.queryRenderedFeatures(e.point, { layers: ['clusters'] });
  map.getSource('properties').getClusterExpansionZoom(
    feature.properties.cluster_id,
    (err, zoom) => {
      if (!err) map.easeTo({ center: feature.geometry.coordinates, zoom });
    }
  );
});

// Detail popup for individual listing
map.on('click', 'property-price', (e) => {
  const { address, price, bedrooms, sqm, status, id } = e.features[0].properties;
  const coords = e.features[0].geometry.coordinates.slice();
  const formattedPrice = status === 'for-rent'
    ? `€${price.toLocaleString()}/mo`
    : `€${price.toLocaleString()}`;

  new mapmetricsgl.Popup({ offset: 10 })
    .setLngLat(coords)
    .setHTML(`
      <div style="min-width:200px">
        <strong style="font-size:15px">${formattedPrice}</strong>
        <p style="margin:4px 0">${address}</p>
        <p style="margin:4px 0;color:#64748b">${bedrooms} bed · ${sqm} m²</p>
        <a href="/listings/${id}" style="color:#2563EB;font-weight:600">View listing →</a>
      </div>
    `)
    .addTo(map);
});

// Change cursor on hover
map.on('mouseenter', 'property-price', () => { map.getCanvas().style.cursor = 'pointer'; });
map.on('mouseleave', 'property-price', () => { map.getCanvas().style.cursor = ''; });
map.on('mouseenter', 'clusters',       () => { map.getCanvas().style.cursor = 'pointer'; });
map.on('mouseleave', 'clusters',       () => { map.getCanvas().style.cursor = ''; });

मूल्य श्रेणी फ़िल्टर

एक श्रेणी स्लाइडर जो दृश्यमान सूचियों को फ़िल्टर करता है, संपत्ति मानचित्र के लिए उच्चतम मूल्य UI परिवर्धन में से एक है। Mapbox GL JS अभिव्यक्ति प्रणाली आपको नेटवर्क राउंड-ट्रिप के बिना क्लाइंट-साइड एक परत (layer) का फ़िल्टर अपडेट करने देती है, फ़िल्टरिंग पहले से लोड किए गए GeoJSON पर ब्राउज़र में होता है।

function applyPriceFilter(min, max) {
  const filter = ['all',
    ['!', ['has', 'point_count']],
    ['>=', ['get', 'price'], min],
    ['<=', ['get', 'price'], max]
  ];
  map.setFilter('property-price', filter);
}

// Wire up range inputs
const minInput = document.getElementById('price-min');
const maxInput = document.getElementById('price-max');

function onRangeChange() {
  applyPriceFilter(Number(minInput.value), Number(maxInput.value));
}

minInput.addEventListener('input', onRangeChange);
maxInput.addEventListener('input', onRangeChange);

ध्यान दें कि क्लस्टर स्रोत डेटा से गणना किए जाते हैं, परत फ़िल्टर से नहीं, इसलिए क्लस्टर गणना में वे सूचियां भी शामिल रहती हैं जिन्हें स्लाइडर ने छिपा दिया है। दोनों को सिंक में रखने के लिए, सूचियों को JavaScript में फ़िल्टर करें और परिणाम को map.getSource('properties').setData() में पास करें।

Geocoding API के साथ पता खोज

उपयोगकर्ताओं को मानचित्र को फिर से केंद्रित करने के लिए पड़ोस या पोस्टकोड टाइप करने दें। Geocoding API GeoJSON विशेषताएं लौटाता है, इसलिए निर्देशांक सीधे map.flyTo में गिरते हैं।

async function searchArea(query) {
  const url = new URL('https://gateway.mapmetrics-atlas.net/forward-geocode/');
  url.searchParams.set('text', query);
  url.searchParams.set('token', 'YOUR_API_KEY');
  url.searchParams.set('size', '1');

  const res  = await fetch(url);
  const data = await res.json();

  if (!data.features.length) return;

  const [lng, lat] = data.features[0].geometry.coordinates;
  map.flyTo({ center: [lng, lat], zoom: 13 });
}

document.getElementById('area-search').addEventListener('keydown', (e) => {
  if (e.key === 'Enter') searchArea(e.target.value.trim());
});

यात्रा-समय खोज के लिए, "इस स्कूल से 20 मिनट के भीतर संपत्ति दिखाएं", MapAtlas Travel Time API का उपयोग करके एक समद्विबाहु ओवरले जोड़ें। Isochrone Maps समझाया लेख दिखाता है कि उस बहुभुज को कैसे प्राप्त करें और प्रदर्शित करें।

संपूर्ण React घटक

उपरोक्त सभी को उचित जीवनचक्र प्रबंधन के साथ एक React घटक में लपेटना:

import { useEffect, useRef, useState } from 'react';
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';

export function PropertyMap({ listings, apiKey }) {
  const containerRef = useRef(null);
  const mapRef       = useRef(null);
  const [priceRange, setPriceRange] = useState([0, 2000000]);

  useEffect(() => {
    const map = new mapmetricsgl.Map({
      container: containerRef.current,
      style: `https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_STYLE_ID/style.json&token=${apiKey}`,
      center: [4.9041, 52.3676],
      zoom: 13
    });
    mapRef.current = map;

    map.on('load', () => {
      map.addSource('properties', {
        type: 'geojson',
        data: { type: 'FeatureCollection', features: listings },
        cluster: true,
        clusterMaxZoom: 14,
        clusterRadius: 60
      });
      // Add cluster, cluster-label, property-price layers (see above)
      // Add click handlers (see above)
    });

    return () => map.remove();
  }, [apiKey]);

  // Update filter when price range slider changes
  useEffect(() => {
    const map = mapRef.current;
    if (!map || !map.getLayer('property-price')) return;
    map.setFilter('property-price', [
      'all',
      ['!', ['has', 'point_count']],
      ['>=', ['get', 'price'], priceRange[0]],
      ['<=', ['get', 'price'], priceRange[1]]
    ]);
  }, [priceRange]);

  return (
    <div>
      <div style={{ padding: '12px 0', display: 'flex', gap: 12 }}>
        <label>
          Min €
          <input type="range" min={0} max={2000000} step={10000}
            value={priceRange[0]}
            onChange={e => setPriceRange([+e.target.value, priceRange[1]])} />
        </label>
        <label>
          Max €
          <input type="range" min={0} max={2000000} step={10000}
            value={priceRange[1]}
            onChange={e => setPriceRange([priceRange[0], +e.target.value])} />
        </label>
      </div>
      <div ref={containerRef} style={{ width: '100%', height: '600px' }} />
    </div>
  );
}

यह घटक का ढांचा है, मूल्य श्रेणी स्लाइडर और जीवनचक्र सफाई सहित लगभग 65 लाइनें; इसे पूरा करने के लिए ऊपर के अनुभागों से परत और क्लिक हैंडलर का कोड जोड़ें।

EU PropTech के लिए GDPR नोट्स

जब कोई संपत्ति खोजकर्ता अपना घर का पता टाइप करता है या आपके मानचित्र पर "मेरे स्थान का उपयोग करें" पर क्लिक करता है, तो वे GDPR अनुच्छेद 4(1) के तहत व्यक्तिगत डेटा साझा कर रहे हैं, जो स्थान डेटा को एक पहचानकर्ता के रूप में नामित करता है। वह स्थान डेटा प्रकट करता है कि वे कहां रहते हैं, जो उनके बारे में अन्य संवेदनशील विशेषताओं का अनुमान लगा सकता है।

EU अनुपालन के लिए व्यावहारिक कदम:

  • ब्राउज़र से सीधे Geocoding API कॉल करने के बजाय अपने बैकएंड के माध्यम से जियोकोडिंग अनुरोधों को रूट करें। आपका बैकएंड अग्रेषण करने से पहले पहचान की जानकारी को हटा सकता है।
  • जब तक आपके पास GDPR अनुच्छेद 6 के तहत प्रलेखित कानूनी आधार, जैसे सहमति, न हो, तब तक सत्र से परे खोज निर्देशांक को लॉग या बनाए न रखें।
  • यदि आप "मुझे बताएं कि जब मेरे पास कोई संपत्ति मेरी मानदंड से मेल खाए" लागू करते हैं, तो संग्रहीत खोज क्षेत्र को एक परिभाषित प्रतिधारण अवधि के साथ व्यक्तिगत डेटा के रूप में व्यवहार करें।

EU Developer's Guide to GDPR-Compliant Map APIs में यह संपूर्ण रूप से कवर किया गया है, जिसमें प्रोसेसर समझौते और डेटा रेसिडेंसी आवश्यकताएं शामिल हैं। MapAtlas EU के भीतर डेटा को संसाधित करता है और वह डेटा प्रोसेसिंग समझौता प्रदान करता है जो GDPR अनुच्छेद 28(3) नियंत्रक और प्रोसेसर के बीच अनिवार्य करता है।

Real Estate industry solution page में PropTech प्लेटफॉर्म उत्पादन में MapAtlas का उपयोग कैसे करते हैं, इस बारे में अतिरिक्त संदर्भ है।

अगले कदम

Frequently Asked Questions

Can I use MapAtlas for a property listing website?

हां। MapAtlas वह सब कवर करता है जिसकी प्रॉपर्टी साइटों को ज़रूरत होती है: प्रॉपर्टी खोज मानचित्र, निवेश डैशबोर्ड और किराये की लिस्टिंग के मानचित्र। Maps API, Mapbox GL JS के अनुकूल है, इसलिए मौजूदा Mapbox-आधारित प्रॉपर्टी मैप कोड न्यूनतम बदलावों के साथ माइग्रेट हो जाता है।

How does marker clustering work for real estate maps?

Clustering groups nearby property markers into a single circle showing the count when the map is zoomed out. As the user zooms in, clusters split into individual markers. MapAtlas supports GeoJSON source clustering natively, set cluster: true on the source and the SDK handles the rest.

Is location data from property searchers subject to GDPR?

Yes. When a user searches by their home address or current location on a property site, that constitutes personal data under GDPR Article 4. EU PropTech platforms should route geocoding requests through a backend proxy and apply appropriate data minimisation and retention policies rather than making client-side API calls that log user locations to third-party servers.

यह उपयोगी लगा? इसे साझा करें।

लेखक के बारे में

Brent van der Heiden

लेखक

Brent van der Heiden

Co-Founder & CEO at MapAtlas

Brent built MapAtlas out of a conviction that developers deserve location APIs with fair pricing and genuine end-user privacy. Before that he co-founded MapMetrics, a community mapping and navigation app. He writes about geospatial infrastructure, map data, AI search visibility, and how location data powers the products people rely on every day.

सभी लेख देखें →
ब्लॉग पर वापस जाएं