block by emeeks 4414107

Parallel Coordinates wired to a map of routes from ORBIS

Full Screen

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
    <title>Route Probability Exploration with Parallel Coordinates</title>
    <style type="text/css">

svg {
  font: 10px sans-serif;
}

path {
  stroke-linejoin: round;
  stroke-linecap: round;
}

.routes {
  stroke-dasharray: 4, 7, 3, 8;
  stroke-width: 2.5;
}

.background path {
  fill: none;
  stroke: #ccc;
  stroke-opacity: .4;
  shape-rendering: crispEdges;
}

.foreground path {
  fill: none;
  stroke: #e04242;
  stroke-opacity: .5;
  stroke-width: 2;
}

.brush .extent {
  fill-opacity: .3;
  stroke: #fff;
  shape-rendering: crispEdges;
}

.axis line, .axis path {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.axis text {
  text-shadow: 0 1px 0 #fff;
  cursor: pointer;
}

    </style>
  </head>
  <body>
      <div id="map" style="border:0px solid gray; background-color:#fdfbf1;">
    </div>
      <div id="parallel" style="border:0px solid gray; background-color:#fdfbf1;">
    </div>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/d3.geo.projection.v0.min.js"></script>
<script src="//d3js.org/topojson.v0.min.js"></script>
    <script type="text/javascript">

    pathRamp=d3.scale.linear().domain([1,5,9,13]).range(["blue","green","orange","blue"]);    
    
var m = [30, 10, 10, 10],
    w = 1280 - m[1] - m[3],
    h = 300 - m[0] - m[2];

var x = d3.scale.ordinal().rangePoints([0, w], 1),
    y = {},
    dragging = {};

var line = d3.svg.line(),
    axis = d3.svg.axis().orient("left"),
    background,
    foreground;

mapsvg = d3.select("#map").append("svg:svg")
.attr("width", 1280)
.attr("height", 400)
;
    
var svg = d3.select("#parallel").append("svg:svg")
    .attr("width", w + m[1] + m[3])
    .attr("height", h + m[0] + m[2])
  .append("svg:g")
    .attr("transform", "translate(" + m[3] + "," + m[0] + ")");


d3.csv("sites.csv", function(csvin) {
	sitesdata = csvin;

  d3.json("lcroutes.json", function(error, lcroutes) {
    pathdata = topojson.object(lcroutes, lcroutes.objects.lcroutes).geometries;

  // Extract the list of dimensions and create a scale for each.
  x.domain(dimensions = d3.keys(pathdata[0]["properties"]).filter(function(d) {
    return d != "type" && d != "geometry" && (y[d] = d3.scale.linear()
        .domain(d3.extent(pathdata, function(p) { return +p["properties"][d]; }))
        .range([h, 0]));
//      .range([h, 0]));
  }));

  foreground = svg.append("svg:g")
      .attr("class", "foreground")
    .selectAll("path")
      .data(pathdata)
    .enter().append("svg:path")
      .attr("d", parallelPath)
      .style("stroke", function(d) {return (pathRamp(d.properties.month))})
      ;

  // Add a group element for each dimension.
  var g = svg.selectAll(".dimension")
      .data(dimensions)
    .enter().append("svg:g")
      .attr("class", "dimension")
      .attr("transform", function(d) { return "translate(" + x(d) + ")"; })
      .on("click", titleClick)

  // Add an axis and title.
  g.append("svg:g")
      .attr("class", "axis")
      .each(function(d) { d3.select(this).call(axis.scale(y[d])); })
    .append("svg:text")
      .attr("text-anchor", "middle")
      .attr("y", -9)
      .attr("class", "dimensionText")
      .text(String);

  // Add and store a brush for each axis.
  g.append("svg:g")
      .attr("class", "brush")
      .each(function(d) { d3.select(this).call(y[d].brush = d3.svg.brush().y(y[d]).on("brush", brush)); })
    .selectAll("rect")
      .attr("x", -8)
      .attr("width", 16);

  createMap();
  
	})
});

function titleClick(d) {
	var pmax = d3.max(pathdata, function(p) { return p["properties"][d]; })
	var pmin = d3.min(pathdata, function(p) { return p["properties"][d]; })
	var pq1 = (pmax * .25) + (pmin * .75);
	var pq2 = (pmax * .5) + (pmin * .5);
	var pq3 = (pmax * .75) + (pmin * .25);

	pathRamp=d3.scale.linear().domain([pmin,pq1,pq2,pq3,pmax]).range(["blue","green","gold","orange","red"]);	
	
	foreground.style("stroke", function(p) {return (pathRamp(p["properties"][d]))});
	d3.selectAll("path.routes").style("stroke", function(p) {return (pathRamp(p["properties"][d]))});
	
	}

function position(d) {
  var v = dragging[d];
  return v == null ? x(d) : v;
}

function transition(g) {
  return g.transition().duration(500);
}

// Returns the path for a given data point.
function parallelPath(d) {
  return line(dimensions.map(function(p) { return [position(p), y[p](d["properties"][p])]; }));
}

// Handles a brush event, toggling the display of foreground lines.
function brush() {
  var actives = dimensions.filter(function(p) { return !y[p].brush.empty(); }),
      extents = actives.map(function(p) { return y[p].brush.extent(); });
  foreground.style("display", function(d) {
    return actives.every(function(p, i) {
      return extents[i][0] <= d["properties"][p] && d["properties"][p] <= extents[i][1];
    }) ? null : "none";
  });
  
  d3.selectAll("path.routes").style("display", function(d) {
	    return actives.every(function(p, i) {
	      return extents[i][0] <= d["properties"][p] && d["properties"][p] <= extents[i][1];
	    }) ? null : "none";
	  });
}

/////////////THE MAP

function createMap(){

	rankRamp=d3.scale.linear().domain([0,.005]).range([1,10]).clamp(true);	

projection = d3.geo.satellite()
    .distance(1.1)
    .scale(1000)
    .rotate([-15, -43, -10])
    .center([-3, -4.5])
    .tilt(25)
    .clipAngle(1000);
    
var graticule = d3.geo.graticule()
    .extent([[180, 180], [-180, -180]])
    .step([5, 5]);

path = d3.geo.path()
    .projection(projection);

siteLabel = mapsvg.append("svg:text")
.attr("x", 20)
.attr("y", 20)
.text("Click site for details");

sprLabel = mapsvg.append("svg:text")
				.attr("x", 20)
				.attr("y", 40)
				.text("PS");

  smLabel = mapsvg.append("svg:text")
  .attr("x", 20)
  .attr("y", 60)
  .text("PSM");

map = mapsvg.append("svg:g").attr("class", "map")
.attr("transform", "translate(2,3)")

  d3.json("rltopo.json", function(error, rltopo) {

/*  
  map.append("path")
    .datum(graticule)
    .attr("class", "graticule")
    .attr("d", path);
    */
  	      
  embossed = map.selectAll("path.routes")
      .data(topojson.object(rltopo, rltopo.objects.romeland).geometries)
    .enter().insert("path")
      .attr("d", path)
      .attr("class", "countries")
      .style("fill", "ghostwhite")
      .style("stroke", "lightgray")
      .style("stroke-width", 2)

  sites = map.selectAll("g.sites")
  .data(sitesdata)
  .enter()
  .append("svg:g")
  .attr("class", "foreground")
  .attr("transform", function(d) {return "translate(" + projection([d.xcoord,d.ycoord]) + ")";})
  .style("cursor", "pointer")
  .on("click", siteClick)
  ;

  circleRamp=d3.scale.linear().domain([0,4,7,11,15,19,23]).range(["red","purple","orange","blue","steelblue","green","yellow"]);
  
sites.append("svg:circle")			      
  .attr('r', function(d) {return (rankRamp(d.ES))})
  .attr("class", "sites")
  .style("fill", function(d) {return (circleRamp(d.EM))})
  .style("stroke", "white")
  .style("opacity", 0)
  .transition()
  .delay(300)
  .duration(1000)
  .style("opacity", .35)
  ;
  
  baseRoads = map.selectAll("path.routes")
  .data(pathdata)
    .enter().insert("path")
      .attr("class", "lcroutes")
      .attr("d", path)
.style("fill", "none")
.style("stroke-width", 2)
//.style("stroke", 2)
.style("stroke", function(d) {return (pathRamp(d.properties.month))})
.attr("class", "routes")      


/* baseRoads = map.selectAll("path.routes")
.data(pathdata)
.enter().append("svg:path")
.style("fill", "none")
.style("stroke", function(d) {return (pathRamp(d.month))})
.attr("d", path)
.attr("class", "routes")
.style("opacity", 0)
    .transition()
    .duration(1000)
    .style("opacity", .2)
	      ;
*/

}
)
}

function siteClick(d,i) {
	siteLabel.text(d.name);
	sprLabel.text("Ranking - Economic: " + d.ES + " - Military: " + d.MS + " - Rapid: " + d.RS );
	smLabel.text("Modules - Economic: " + d.EM + " - Military: " + d.MM + " - Rapid: " + d.RM );
}

mapsvg.on("click", function() {
    p = projection.invert(d3.mouse(this));
   console.log(p);
   projection.rotate([-(p[0]), -(p[1])]);
   mapsvg.selectAll("path").transition().duration(1000).attr("d", path);
     sites.transition().duration(1000).attr("transform", function(d) {return "translate(" + projection([d.xcoord,d.ycoord]) + ")";})

});


    </script>
  </body>
</html>