Skip to content
Niene edited this page Aug 14, 2017 · 13 revisions

Interactivity: Mouse over action!

Wouldn't it be cool to add some animation to your map? Make it react to our mouse actions?

Let's see, when the mouse moves over the world map, we can create a function for it. This is a function for the things that have to happen when the mouse moves over a country:

// Create Event Handlers for mouse
function handleMouseOver(d, i) {  // Add interactivity
// Use D3 to select element, change color 
  d3.select(this)
    .style("fill", "orange");
};

A JavaScript function is a block of code designed to perform a particular task. A JavaScript function is executed when "something" invokes it (calls it). A JavaScript function is defined with the function keyword, followed by a name, followed by parentheses (). The parentheses may include parameter names separated by commas (parameter1, parameter2, ...). The code to be executed, by the function, is placed inside curly brackets: {}

The code inside the function will execute when "something" invokes (calls) the function:

  • When an event occurs (when a user clicks a button)
  • When it is invoked (called) from JavaScript code
  • Automatically (self invoked)

Let's explain our function

ℹ️ Our function is called handleMouseOver and takes has no arguments.

ℹ️ The code to be executed is a d3 function. With d3 we select the object the mouse is on and give it a new style property. "fill" , "orange"

So this is only the function. You can add it to your code, but nothing will happen until you ivoke the function somewhere else.

We want to evoke this function when the mouse is on a path. With D3 we can add a action to the objects.

▶️ Add `.on("mouseover", handleMouseOver) to the world map paths!

layerWorld.selectAll("path")
           .data(json.features)
           .enter()
           .append("path")
           .attr("d", path)
           .style("fill", "#313030")
           .style("stroke", "#5a5959")
           .on("mouseover", handleMouseOver);

Now see what happens on your map when you move your mouse around! Of course we also want the color to disappear again. For this we need a new function for the mouse-out action. We call this function handleMouseOut.

▶️ Add it to your code.

function handleMouseOut(d, i) {
// Use D3 to select element, change color back to normal
  d3.select(this)
    .style("fill", "#313030")
};

▶️ And add the action to our layerWorld!

  .on("mouseout", handleMouseOut);

▶️ See if you can find any other mouse actions by using the internet. For example .on("mousedown", ..) Tip: any DOM event type supported by your browser may be used.

▶️ Also see if you can adjust the code to be executed in the function! What do you want to make happen?

Data Driven Styling

The world data actually has a lot of attributes. We can use these attributes for styling the data! To see what attributes are available in the data set we can do 3 things.

  1. Open the GeoJSON file with your text editor to see the raw data.
  2. Let the browser print your data set in the console.
  3. Open the GeoJSON file in Qgis for example.

Let's try the first 2!

▶️ 1. Open the GeoJSON file with your text editor. This might take a little while because the dataset is quite big. This is what it looks like:

{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"scalerank":1,"featurecla":"Admin-0 country","labelrank":3,"sovereignt":"Afghanistan","sov_a3":"AFG","adm0_dif":0,"level":2,"type":"Sovereign country","admin":"Afghanistan","adm0_a3":"AFG","geou_dif":0,"geounit":"Afghanistan","gu_a3":"AFG","su_dif":0,"subunit":"Afghanistan","su_a3":"AFG","brk_diff":0,"name":"Afghanistan","name_long":"Afghanistan","brk_a3":"AFG","brk_name":"Afghanistan","brk_group":"","abbrev":"Afg.","postal":"AF","formal_en":"Islamic State of Afghanistan","formal_fr":"","note_adm0":"","note_brk":"","name_sort":"Afghanistan","name_alt":"","mapcolor7":5,"mapcolor8":6,"mapcolor9":8,"mapcolor13":7,"pop_est":28400000,"gdp_md_est":22270,"pop_year":-99,"lastcensus":1979,"gdp_year":-99,"economy":"7. Least developed region","income_grp":"5. Low income","wikipedia":-99,"fips_10":"","iso_a2":"AF","iso_a3":"AFG","iso_n3":"004","un_a3":"004","wb_a2":"AF","wb_a3":"AFG","woe_id":-99,"adm0_a3_is":"AFG","adm0_a3_us":"AFG","adm0_a3_un":-99,"adm0_a3_wb":-99,"continent":"Asia","region_un":"Asia","subregion":"Southern Asia","region_wb":"South Asia","name_len":11,"long_len":11,"abbrev_len":4,"tiny":-99,"homepart":1},"geometry":{"type":"Polygon","coordinates":[[[61.210817091725744,35.650072333309225],[62.230651483005886,35.270663967422294],[62.98466230657661,35.40404083916762],[63.19353844590035,35.857165635718914],[63.98289594915871,36.0079574651466],[64.5464791197339,36.31207326918427],[64.7461051776774,37.111817735333304],[65.58894778835784,37.30521678318564],[65.74563073106683,37.66116404881207],[66.21738488145934,37.39379018813392],[66.51860680528867,37.36278432875879],[67.07578209825962,37.35614390720929],[67.82999962755952,37.144994004864685],[68.13556237170138,37.02311513930431],[68.85944583524594,37.344335842430596],[69.19627282092438,37.15114350030743],[69.51878543485796,37.60899669041342],[70.11657840361033,37.58822276463209],[70.27057417184014,37.735164699854025],[70.3763041523093,38.13839590102752],[70.80682050973289,38.486281643216415],[71.34813113799026,38.25890534113216],[71.23940392444817,37.953265082341886],[71.54191775908478,37.905774441065645],[71.44869347523024,37.06564484308052],[71.8446382994506,36.73817129164692],[72.1930408059624,36.948287665345674],[72.63688968291729,37.047558091778356],[73.26005577992501,37.495256862939],[73.9486959166465,37.4215662704908],[74.98000247589542,37.419990139305895],[75.15802778514092,37.13303091078912],[74.57589277537298,37.02084137628346],[74.06755171091783,36.83617564548845],[72.92002485544447,36.72000702569632],[71.84629194528392,36.50994232842986],[71.26234826038575,36.074387518857804],[71.49876793812109,35.650563259416],[71.61307620635071,35.153203436822864],[71.11501875192164,34.733125718722235],[71.15677330921346,34.34891144463215],[70.8818030129884,33.98885590263852],[69.9305432473596,34.02012014417511],[70.3235941913716,33.35853261975839],[69.68714725126486,33.105498969041236],[69.26252200712256,32.5019440780883],[69.31776411324256,31.901412258424443],[68.92667687365767,31.620189113892067],[68.55693200060932,31.713310044882018],[67.79268924344478,31.58293040620963],[67.68339358914747,31.30315420178142],[66.93889122911847,31.304911200479353],[66.38145755398602,30.738899237586452],[66.34647260932442,29.887943427036177],[65.0468620136161,29.472180691031905],[64.35041873561852,29.560030625928093],[64.14800215033125,29.340819200145972],[63.55026085801117,29.468330796826166],[62.54985680527278,29.31857249604431],[60.87424848820879,29.829238999952608],[61.781221551363444,30.735850328081238],[61.69931440618083,31.379506130492672],[60.94194461451113,31.548074652628753],[60.863654819588966,32.18291962333443],[60.536077915290775,32.98126882581157],[60.963700392506006,33.52883230237626],[60.52842980331158,33.676446031218006],[60.80319339380745,34.40410187431986],[61.210817091725744,35.650072333309225]]]}},
....
]
}

▶️ 2. Put a console.log(data); line in your code after the call for the data to view your dataset in the browser. So you get:

//Call the geojson data
d3.json("world.geojson", function(json) {
        
  //view the data
  console.log(json);
  
  //Bind data and create one path per GeoJSON feature
        layerWorld.selectAll("path")
           .data(json.features)
           .enter()
           ...

▶️ Go to the browser, refresh and open the debugger. Go to the Web console tab. Here you will see your Object printed.

  • Click with your right mouse button, choose : Inspect Element
  • Or Press F12

▶️ Click the object and go through the nice drop down view of your dataset to explore what it contains!

The GeoJSON FeatureCollection contains Features which each exist out of properties and a geometry.

Choropleth

We can use these attributes to style the map. Let's try to make a Choropleth out of our world map.

▶️ First, center the map in your browser, so you can view the whole world in your screen!! This is difficult, but go ahead and try!

To make a color scheme we need an extra d3 package. The scale-chromatic library. This contains several color scales. Have a look at https://github.com/d3/d3-scale-chromatic for all the possibilities!

▶️ Put the library in the <head> of your index.html

<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>

▶️ with the following code you create a color range!

var color = d3.scaleThreshold()
    .domain(d3.range(0, 8))
    .range(d3.schemeBlues[8]);

ℹ️ the .domain is the data range, the attribute we use only has values from 0 to 8. Note! If you take another attribute you should also adjust the domain accordingly!

ℹ️ the .range is the color range. We use the Blue schema with 8 steps.

ℹ️ The d3.scaleTreshold() function converts our domain to our range. Here it is exactly the same, but your domain can be much bigger or smaller. The threshold scale allows you to specify arbitrary breaks in continuous data.

Have a look at https://github.com/d3/d3-scale for all the D3 scales available!

▶️ Now we still need to add a function to our paths that gives it the right color on the attributes. Change the .style("fill", "#313030") to:

.style("fill", function(d){
      return color(d.properties.mapcolor7)
    })

Do you notice that our mouse-out action resets the color of the countries to grey again?

▶️ Let's try to fix this! Make sure the countries get their right color back. If you can't manage, ask for help.

➡️ Continue to D3 step 3 if you feel really confident! If you are almost running out of time it might be nice to spend the last bit of the workshop on putting your map on-line! Go to the Hosting on Github to learn how!