Mercator projection with (.countries) tooltip push

17 views
Skip to first unread message

françois Manley

unread,
May 17, 2017, 4:42:43 AM5/17/17
to d3-js
Hello everybody,

I'm a beginner with d3.
I manage to build a projection in a html wrapper.

I also managed to build a tooltip as long as my mouse pointer hovers a country which ID matches both topojson / countriesRando.txt's.
Also a few CSS styling.

I'd like to be able to push my CSV / TXT data fields (pop / modulo / id) inside my tooltip.
It looks like so far i manage to display in the tooltip the topojson country's ID but not the one in the CSV / TXT file.

How could i manage this?
Thank you very much for the help.

F.


:DOCTYPE html>
<html lang="en">
<head>
   
<meta charset="utf-8">
   
<title>d3 choropleth map</title>
    <link rel="stylesheet" href="css/
styles.css">
    <!--[if IE]>
        <script src="
http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
   
<![endif]-->
</head>
<body>
    <div id="wrapper">    
           <h1> Choropleth classic + tooltip</
h1>
           
<div id="map"></div>
     
   
</div>

<script src="js/
d3.v3.min.js"></script>
<script src="
js/queue.v1.min.js"></script>
<script src="
js/topojson.v1.min.js"></script>
<script src="
js/d3.geo.projection.v0.min.js"></script>
<script src="
js/main.js"></script>

</body>
</html>



//globals
 
var projection, path, graticule, svg, div, tooltip, borders, impacts, attributeArray = [], currentAttribute = 0, playing = false;

 
var width = 1000,
  height
= 650;

  projection
= d3.geo.eckert5()   // define our projection with parameters
   
.center([5, 25]) // x, y natural position of the map when loading
   
.scale(215) //mapscale (natural zoom-in/out when loading page)
   
.rotate([-1,0]) //slides the map on a x-axis in its SVG box
   
.precision(.50);

  path
= d3.geo.path()  // create path generator function
     
.projection(projection);  // add our define projection to it

 
//graticule = d3.geo.graticule(); // create a graticule

 
var zoom = d3.behavior.zoom()
   
.translate(projection.translate())
   
.scale(projection.scale())
   
.scaleExtent([height*.33, 15 * height]) // manage zoom strength [out, in]
   
.on("zoom", zoom);

  svg
= d3.select("#map").append("svg")   // append a svg to our html div to hold our map
     
.attr("width", width)
     
.attr("height", height)
     
.call(zoom);

 
function zoom() {
  projection
.translate(d3.event.translate).scale(d3.event.scale);
  svg
.selectAll("path").attr("d", path);
  circles
   
.attr("cx", function(d){return proj([d.long, d.lat])[0];})
   
.attr("cy", function(d){return proj([d.long, d.lat])[1];});
 
}

  svg
.append("defs").append("path")   // prepare some svg for outer container of svg elements
     
.datum({type: "Sphere"})
     
.attr("id", "sphere")
     
.attr("d", path);

  svg
.append("use")   // use that svg to style with css
     
.attr("class", "stroke")
     
.attr("xlink:href", "#sphere");

  svg
.append("path")    // use path generator to draw a graticule
     
.datum(graticule)
     
.attr("class", "graticule")
     
.attr("d", path);

  div
= d3.select("body")
           
.append("div")  
           
.attr("class", "tooltip")              
           
.style("opacity", 0);

  tooltip
= d3.select("body").append("div")
   
.attr("class", "tooltip")
   
.style("opacity", 0.1)
   
.style("background", "");

  borders
= svg.append("g");
  impacts
= svg.append("g");


  queue
()   // queue function loads all external data files asynchronously
   
.defer(d3.json, "data/world-topo.json")  // our geometries
   
.defer(d3.tsv, "data/countriesRandom.txt")  // and associated data in csv file
   
.await(processData);   // once all files are loaded, call the processData function passing
                           
// the loaded objects as arguments

var metors;
function processData(error,world,countryData) {
 
// function accepts any errors from the queue function as first argument, then
 
// each data object in the order of chained defer() methods above

 
var countries = world.objects.countries.geometries;  // store the path in variable for ease
 
for (var i in countries) {    // for each geometry object
   
for (var j in countryData) {  // for each row in the CSV
     
if(countries[i].properties.id == countryData[j].id) {   // if they match
       
for(var k in countryData[i]) {   // for each column in the a row within the CSV
         
if(k != 'name' && k != 'id') {  // let's not add the name or id as props since we already have them
           
if(attributeArray.indexOf(k) == -1) {
               attributeArray
.push(k);  // add new column headings to our array for later
           
}
            countries
[i].properties[k] = Number(countryData[j][k])  // add each CSV column key/value to geometry object

         
}
       
}
       
break;  // stop looking through the CSV since we made our match
     
}
   
}
 
}
    rawMetors
= countryData;

    metors
= [];
    rawMetors
.forEach(function(d){
        d
.degree = +d.id;
        d
.popu = +d.pop;
        metors
.push(d);

   
});
    metors
.sort(function(a, b){return a.degree - b.degree;})
    console
.log(metors)

    svg
.selectAll(".country")   // select country objects (which don't exist yet)

     
.data(topojson.feature(world, world.objects.countries).features)  // bind data to these non-existent objects
     
.enter().append("path") // prepare data to be appended to paths
     
.attr("class", "country") // give them a class for styling and access later
     
.attr("id", function(d) { return "code_" + d.properties.id; }, true)  // give each a unique id for access later
     
.attr("d", path) // create them using the svg path generator defined above
     
         
.on("mouseover", function(d){
                  div
.transition()
                 
.duration(100)
               
.style("opacity", .9)

                tooltip
               
.style("left", (d3.event.pageX + 5) + "px")
               
.style("top", (d3.event.pageY - 5) + "px")
               
.transition().duration(300)
               
.style("opacity", 100)
               
.style("display", "block")
                updateDetails
(d);
               
})

     
.on("mouseout", function(d){
                div
.transition()
               
.attr("stroke", "")
               
.attr("fill-opacity", function(d){return 1;})
               
.duration(500)
               
.style("opacity", .001)

                tooltip
.transition().duration(200).style("opacity", 0);
               
})

   
var dataRange = getDataRange(); // get the min/max values from the current year's range of data values
    d3
.selectAll('.country')  // select all the countries
   
.attr('fill-opacity', function(d) {
       
return getColor(d.properties[attributeArray[currentAttribute]], dataRange);  // give them an opacity value based on their current value
   
});
}

function getColor(valueIn, valuesIn) {

 
var color = d3.scale.linear() // create a linear scale
   
.domain([valuesIn[0],valuesIn[1]])  // input uses min and max values
   
.range([.3,1]);   // output for opacity between .3 and 1 %

 
return color(valueIn);  // return that number to the caller
}

function getDataRange() {
 
// function loops through all the data values from the current data attribute
 
// and returns the min and max values

 
var min = Infinity, max = -Infinity;  
  d3
.selectAll('.country')
   
.each(function(d,i) {
     
var currentValue = d.properties[attributeArray[currentAttribute]];
     
if(currentValue <= min && currentValue != -99 && currentValue != 'undefined') {
        min
= currentValue;
     
}
     
if(currentValue >= max && currentValue != -99 && currentValue != 'undefined') {
        max
= currentValue;
     
}

 
});
 
return [min,max];  //boomsauce
}


var printDetails = [{'var': 'id', 'print': 'Entity'},
                   
{'var': 'pop', 'print': 'Population'},
                   
{'var': 'cartodb_id', 'print': 'ID de carte'}];


function updateDetails(metor){
   
// this section is unecessary if we don't want the image
   
//var image = new Image();
   
//image.onload = function(){
       
//document.getElementById("tooltipImg").src = 'pictures/' + metor.cartodb_id + '.jpg';}
   
//image.src = 'pictures/' + metor.cartodb_id + '.jpg';

    tooltip
.selectAll("div").remove();
    tooltip
.selectAll("div").data(printDetails).enter()
       
.append("div")
           
.append('span')
               
.text(function(d){return d.print + ": ";})                
               
.attr("class", "boldDetail")
           
.insert('span')
               
.text(function(d){return metor[d.var];})
               
.attr("class", "normalDetail");
}

de ici
...


Reply all
Reply to author
Forward
0 new messages