Spatial Pixel

Making Design Computable

There are several ways to add interactive markers to a map in SlippyMapper.

If all you care about is an aesthetic effect, like a highlight on hover, and you don’t need to access the data the marker represents, it’s just a matter of providing a function to the addMarker() method.

"""Example of how to make markers visually interactive."""

import spatialpixel.mapping.slippymapper as slippymapper

def setup():
    size(1100, 500)

    global m
    m = slippymapper.SlippyMapper(40.7, -73.963175, 11, 'toner-lite', width, height)

    # Some sample data.
    jfk = {'lat':40.6413, 'lng':-73.7781}
    lga = {'lat':40.7769, 'lng':-73.8740}
    ewr = {'lat':40.6895, 'lng':-74.1745}
    nyc_airports = [jfk, lga, ewr]

    # Write a function to provide to addMarker().
    def airport_marker(x, y, marker):
        marker.stroke(255, 0, 0)
        marker.noFill()
        if dist(mouseX, mouseY, x, y) <= 15:
            marker.fill(255, 0, 0)
        marker.ellipse(x, y, 30, 30)

    # Create markers for each airport.
    for airport in nyc_airports:
        m.addMarker(airport['lat'], airport['lng'], airport_marker)

    m.render()

def draw():
    background(255)
    m.draw()

which results in:

It’s possible to use this method to make markers that respond to the data they represent (more than just location, anyway). The function can return a closure that binds to the data, or you can make a new function for each marker. Sometimes that’s fine, but there’s another way that’s more object-oriented:

Interactive Data Markers

If you want to make the marker respond to the data itself, you can extend the DataMarker class provided in the slippymapper module.

"""This example shows how to create interactive data markers in SlippyMapper.

Creating them involves extending the DataMarker class and providing a draw()
method that draws the marker.
"""

import spatialpixel.mapping.slippymapper as slippymapper

def setup():
    size(1100, 500)

    global m
    m = slippymapper.SlippyMapper(40.7, -73.963175, 11, 'toner-lite', width, height)

    # Some sample data.
    jfk = {'lat':40.6413, 'lng':-73.7781, 'code':"JFK", 'traffic':7000}
    lga = {'lat':40.7769, 'lng':-73.8740, 'code':"LGA", 'traffic':3000}
    ewr = {'lat':40.6895, 'lng':-74.1745, 'code':"EWR", 'traffic':5000}
    nyc_airports = [jfk, lga, ewr]

    # Create markers for each airport. The constructor here, AirportMarker(), 
    # provides the value of "airport" to the self.data property of the instance.
    for airport in nyc_airports:
        m.addMarker(airport['lat'], airport['lng'], AirportMarker(airport))

    m.render()

def draw():
    background(255)
    m.draw()

# This is a custom data marker. It allows you to attach data to your marker.
# All you need is to define the method drawMarker() with these arguments.
class AirportMarker(slippymapper.DataMarker):
    def drawMarker(self, x, y, marker):
        # self.data is the data passed in when the marker was created.
        # In this case, it's the value of "airport" in AirportMarker(airport) above.
        diam = self.data['traffic'] / 100

        # 'marker' is an object that enables you to style the marker. Just call
        # your normal drawing functions prefaced by 'marker' and a dot. This refers
        # to the fourth argument of this method above.
        marker.stroke(255, 0, 0)
        marker.noFill()

        # Make it a bit interactive by filling the ellipse on a mouse hover.
        if dist(x, y, mouseX, mouseY) < diam / 2:
            marker.fill(255, 0, 0)

        marker.ellipse(x, y, diam, diam)

        # Draw the airport name and nudge it to the right.
        marker.fill(255, 0, 0)
        marker.text(self.data['code'], x + diam / 2 + 3, y)

Now, the markers can show the airport code and draw themselves based on the daily traffic at that airport (fictional data, of course):

And that’s about it. You can create as many different marker types as you like, just subclass the DataMarker class and provide a drawMarker() method definition that does all the work. Remember that self.data will refer to the value you pass in when constructing the marker. You can pass in anything, a string, dictionary, tuple, list, whatever you want to display. SlippyMapper will give you the x and y coordinates in pixel space of where the marker should go.

I'm Allan William Martin, a product manager, computational designer, and software engineer in New York City. I work at Pivotal on Cloud Foundry, a cloud-native application platform. I've taught at the Yale School of Architecture, New York Institute of Technology, and General Assembly.

This post was published on by .