Real estate search on the map

Three search scenarios your visitors already expect on a real estate portal, ready to use in the JavaScript Map plugin: search by travel time, draw the search area, and lifestyle search. Plus a results map that displays your listings with the area they were found in.

What you get

The division of work is simple and deliberate: Yatmo computes the geography (isochrones, proximity to points of interest, stored criteria) and your backend searches the listings, because only you know your inventory, your filters and your business rules. Everything the map hands over is standard GeoJSON.

The flow, end to end

  1. Search page. Your page embeds the map with one or more scenarios enabled. The visitor picks an address and a travel time, draws an area, or saves lifestyle criteria. Yatmo draws the resulting area on the map.
  2. Hand-over. When the visitor clicks the search button, the plugin calls your onSearch(shape, meta) callback (and fires a yatmo:search DOM event) with the polygon as a GeoJSON geometry.
  3. Your backend. You run your own listings query with a spatial filter on that polygon, exactly as you would with a bounding box today. Any database with a "point in polygon" function works (see below).
  4. Results page. Another page (or the same one) embeds the map with listings: your results, and the same shape so the visitor sees where they searched.
Nothing new to load for your other pages
The search features live in a companion module that map_v3.js only downloads when yatmoConfig declares one of them. Your property pages that use the map today keep their exact weight and behaviour.

Enabling a scenario

Each scenario is one optional object in yatmoConfig. Several can be enabled on the same map, they stack in one panel.

<div id="map"></div>

<script>
    yatmoConfig = {
        licenseKey: 'xxxxxxxxxxxxxxxxxx',
        language: 'FR',
        country: 'BE',
        container: 'map',
        center: [4.3517, 50.8503],
        zoom: 12,
        startsWithPoisHidden: true,          // a search map usually starts clean
        accentColor: '#0a7cff',              // your brand colour, used by every control
        rounded: '10px',                     // corner radius of every Yatmo control

        travelTimeSearch: { onSearch: runMySearch },
        drawSearch:       { onSearch: runMySearch },
        lifestyleSearch:  { userId: 'your-visitor-id', onSearch: runMySearch }
    };

    function runMySearch(shape, meta) {
        // shape: GeoJSON Polygon or MultiPolygon (null when the area was cleared)
        // meta.type: 'travelTime' | 'drawn' | 'lifestyle'
        sessionStorage.setItem('searchShape', JSON.stringify(shape));
        location.href = '/results';
    }
</script>
<script src="https://map.yatmo.com/map_v3.js"></script>

Getting the shape back

Two callbacks, so you can tell a preview from a search intent:

Name In Type Description
onShape(shape, meta) callback function Fired every time the area changes: computed, redrawn, cleared (shape is then null). Use it for previews, counters, analytics.
onSearch(shape, meta) callback function Fired when the visitor clicks the search button of the panel. This is where you run your listings query.
yatmo:shape / yatmo:search DOM event CustomEvent The same two moments as DOM events on the map container, event.detail = { shape, meta }, bubbling. Handy with frameworks or tag managers.
YatmoSearch.getShape() runtime function Returns the current area at any time (or null).

meta always carries type (travelTime, drawn or lifestyle) plus scenario-specific fields documented on each page. The shape is a GeoJSON geometry (not a Feature): { "type": "Polygon", "coordinates": [[[lng, lat], ...]] }, longitude first as in every GeoJSON. Travel-time and lifestyle areas are often MultiPolygons (a river or a motorway splits them).

document.getElementById('map').addEventListener('yatmo:search', function (e) {
    console.log(e.detail.meta.type, e.detail.shape);
});

Filtering on your side

Store the GeoJSON with the search (session, URL parameter, query string of your API, whatever you already do for bounding boxes) and filter your listings with a point-in-polygon test. The shapes are simplified by Yatmo before being handed over (a few hundred vertices for a drawn area, a few thousand for a country-wide lifestyle criterion), so they are cheap to query.

-- PostgreSQL + PostGIS
SELECT * FROM listings
WHERE ST_Contains(ST_GeomFromGeoJSON(:shape), ST_SetSRID(ST_MakePoint(longitude, latitude), 4326));

-- SQL Server
DECLARE @area geography = geography::STGeomFromText(@wkt, 4326);  -- convert the GeoJSON to WKT once, server side
SELECT * FROM listings WHERE @area.STIntersects(geography::Point(latitude, longitude, 4326)) = 1;

-- MySQL 8
SELECT * FROM listings
WHERE ST_Contains(ST_GeomFromGeoJSON(:shape), ST_SRID(POINT(longitude, latitude), 4326));

Search engines do it too: Elasticsearch geo_polygon / geo_shape queries, Algolia insidePolygon, Meilisearch _geoPolygon. If your stack cannot do spatial queries, pre-filter with the polygon's bounding box and test the remaining points in code with any ray-casting helper.

Styling and CSS isolation

The plugin protects itself from your site's generic CSS and, at the same time, lets you restyle anything on purpose:

/* A dark, branded panel: your selectors are more specific than the plugin's, so they win */
#map [data-yatmo-root] {
    --yatmo-accent: #e8590c;
    --yatmo-search-radius: 18px;
}
#map [data-yatmo-root] .yatmo-search-panel { background: #1f2430; color: #e6e6e6; }
#map [data-yatmo-root] .yatmo-search-title { color: #fff; }
#map [data-yatmo-root] .yatmo-search-input  { background: #2a3040; color: #fff; border-color: #444c60; }
Global !important rules are the one thing we cannot absorb
A site rule such as * { letter-spacing: 2px !important } beats any scoped rule by definition. Keep !important off your generic selectors, or scope them outside the map container.

Languages

The panels are translated in the 23 languages of the plugin, selected by yatmoConfig.language. Category names ("Primary school", "Metro station") and transit line names come from the Yatmo API in that language, in every country we cover. Prices, titles and places of your listings are yours: the plugin displays the strings you give it, so format them the way your site does.

Performance

Next steps