Step 9: Show details of features¶
In this step, we use a container to show details of a feature when clicking it.
Details container¶
We did not touch our HTML document in a while and now we are going to create a <div>
container just underneath the map. In this container, we will show the details of a feature when the user clicks on it. The container is hidden initially.
11 12 13 14 15 16 17 | <!-- ... -->
<div id="map"><!-- Map container --></div>
<div id="details" class="hidden"><!-- Details container --></div>
<!-- JS libraries -->
<!-- ... -->
|
Click function to show details¶
Similar to the function to show a tooltip, we will create a function to show the details of a feature.
We are creating a function which handles showing the details.
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | // ...
/**
* Show the details of a feature in the details <div> container.
*
* @param {object} f - A GeoJSON Feature object.
*/
function showDetails(f) {
// Get the ID of the feature.
var id = getIdOfFeature(f);
// Use the ID to get the data entry.
var d = dataById[id];
// The details HTML output is just the name
var detailsHtml = d.name;
// Put the HTML output in the details container and show (unhide) it.
d3.select('#details').html(detailsHtml);
d3.select('#details').classed("hidden", false);
}
// ...
|
And we trigger the function when a user clicks on a feature.
91 92 93 94 95 96 97 98 99 100 | // ...
.attr('d', path)
// When the mouse moves over a feature, show the tooltip.
.on('mousemove', showTooltip)
// When the mouse moves out of a feature, hide the tooltip.
.on('mouseout', hideTooltip)
// When a feature is clicked, show the details of it.
.on('click', showDetails);
// ...
|
Mustache templates¶
Until now, we are just showing the name of the feature in the details container. We would like to show much more information, for example a table showing all the data we have on this feature (name, total area, forest area in % etc.).
Returning HTML output from a JavaScript function can be a bit painful, as we have to create a string full of HTML tags and variables between. This can become quite ugly, especially if we want to output an HTML table.
This is why we are going to use Mustache templates and more specifically mustache.js since we are dealing with JavaScript. As stated on their homepage, Mustache is a logic-less template syntax. It can be used for HTML, config files, source code - anything. It works by expanding tags in a template using values provided in a hash or object.
First, we are going to include the mustache.js JavaScript library in our HTML document.
14 15 16 17 18 19 20 | <!-- ... -->
<!-- JS libraries -->
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.2.1/mustache.min.js"></script>
<!-- ... -->
|
Now we are ready to create a Mustache template. We can do so right in our HTML document. This way, we will have all of our HTML output in one file. To define Mustache markup in a HTML document, we can use the <script>
tag with type x-tmpl-mustache
. The script within this block will not be executed until we tell Mustache to do so.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <!-- ... -->
<div id="details" class="hidden"><!-- Details container --></div>
<!-- Mustache template, rendered later to show the details of a feature -->
<script id="template" type="x-tmpl-mustache">
<h3>{{ name }}</h3>
<table>
<tr>
<th>Total area:</th>
<td>{{ area }} km²</td>
</tr>
<tr>
<th>Urban area:</th>
<td>{{ urban }} %</td>
</tr>
<tr>
<th>Agricultural area:</th>
<td>{{ agriculture }} %</td>
</tr>
<tr>
<th>Forest area:</th>
<td>{{ forest }} %</td>
</tr>
<tr>
<th>Unproductive area:</th>
<td>{{ unproductive }} %</td>
</tr>
</table>
</script>
<!-- JS libraries -->
<!-- ... -->
|
Now we need to tell Mustache to load this template and parse it so it can be filled with values later.
7 8 9 10 11 12 13 | // ...
// We get and prepare the Mustache template, parsing it speeds up future uses
var template = d3.select('#template').html();
Mustache.parse(template);
// ...
|
And finally, in our showDetails function, we replace our previously created detailsHtml output with our rendered Mustache template.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | // ...
/**
* Show the details of a feature in the details <div> container.
* The content is rendered with a Mustache template.
*
* @param {object} f - A GeoJSON Feature object.
*/
function showDetails(f) {
// Get the ID of the feature.
var id = getIdOfFeature(f);
// Use the ID to get the data entry.
var d = dataById[id];
// Render the Mustache template with the data object and put the
// resulting HTML output in the details container.
var detailsHtml = Mustache.render(template, d);
// Put the HTML output in the details container and show (unhide) it.
d3.select('#details').html(detailsHtml);
d3.select('#details').classed("hidden", false);
}
// ...
|
Next
Proceed to Step 10: A bit of styling.
Code¶
- For reference, the file
index.html
after step 9: https://github.com/lvonlanthen/data-map-d3/blob/step-09/index.html
- For reference, the file
- For reference, the file
style.css
after step 9: https://github.com/lvonlanthen/data-map-d3/blob/step-09/style.css
- For reference, the file
- For reference, the file
map.js
after step 9: https://github.com/lvonlanthen/data-map-d3/blob/step-09/map.js
- For reference, the file
- The diff view of step 8 and step 9:
https://github.com/lvonlanthen/data-map-d3/compare/step-08...step-09?diff=split