Map real estate search apps are a great way to enhance web app functionality and user-engagement. They can be significantly more user-friendly to use for real estate listing search utilities than standard html forms. Many features in the SimplyRETS API are built with this specific use-case in mind.
For the uninitiated, SimplyRETS leverages your RETS or RESO Web API data feed to provide a more modern and robust API for developing real estate software using listing, open house, and agent data from your MLS. Our services are designed to be simple and effective for any developer to use productively.
In this tutorial, I’ll outline how to build a simple map-based search app using the SimplyRETS API. If you want to skip to the code or follow along with a complete sample, you can use our Github Examples Repo. We’ve prepared a live demo with the code from this tutorial here.
Sections
Background details
The primary feature in the SimplyRETS API which helps with map-based searching
is the points
query parameter. The points
parameter is simply a list of
latitude/longitude coordinates (separated by a comma). See our
interactive documentation
for more details and other query parameters.
A raw query url to our listings api endpoint which uses points
should look
like:
https://api.simplyrets.com/properties?points=29.723837146389066,-95.69778442382812&points=29.938275329718987,-95.69778442382812&points=29.938275329718987,-95.32974243164061&points=29.723837146389066,-95.32974243164061
Note that points
is specified once for each point in a polygon made up of
latitude/longitude coordinates.
In order to utilize the points
parameter from a web app, we need a few
external utilities and libraries for rendering maps on html/javascript pages.
I’ll be using Leaflet and
OpenStreetMap as a starting point to build the
map and access basic map tools. We will also be using a Leaflet extension called
Leaflet.Draw
I will use jQuery to make some of the Javascript more simple. However, jQuery is not strictly necessary for this app.
All the tools used in this tutorial are free and open source. You are free to download and use them in your own projects. I have also included the source code for this tutorial on our Github. if you’d like to follow along or reuse it.
Once the foundation is laid, I’ll make API calls to the SimplyRETS listings
endpoint, https://api.simplyrets.com/properties
, using javascript to retrieve
the listing data and populate the map.
The end result of this tutorial should be a simple mapping application which can be adapted for use in many different situations. You can check out a live demo here.
Getting set up
To get started, create a file named index.html
and include an html page shell.
<html>
<head>
<title>SimplyRETS interactive map search</title>
<script>
$(document).ready(function () {
console.log("SimplyRETS Map Search")
})
</script>
</head>
<body>
<div id="#map" style="height: 100%"></div>
</body>
</html>
This html is enough to get started. You can open this file directly in a web
browser (without a web server). Type file:///
in your address bar to navigate
to the right folder. Don’t worry if the page is all white yet.
Include dependencies
Next, we need to include some scripts and stylesheets in order to use Leaflet, OpenStreetMap, and jQuery. For the purposes of this tutorial, I will use CDN links. It’s not necessary to download any code manually.
<head>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.css" />
<!--[if lte IE 8]>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.ie.css" />
<![endif]-->
</head>
Include these stylesheets inside the <head>
tag of index.html
. Do the same
for the javascrtipt:
<head>
<!-- ...stylesheets... -->
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
<script src="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.js"></script>
</head>
JavaScript
Now that we have our project setup and a code skeleton to work with, we can start writing some javascript to implement our map logic.
$(document).ready(function () {
// Code goes here.
})
This line of jQuery code ensures that the web page is ready to be manipulated.
jQuery handles the details for us. Anything inside the ready(function() {
code
block will be executed once when the DOM can be manipulated.
Next, we need to setup a Leaflet map.
var map = new L.Map("map")
L.tileLayer("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution:
'© <a href="http://openstreetmap.org">OpenStreetMap</a> contributors',
maxZoom: 18,
}).addTo(map)
The capital L
is an identifier for the Leaflet namespace. Functions called
after the L.
are specific to the Leaflet API. In this case, we are
initializing a map, then creating a tileLayer
which we add to the map. In
short, Leaflet applications work by manipulating various layers within the
context of a map.
The tile layer on our map is backed by an OpenStreetMap tile png. The maxZoom
is set to 18. The higher the maxZoom
, the further away the the map will be
allowed to zoom out. The final addTo
call is where the tile layer is directly
associated with the map object.
We use the latitude/longitude coordinates of Houston, Texas to center the map since the SimplyRETS test data is located in Houston.
var houston = new L.LatLng(29.97, -95.35)
map.setView(houston, 13)
L.LatLng
is another convenience class which the Leaflet API provides. A
LatLng
object can be applied directly to the map as a view using setView
.
The second argument to setView
is the initial zoom. 13 is a good enough value
to see the entire city.
Drawing on the map
In order to draw Polgons on the map, we need to set up a Leaflet FeatureGroup
.
FeatureGroup
’s are another Leaflet class capable of grouping and interacting
with other layers on the map. Using FeatureGroup
s, we can add our polygon(s)
to the map using only a few lines of code.
We set up a basic feature group name drawnItems
(for drawn items) and add it
to the map using addLayer
.
var drawnItems = new L.FeatureGroup()
map.addLayer(drawnItems)
Now, we need to attach the same drawnItems
FeatureGroup
to a Draw
control.
var drawControl = new L.Control.Draw({
edit: {
featureGroup: drawnItems,
},
draw: {
circle: false,
marker: false,
polyline: false,
},
})
map.addControl(drawControl)
We created a new Draw
control, using our FeatureGroup for drawn items. To
connect the Draw
control with the map, we use the map.addControl
function
call (similar to map.addLayer
).
If you load the map now, you will see a control panel in the upper left corner:
For the purpose of this tutorial, we focus on the square and polgon tools. Using
the draw
options when creating the Draw
control, we can disable control
components which we are not using (e.g. circle, marker, and polyline). For more
information see the
Leaflet.Draw documentation
Calling the listings API
Now that we have our map, layers, and draw control setup we can finally start pulling listings from SimplyRETS. In order for the draw control to do this, we must implement an event listener callback function which describes what to do when shapes are created on the map using the draw control
Leaflet uses event methods to hook
into the Map and run functions. The on
function is used to add an event
listener to an object (e.g. a Map
). For example,
map.on('click', function(e) { alert(e.latlng); });
could be used to run a
function when a user clicks on the map.
We need to hook into our draw controls 'draw:created'
event in order to
properly handle draw events on our map.
Since our event listener will be run when a polygon is overlayed on the map, we can outline a set of steps to request data from the SimplyRETS api using the lat/lng coordinates drawn by the user.
- Get latitude longitude coordinates from the Draw Control.
- Request listings from the SimplyRETS API using the latitude/longitude points as query parameters
- Place each listing in the API response as a point on the map.
Start by creating an event callback for 'draw:created'
.
map.on("draw:created", function (e) {
var latLngs = $.map(e.layer.getLatLngs(), function (o) {
return { name: "points", value: o.lat + "," + o.lng }
})
})
First, the callback extracts and formats the latitude/longitude points from the
new polygon. The argument passed to function(e) { .. }
is the event.
Unsurprisingly, the event contains a layer for the new polygon. Calling
getLatLngs()
on the layer will return a list of latitude/longitude points.
The $.map
function from jQuery is used to format the lat/lng points into a
suitable format for the SimplyRETS points
query parameter. The function passed
to $.map
returns a name/value pair for each point in the polygon and is stored
in the latLng
var.
An ajax request is then created to submit the latLng
points to the SimplyRETS
properties endpoint and retrieve listings. We pass in the latLngs
variable as
the ajax data
parameter. This means the list of latitude/longitude points are
translated into query parameters in the GET request.
In the beforeSend
function, we setup authentication to the SimplyRETS api
using test credentials. Using test credentials here is for test purposes only.
Use caution when determining how to handle authenticating your credentials from
your app.
$.ajax({
url: 'https://api.simplyrets.com/properties',
data: latLngs,
beforeSend: function(xhr) {
// Create the correct authentication headers for the
// SimplyRETS API. Using our trial credentials here is for
// test purposes _only_. Use caution when determining how to
// handle your credentials w/ your specific use-case.
xhr.setRequestHeader("Authorization", "Basic " + btoa("simplyrets:simplyrets"))
},
success: function(data) {
$.each (data, function (idx) {
var markerLocation = new L.LatLng(data[idx].geo.lat, data[idx].geo.lng);
var marker = new L.Marker(markerLocation);
map.addLayer(marker);
});
}
});
map.addLayer(e.layer);
});
The final bit that’s needed, is a function to run on a successful request with
the retrieved listing data. The $.ajax
function provides an option named
success
for a function to with the response data.
Since the data retrieved is in JSON format by default, we can loop directly over
each listing in the results using jQuery $.each
function.
For each listing, we create a marker location and corresponding marker. To tie
it all together, we use map.addLayer
to add the marker to the map.
Conclusion
Voila, you should now see markers within a polygon region on your map. You can try a live demo of the code here. The end result of our code can now be used as a starting point in any application which requires map-based search. The code is quite small and can be easily customized:
<html>
<head>
<title>SimplyRETS Map Search</title>
<link
rel="stylesheet"
href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.css"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.css"
/>
<!--[if lte IE 8
]><link
rel="stylesheet"
href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.ie.css"
/><![endif]-->
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
<script src="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.js"></script>
<script language="javascript">
$(document).ready(function () {
var map = new L.Map("map")
L.tileLayer(
"http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
{
attribution:
'© %lt;a href="http://openstreetmap.org">OpenStreetMap</a> contributors',
}
).addTo(map)
var houston = new L.LatLng(29.97, -95.35)
map.setView(houston, 10)
var drawnItems = new L.FeatureGroup()
map.addLayer(drawnItems)
var drawControl = new L.Control.Draw({
edit: {
featureGroup: drawnItems,
},
})
map.addControl(drawControl)
map.on("draw:created", function (e) {
var latLngs = $.map(e.layer.getLatLngs(), function (o) {
return { name: "points", value: o.lat + "," + o.lng }
})
$.ajax({
url: "https://api.simplyrets.com/properties",
data: latLngs,
beforeSend: function (xhr) {
xhr.setRequestHeader(
"Authorization",
"Basic " + btoa("simplyrets:simplyrets")
)
},
success: function (data) {
$.each(data, function (idx) {
var markerLocation = new L.LatLng(
data[idx].geo.lat,
data[idx].geo.lng
)
var marker = new L.Marker(markerLocation)
map.addLayer(marker)
})
},
})
map.addLayer(e.layer)
})
})
</script>
</head>
<body>
<div id="map" style="height: 100%"></div>
</body>
</html>
The example code can be found on the SimplyRETS examples repo on Github and is completely free to take and use as you wish. Send us a message any time if you have questions or you’re interested in learning more about.
— Christopher @ SimplyRETS