Step 11: Responsive map and instructions

In this step, we are going make our map responsive and we will add some instructions on how to use the map.

Full screen responsive map

Since we included Skeleton, you may have noticed that the row used for the details container is wider than the map container on wide screens. This does not look very nice and comes from the fact, that Skeleton uses a max width of 960px on large screens, but our map still has a hard coded width of 900px.

We can remove the width (and height) definition in the CSS style of the map container.

style.css - full screen map
33
34
35
36
37
38
39
40
/* ... */

#map {
  border: 1px solid silver;
  background: #E6E6E6;
}

/* ... */

While this lets the map container take up the full width of the row (same as the row in the details container), the map now has an ugly grey border when zooming in. Also, on smaller screens the map is now bigger than the container itself.

This is because the SVG element we created in the map still has a hard coded width of 900px.

To fix this, we do not set the width and height of the SVG element explicitely and use a viewbox instead. The viewbox receives initial dimensions (our width and height) and we tell it to preserve the aspect ratio so. This permits the container to handle rescaling automatically and while preserving the aspect ratio if the container is smaller or bigger than initially set.

map.js - table styling
11
12
13
14
15
16
17
18
19
20
21
// ...

// We create a SVG element in the map container and give it some
// dimensions. We can use a viewbox and preserve the aspect ratio. This
// also allows a responsive map which rescales and looks good even on
// different screen sizes
var svg = d3.select('#map').append('svg')
  .attr("preserveAspectRatio", "xMidYMid")
  .attr("viewBox", "0 0 " + width + " " + height);

// ...

Now the map looks and zooms quite nicely, regarding of the screen size. The only thing which is not pleasant is a small grey border at the bottom of the map, visible especially when zooming in. This seems to be an issue of the font size within the map container and it can be fixed in the CSS style by setting the font-size of the map container to 0.

style.css - set font-size in map container to 0
33
34
35
36
37
38
39
40
41
/* ... */

#map {
  font-size: 0; /* to prevent margin at bottom of map container */
  border: 1px solid silver;
  background: #E6E6E6;
}

/* ... */

However, this also sets the font size of the tooltip to 0, so we need to prevent that by setting a font size specifically for the tooltip.

style.css - font-size for tooltip
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
/* ... */

.tooltip {
  font-weight: bold;
  padding: 0.5rem;
  border: 1px solid silver;
  color: #222;
  background: #fff;
  border-radius: 5px;
  box-shadow: 0px 0px 5px 0px #a6a6a6;
  opacity: 0.9;
  position: absolute;
  font-size: 1.5rem;
}

/* ... */

The map is now fully responsive and scales nicely when the screen size changes. However, there is a lot of margin at the side of the map and especially on small screens we would rather like the map to fill up the space available. You can overwrite the margin of the container element in the CSS style sheet:

style.css - less margin for container
34
35
36
37
38
39
40
/* ... */

.container {
  width: 100%;
}

/* ... */

Instructions

We would like to add some instructions on how to use the map and we can add this in the HTML document.

index.html - instructions
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    <!-- ... -->
    <div class="container">
      <h3>Land use statistics map</h3>
      <div id="map"><!-- Map container --></div>

      <div id="details" class="hidden row"><!-- Details container --></div>
      <div id="initial">
        <h5>Instructions</h5>
        <ul>
          <li>Select a municipality to show the details.</li>
          <li>Scroll in the map to zoom in and out.</li>
        </ul>
      </div>
    </div>
    <!-- ... -->

We also set some margin at the top, same as for the details container.

style.css - top margin for instructions
20
21
22
23
24
25
26
/* ... */

#details, #initial {
  margin-top: 2rem;
}

/* ... */

And finally we want the initial instructions to disappear when the details of a feature are shown.

map.js - hide initial content when details are shown
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// ...

/**
 * 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);

  // Hide the initial container.
  d3.select('#initial').classed("hidden", true);

  // 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 12: Dropdown to select map key.

Code