2016-11-29

Hello again!

We’re back with the fourth installment of Make Your Own [  ]. Today, we’ll be focusing on how to add labels to your map using mapzen.js and the Tangram scene file.

We are going to begin right where we left off last time, so if you haven’t yet read the first few posts, I recommend starting there:

One Minute Map

Map Sandwich

Filters & Functions

Once again, I’m going to assume you have a text editor and access to a web server. If you need either, please read our developer guide on setting up a bare bones development environment or use the gist → bl.ocks workflow described in One Minute Map.

Ok, let’s get started!



Here’s a reminder of what our geology map looks like from the last post:

Looks pretty good, no?

Buuuut…. it’s maybe not the most helpful map I’ve ever made. (What do these colors even mean?!) Sure, we could slap on a legend, but I’d like to do one better. Let’s add labels to the geologic units. That way we’ll have a better idea of what we’re looking at.

We’ll start where we left off last time, with index.html:

and scene.yaml:

Layer or Sublayer

As you can see above, our scene file has two layers: _national_park (San Juan National Historic Park boundaries) and _geology (San Juan geologic units).

One option for drawing our labels would be to add a third layer to our scene file. Something along the lines of:

However, because we are using the same data source as our _geology layer, we could turn our layer into a sublayer of _geology. The sublayer will inherit both the data source and the filter that we set up for our _geology layer, which will effectively reduce the number of parameters we need to set. (#winning)

Ok, so let’s call our sublayer “_geology_labels” and insert it within the _geology layer, just below the draw block. I’ll add a comment to make it a little easier to follow:

Labels

To draw our labels, we’ll be using one of Tangram’s built-in draw styles called text. The text draw style will draw a text label at a given point, depending on the type of data that is provided. For point data, the label will be drawn at the point. For lines, the label will be drawn along the line. And for polygons (like our data), text will be drawn within the polygon at regular spacing or at the polygon’s centroid. (More on that shortly.)

To our scene file, let’s add a simple, black label:

We’re using the text_source parameter to set the source of the label text. This could be a function (that returns a string) or the name of a feature property. If you recall from our last post in the series (Filters and Functions), each of our GeoJSON features comes with a set of feature properties:

These properties are accessible to a few different blocks, including filters and text_source. In this case, we’re telling Tangram to show the value stored in the feature property "GLG_SYM" as the text for our label.

If you’ve updated your map, it should look something like this:



There are several text parameters we can use to modify our labels, but the only parameter that needs to be set is font. So far, we’ve set our label size and color, but let’s take a look at some of the other font parameters we can use to improve the look of our labels.

Let’s change our font weight to bold and update the color of our text to something that blends a little better: rgba(130, 84, 41, 0.9). We’ll also change our fixed size to a dynamic size using stops (which you may remember from our Map Sandwich post):

Ok, that’s better. Let’s do one more thing to make these labels pop a little more. Let’s add a stroke to the font. Stroke might be better described as an outline or halo around the text and takes only two properties:

I’m using a low opacity value in my rgba, so as to not make the labels too distracting. What do you think?



Ok, I’ll be honest. There is one thing that’s still bothering me.

There are just so many labels. We don’t need so many duplicate labels. Who does that help?

On first look, it seems like repeat_distance might be our answer. The repeat_distance parameter specifies the minimum distance between labels. That’s great! We can just bump up that number and away we go!

Well… not so fast.

There’s one thing we’re forgetting.

Tangram displays data in tiles. And each tile interprets repeat_distance separately. So, while a label may not repeat within a tile, it can still repeat across tiles. This can result in multiple labels per feature, spread across different tiles.

If we zoom in on a single geologic unit, this effect becomes quite obvious:

I know I’ve said this before, but… we can fix that!

Enter: the generate_label_centroids parameter.

There is an optional parameter that we can pass to our data source, called generate_label_centroids. This will create a label point at the centroid of each of our polygon features. It will also assign a {label_placement: true} property to each of the centroid labels, which will allow us to filter the labels to show only those at the polygon centroid.

Did that make sense? Let’s take a look at it in action.

In our sources block, we’ll update our _nps_geology layer to include this new parameter:

Then we’ll add a filter to _geology_labels to ensure we’re only displaying the centroid labels:

At this point, your geology_labels sublayer should look something like this:

We should note that _geology_labels is still following the rules of its parent layer’s filter; it has simply added a second set of filtering rules. We can further refine this filter, by displaying our labels at zoom level 13 and above:

By the way, the format I used above ({ label_placement: true, $zoom: { min: 13 } }) is a shortcut for mapping multiple filters using the all filter. This is equivalent to:

Phew! Labels. Amiright?

This is usually the point where I am extremely grateful that I can build off of gorgeous, existing cartography (like the Mapzen basemaps *cough* *cough*), and don’t have to worry about things like highway shields or water transformations at different zoom levels.

I sense a segue coming…

Though there are times when that gorgeous cartography might get in the way of our map’s primary focus.

Ah, there it is.

Overriding basemap features

Perhaps it’s better if I show you what I mean. Let’s take a closer look at English Camp on our map:

Have you noticed something a little off with that orange color within our national park boundary? What’s happening is that orange (as well as the surrounding colors, though less noticeably so) is blending with Walkabout’s landuse layer, which is typically a nice, soothing green. In our case, however, the colors blend to create a somewhat distracting region of muted colors.

Maybe it’s not a big deal. Maybe I’m being picky. Let’s fix it just the same.

The easiest way to fix this is to override Walkabout’s landuse layer and simply set its visibility to false. At the bottom of your scene file, add the following layer:

Because this layer has already been defined in an imported scene file, we don’t need to set any other parameters. We simply pass in the parameter we want to override.

Easy!

Well, easy if you happen to share an office with the architects of Walkabout. Admittedly, it’s much less easy if you need to sift through the Walkabout yaml file to figure out layer names and settings.

To make this is a little less painful, we’ll use Tangram Play, Mapzen’s live Tangram style editor.

In your browser, go to https://mapzen.com/tangram/play/#13.4608/48.5872/-123.1450 (this link will position you right over English Camp on San Juan Island).

In the default.yaml file on the right, delete everything and replace with a single line:

Then click the Inspect button in the top right corner.

Inspect mode will allow you to move your cursor across the map and get information about each layer, including the layer name(s) that Walkabout uses for styling.

Go ahead and click on the green national park polygon:

As you’ll see, it’s part of a layer named “landuse”. In the default.yaml file, add the following just beneath the import line:

You should no longer see the green of the national park. We have effectively turned off the entire landuse layer.

We can do the same with sublayers. Just south of the park are several small roads, which I’d like to hide on our map. If you click on one of the minor roads, you’ll see the layer information:

At the bottom, you’ll see that minor_road is a sublayer of roads. We don’t want to turn off all roads, just the minor roads, so we’ll want to target just this sublayer.

In the default.yaml file, add another layer reference:

As expected, this turns off only the minor_road sublayer. This method doesn’t just work for the visibility parameter. If we wanted, we could make other changes to the existing layer, including changing the road color, width, and outline:

It’s not quite the cartographic marvel I was going for, but you get the idea.

Once we’ve figured out which layers we want to turn off (or modify) using Tangram Play, we can then copy and paste those layers back into our local scene.yaml file:

And we’re done!

The full code for this exercise can be seen on bl.ocks.org. You can also view and modify the final scene file using Tangram Play.

Thanks for coming along on another whirlwind tour of mapzen.js and the Tangram scene file. Stay tuned for the next Make Your Own [  ] post when we’ll talk about ways we can add interactivity to our map. It’s gonna be a good one!

If you have questions or want to show off something you’ve made with Mapzen, drop us a line. We love to hear from you!

Show more