Skip to content

Instantly share code, notes, and snippets.

@mehak-sachdeva
Last active August 29, 2016 15:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mehak-sachdeva/19dd6ab27c4ebdc3924bdd77a13548d5 to your computer and use it in GitHub Desktop.
Save mehak-sachdeva/19dd6ab27c4ebdc3924bdd77a13548d5 to your computer and use it in GitHub Desktop.

#Carto.js - Lesson 3: Basic Interactivity divided into steps for designing

Basic Interactivity

In the last lesson, we got a small peek at CartoCSS and SQL when we created a layer source object to get information to createLayer:

{% highlight javascript %} var layerSource = { user_name: 'documentation', type: 'cartodb', sublayers: [{ sql: "SELECT * FROM africa_adm0", // African countries cartocss: '#africa_adm0{polygon-fill:#FF6600;polygon-opacity:0.7;line-color:#FFF;line-width:1;line-opacity:1;}' }, { sql: "SELECT * FROM ne_50m_lakes", // Natural and artificial lakes cartocss: '#ne_50m_lakes {polygon-fill:#0000FF;}' }] } {% endhighlight %}

In this lesson, we will be using these powerful languages to boost the expressiveness of our maps.

<iframe src="//player.vimeo.com/video/114620642" width="700" height="393" frameborder="0"> </iframe>

Modifying SQL and CartoCSS

This is the third lesson in the course CARTO.js from the ground up. While still covering our JavaScript API in more depth, this lesson also relies on a basic understanding of the CartoCSS and SQL languages. We will keep it pretty simple here so you should not have trouble following along. If you would prefer to have a crash course before starting, check out some of the great documentation and [use cases]({{ site.baseurl }}/courses/intermediate-design/) for CartoCSS. For SQL, you can teach yourself in the CARTO Editor by using our first lesson in the [SQL and PostGIS in CARTO]({{ site.baseurl }}/courses/sql-postgis/) series.

SQL is a language for posing queries on your data and getting back the data that matches your query. For instance, if you have a database of home prices in different postal codes, one can easily find all homes within a certain price range in a specific postal code. SQL is an acronym for structured querying language.

CartoCSS is a language for altering the appearance of the CARTO data layer on your map. It helps you make your maps beautiful. Look up at the layer source code above, you can see some of the simpler ways of styling data. It was created by MapBox, is open source, and is lots of fun. To find out more about it, read the documentation.

Using the CARTO.js library, the main method to change the SQL and CartoCSS after they have been declared is sublayer.set(sublayerDefinition), where sublayerDefinition is equivalent to one of the objects in the sublayers array declared in layerSource above. If you only need to change one of CartoCSS or SQL for a previously created layer, there are some convenient methods:

  • sublayer.setCartoCSS("new CartoCSS styles")
  • sublayer.setSQL("new SQL")

If you instead want to retrieve entries from previously created sublayers, you have the following get... methods:

  • sublayer.getCartoCSS()
  • sublayer.getSQL()

Our goal with this lesson: Add more interactivity to our maps by using CARTO.js sublayer methods for altering SQL and CartoCSS.

The Data

We will be using the real-time earthquake data available through USGS' up-to-date datasets. To get a large amount of data, grab the "all earthquakes" link under "Past 30 Days" and import it into your account. As you will be doing this lesson at a different time than when this lesson was written, your data will appear differently than what appears below.

Before working with any data, rename the dataset to earthquakes_cdbjs_lesson3. Also don't forget to spend some time inspecting the data types and their values. Experimenting with the filters in the right pane is a great way to get to know your data.

The table has about a dozen columns, all of which are explained here. The ones of interest to us are:

  • time (date format)
  • latitude (number)
  • longitude (number)
  • depth (number) -- depth of the event in kilometers
  • mag (number) -- magnitude of event
  • place (string) -- description of where the event occurred
  • net (string) -- reporting station whose measurements made it into the data

We will start out with the following layer source. We will be able to update the layer by calling some of the listed methods of the CARTO.js API.

{% highlight javascript %} var layerSource = { user_name: 'documentation', type: 'cartodb', sublayers: [{ sql: "SELECT * FROM earthquakes_cdbjs_lesson3", // Earthquakes from the past 30 days cartocss: '#all_day{marker-fill-opacity:0.9;marker-line-color:FFF;marker-line-width: 1.5;marker-line-opacity: 1;marker-placement: point;marker-type: ellipse;marker-width: 10;marker-fill: #FF6600;marker-allow-overlap: true;}' // Simple visualization }] } {% endhighlight %}

CartoCSS

Since we have only point data in our earthquake dataset, we will be focusing on the marker type of CartoCSS, but as you can see in the documentation it is only one of several elements that can be styled directly on your map.

An easy way to get used to the basics of CartoCSS is by using the Vizualization Wizard in the CARTO Editor. It allows you to pick different visualizations to style them differently in the wizard.

Make sure you're in "MAP VIEW" to see your data visualized with Simple. Sticking with Simple, click on the CartoCSS Editor tab (the one with CSS) two below the Wizards tab to see how your data is styled.

![Simple CartoCSS Visualization]({{ site.baseurl }}/img/course3/lesson3/cartocss-simple.png)

You should see that the marker fill has an opacity option (marker-fill-opacity), the border to the marker (marker-line-color) is colored to be white (#FFF is short for #FFFFFF, which is white in hexadecimal), the marker width is set to 10 pixels, the fill is orange (#FF6600), and so on. If you're interested, check out the CartoCSS docs for more info about the other options.

CartoCSS strings in JavaScript

You have several options for using the CartoCSS text in CARTO.js. As the styling statements can be rather long, you may want to deal with the CartoCSS strings in different ways depending on your coding goals.

One option is to pass it as a string concatenated from separate lines:

{% highlight js %} var simpleStyle = '#earthquakes_cdbjs_lesson3 {' + 'marker-fill-opacity: 0.9;' + 'marker-line-color: #FFF;' + 'marker-line-width: 1.5;' + 'marker-line-opacity: 1;' + 'marker-placement: point;' + 'marker-type: ellipse;' + 'marker-width: 10;' + 'marker-fill: #FF6600;' + 'marker-allow-overlap: true;' + '}'; {% endhighlight %}

Another option is to minify the string--that is, to get rid it of all the white space and newlines. This makes your styles much less readable, but your JavaScript file will be smaller and load a tiny bit faster. This method can be problematic as there are currently no minifiers for CartoCSS, so you have to rely on tools for CSS, which is parsed differently.

{% highlight js %} var simpleStyle = '#earthquakes_cdbjs_lesson3{marker-fill-opacity:0.9;marker-line-color:#FFF;marker-line-width:1.5;marker-line-opacity:1;marker-placement:point;marker-type:ellipse;marker-width:10;marker-fill:#FF6600;marker-allow-overlap:true;}'; {% endhighlight %}

Because single or double quotes often appear in CartoCSS statements, you should be cautious that every character is part of the string. For instance, the following would produce a parse error:

{% highlight js %} var cartocss = '#table_name{text-face-name:'DejaVu Sans Book';}' {% endhighlight %}

The syntax highlighting we use in Academy helps us tell the story: the DejaVu Sans Book portion of the CartoCSS statement is interpreted as a series of variables (grey), not part of the string (green). You could fix it by writing it the following way instead:

{% highlight js %} var cartocss = "#table_name{text-face-name:'DejaVu Sans Book';}"; {% endhighlight %}

A third option is to create a custom <style> type with an id that allows you to extract the text. For instance, one could use the following:

{% highlight scss %}

<style type="cartocss/text" id="simple"> /** simple visualization */ #earthquakes_cdbjs_lesson3{ marker-fill-opacity: 0.9; marker-line-color: #FFF; marker-line-width: 1.5; marker-line-opacity: 1; marker-placement: point; marker-type: ellipse; marker-width: 10; marker-fill: #FF6600; marker-allow-overlap: true; } </style>

{% endhighlight %}

{% highlight html %}

<script> ... simpleStyle = $("#simple").text(); sublayer.setCartoCSS(simpleStyle); ... </script>

{% endhighlight %}

The <script> portion of the code pulls the text between the specified style tags (#simple in this case) and sets simpleStyle equal to it. This option allows you to directly copy and paste the code from the CARTO Editor without worrying about the errors that can occur from reformatting. Because of it's ease of use and readability, this is the format we will use for this lesson. As with other style tags, we will place this structure in the <head> section of the HTML document.

Conditions in CartoCSS

Now that we know what the Simple visualization looks like in CartoCSS, let's look at other visualizations. Switch to Choropleth, select the mag column, and choose Equal Interval for Quantification. Now switch to the CartoCSS tab again.

You can see that in addition to the first data structure, there are additional structures with conditional statements on the mag column. The statements style your data based on the conditions in the square brackets. If you switch to select Bubble from the Visualization Wizard, you will see your markers are given conditional sizes similar to the following:

{% highlight scss %} #table_name [mag < 2.0] { marker-width: 10; } #table_name [mag < 4.0] { marker-width: 20; } ... {% endhighlight %}

By writing CartoCSS like this, your styles are more dynamic and responsive to your data. It allows you to easily make your own choropleth, category, bubble map, or intensity visualization just as you would with the Visualization Wizard in the CARTO Editor.

Maps styled by end user

CARTO was created with the goal of helping people from all walks of life tell stories with maps and data. Let's say you're contracted by the USGS to create a simple interface to easily communicate earthquake data. We will be working from this template (follow the link, then copy & paste). Rename it to cartocss-style.html

First, we'll define the style for a Simple visualization between custom <style> tags as we discussed above. Put the <style type='cartocss/text' id='...'>CartoCSS Styles</style> element between the <head> tags, below the CSS and JavaScript library inclusions.

Next we need to add more styles from the CARTO Editor. The visualizations that I am recreating are:

  • Simple with an id of simple
  • Category by reporting station (net column), id is categ-report-sta
  • Choropleth of earthquakes by magnitude (mag column), id is choropleth-magnitude
  • Size (Bubble visualization) earthquakes by magnitude (mag column), id is bubble-magnitude
  • Size (Bubble) earthquakes by magnitude (mag column), choropleth by depth (depth column), id of bubble-choropleth

All of these CartoCSS styles go in their own <style type='cartocss/text' id='...'> structure between the <head> tags. The only one that requires some direct editing is the last one. This pulls the conditional styles from two different visualizations.

Next, we'll initialize a map like we have done already in [Lesson 2]({{ site.baseurl }}/courses/cartojs-ground-up/creating-basic-map-apps/#exploring-callback-functions):

{% highlight js %} window.onload = function () { var tableName = "earthquakes_cdbjs_lesson3";

// Put layer data into a JS object var layerSource = { user_name: 'documentation', type: 'cartodb', sublayers: [{ sql: "SELECT * FROM " + tableName, // All recorded earthquakes past 30 days cartocss: $("#simple").text() // Simple visualization }] }

// For storing the sublayer var sublayer;

// Instantiate new map object, place it in 'map' element var map_object = new L.Map('map', { center: [37.7741154,-122.4437914], // San Francisco zoom: 4 });

L.tileLayer('http://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' }).addTo(map_object);

// Add data layer to your map cartodb.createLayer(map_object,layerSource) .addTo(map_object) .done(function(layer) { sublayer = layer.getSubLayer(0); }) .error(function(err) { console.log("error: " + err); }); } {% endhighlight %}

Now that we have our styles, we need to interact with them. Our first step is to create some buttons with the following HTML that is placed immediately after the <div id='map'></div> element:

{% highlight html %}

CartoCSS Selectors

  • Categorize earthquakes by reporting station
  • Color earthquakes by magnitude
  • Size earthquakes by magnitude
  • Size earthquakes by magnitude, color by depth
  • Reset CartoCSS
{% endhighlight %}

And finally, we need to connect click events with these buttons. The following code does just the trick:

{% highlight js %} // Create layer selector function createSelector(layer) { var cartocss = ""; var $options = $(".layer_selector").find("li"); $options.click(function(e) { var $li = $(e.target); var selected = $li.attr('data');

$options.removeClass('cartocss_selected');
$li.addClass('cartocss_selected');

cartocss = $('#'+selected).text();

layer.setCartoCSS(cartocss);

}); } {% endhighlight %}

Place this function after createLayer. This code finds all the li elements and stores their reference in the variable $options. Once one of the li elements is clicked, its reference is stored in $li, and its data is extracted and placed in the variable selected. The style of the buttons is altered, and then the CartoCSS text is retrieved from the <style> structures you previously created. Finally, the layer is told to change is appearance once the setCartoCSS() method is applied to it.

The last piece is putting a call to createSelector(sublayer); right after sublayer is set equal to layer.getSubLayer(0); within .done().

Check out a live version [here]({{ site.baseurl }}/t/03-cartodbjs-ground-up/lesson-3/cartocss-style-hosted.html) or the source code here. There is also a version that uses minified strings if you prefer that method. And look here for a jsFiddle.

Basic SQL queries

Let's do a few simple queries in the CARTO Editor, and then work in JavaScript to extend our application with some of the more interesting queries. Copy your previous file to a new one called cartocss-and-sql.html.

Going back to the CARTO Editor in your browser, try experimenting with some SQL statements in the SQL editor in the right pane. Note that SELECT * FROM earthquakes_cdbjs_lesson3 just gives you all the rows and columns of your data.

We will be passing the following SQL statements to our method sublayer.setSQL("..."):

  • Events of magnitude greater than or equal to 5.0:
    SELECT * FROM earthquakes_cdbjs_lesson3 WHERE mag >= 5.0
  • Events that are not earthquakes:
    SELECT * FROM earthquakes_cdbjs_lesson3 WHERE type != 'earthquake'
  • Events that have a place referencing Papua New Guinea:
    SELECT * FROM earthquakes_cdbjs_lesson3 WHERE place ILIKE '%papua new guinea%'

We can code these into some HTML, grab them with a little JavaScript, and pass them to setSQL() to change the display of our map.

First we need to write the HTML. Put this statement below the CartoCSS structure: {% highlight html %}

SQL Selectors

  • Show magnitude >= 5.0
  • Show non-earthquakes
  • Show events near Papua New Guinea
  • Reset SQL
{% endhighlight %}

We now need a function that, once an li is clicked on, the respective WHERE clause stored in data will be appended to a SELECT * FROM earthquakes_cdbjs_lesson3 to produce the query we want. Note that the last li will just reproduce the default select all rows and columns statement once clicked on.

Next we need to change our createSelector function so that it interacts with the new SQL portion.

{% highlight js %} function createSelector(layer) { var condition = ""; // SQL or CartoCSS string var $options = $(".layer_selector").find("li"); $options.click(function(e) { var $li = $(e.target); var selected = $li.attr('data'); var type = $li.data('type'); // 'sql' or 'cartocss'

if (type === "cartocss") { // if a CartoCSS selector is chosen, set the style
  $options.removeClass('cartocss_selected');
  if (selected !== "simple") {
    $li.addClass('cartocss_selected');
  }

  condition = $('#'+selected).text();
  layer.setCartoCSS(condition);
} else { // if a SQL selector is chosen, re-query the data
  $options.removeClass('sql_selected');
  if (selected !== "") {
    $li.addClass('sql_selected');
  }

  layer.setSQL("SELECT * FROM " + tableName + selected);
}

}); } {% endhighlight %}

That's it! If you're having trouble getting yours to work, check out the source code here, or a live version [here]({{ site.baseurl }}/t/03-cartodbjs-ground-up/lesson-3/cartocss-and-sql-hosted.html)

Pro tip: If you want to take your map to a different location based on coordinates and zoom, you can call map_object.setView([lat,lon],zoom) method from the Leaflet.js library. In our case, if you want the map to go to Papua New Guinea after a user clicks on that option, you could grab the latitude and longitude from here, and then add an if statement like this:

{% highlight js %} if (selected.indexOf('guinea') !== -1) { map_object.setView([-9.5, 147.116667],6); } {% endhighlight %}

The string.indexOf('substring') method returns the index of the string where the substring occurs. If no substring is found, -1 is returned.

Moving forward

If you want to go a lot further with SQL and know (or want to learn) a little PostGIS, check out the tutorial Query by Distance.

What else do you want to learn in Academy? Drop us a line at contact@cartodb.com.

@mehak-sachdeva
Copy link
Author

cartocss-simple

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment