2012-08-29 106 views
1

我正在实施经典的mercator示例(https://github.com/mbostock/d3/blob/master/examples/mercator/mercator.html),我已将其更改为放大到阿富汗并只使用一个自定义滑块。我正在阅读发生爆炸的地方的GeoJSON数据,并且图表将它们全部映射到负载。我想使用滑块一次仅查看一个月的爆炸点,但无法筛选结果。我根据Google群组中的帖子尝试了几件事,但未能理解如何过滤之前从“explosions.json”中读取的数据。谢谢您的帮助!D3过滤数据点

<!DOCTYPE html> 
    <html> 
    <head> 
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> 
<title>IED Attacks in Afghanistan (2004-2009)</title> 
<script type="text/javascript" src="../d3.v2.js"></script> 
<script type="text/javascript" src="../lib/jquery/jquery.min.js"></script> 
<script type="text/javascript" src="../lib/jquery-ui/jquery-ui.min.js"></script> 
<style type="text/css"> 

    @import url("../lib/jquery-ui/jquery-ui.css"); 

    body, .ui-widget { 
    font: 14px Helvetica Neue; 
    } 

    svg { 
    width: 960px; 
    height: 600px; 
    border: solid 1px #ccc; 
    background: #eee; 
    } 

    line { 
    stroke: brown; 
    stroke-dasharray: 4,2; 
    } 

    path { 
    fill: #ccc; 
    stroke: #fff; 
    } 

    div { 
    width: 960px; 
    } 

</style> 
</head> 
<body> 
<h3>IED Attacks in Afghanistan (2004-2009)</h3> 
<script type="text/javascript"> 

     // Create the Mercator Projection (Map) 
     var xy = d3.geo.mercator(), 
      path = d3.geo.path().projection(xy); 


     // Create the states variable 
     var states = d3.select("body") 
     .append("svg") 
     .append("g") 
      .attr("id", "states"); 
     // Create the equator variable 
     var equator = d3.select("svg") 
     .append("line") 
      .attr("x1", "0%") 
      .attr("x2", "100%"); 
     // Create the explosions variable 
     var explosions = d3.select("svg") 
     .append("g") 
      .attr("id","explosions"); 

     // Load in the states & equator data from the file 'world-countries.json' 
     d3.json("world-countries.json", function(collection) { 
      states 
       .selectAll("path") 
       .data(collection.features) 
       .enter().append("path") 
       .attr("d", path) 
       .append("title") 
       .text(function(d) { return d.properties.name; }); 
      equator 
       .attr("y1", xy([0, 0])[1]) 
       .attr("y2", xy([0, 0])[1]); 
     }); 

     // the variable that holds our translate, center on Afghanistan 
     var translate = xy.translate(); //create translation to center gride in different area 
     translate[0] = -1741; 
     translate[1] = 1487; 
     xy.translate(translate); // center 

     xy.scale(12000); //zoom in 

     // Load in the explosions data from the file 'explosions.json' 
     d3.json("explosions.json", function(collection) { 
      explosions 
       .selectAll("path") //make a path and attach data 
       .data(collection.features) 
       .enter().append("path") 
       .attr("d", path) 
       .style("stroke","red") //color the path points 
       .style("stroke-width",2) //size of point stroke 
       .attr("class","explosionpoint") 
       .append("title") //title is the 'name' field in the json file 
       .text(function(d) { return d.properties.name; }); 
     }); 



    </script> 

    <p></p> 
    <!-- Slider --> 
    <div id="scale"></div><p></p> 
    <script type="text/javascript"> 

     $("#scale").slider({ 
     min: 20040101, //min : 1/1/04 
     max: 20100101, //max: 1/1/10 
     value: 20060601, //default slider value 
     step: 100, // step is the allow increments the slider can move. 100 = one month 
     slide: function(event, ui) { 


      /* REMOVE ALL EXPLOSION PATHS EXCEPT FOR A PARTICULAR MONTH OR RELOAD WITH FILTERED RESULTS */ 
     } 
     }); 

</script> 

回答

4

你需要发布的部分或全部的explosions.json对象的一个​​具体的答案。但是,如果它的结构类似于{explosion1:{data1:true, data2:true}, explosion2:{data1:true, data2:false}}像这样将筛选JSON:

function filterJSON(json, key, value) { 
    var result = {}; 
    for (var explosionIndex in json) { 
    if (json[explosionIndex][key] === value) { 
     result[explosionIndex] = json[explosionIndex]; 
    } 
    } 
    return result; 
} 

(例如filterJSON(myjson, "data1", true)将给予所有DATA1爆炸:真)

这不是特定于D3。

然后,你可以使用类似这样的事情在D3方:

explosions.data(myFilteredData).exit().remove(); // remove ones you don't want 
explosions.enter().append("path")... // add back ones you do want 

如果我理解你的应用程序,它实际上是更好的只是切换SVG元素的visiblity属性。

var sliderrange = [20040101, 20040201]; //replace with code based on your slider 
explosions.selectAll(".explosionpoint").attr("visibility", function(d) { 
    //Replace with the correct date comparison logic 
    return d.date < sliderrange[1] && d.date > sliderrange[0] ? "visible" : "hidden"; 
}); 
+1

谢谢Zach。是的,我最终通过在开始时绘制所有点(如上所述),然后在'block'和'none'之间切换每个点的显示值来过滤点。这操作很快,可能比重新加载过滤的数据更好。 – user1245530

2

D3确实有一个非常自然的方式来做到这一点。我假设你的数据看起来是这样的:

[{name: explosion1name, day: 20040110,...}, {name: explosion2name, day: 20040111,...}] 

...那你有一些变量,我们把它叫做explosionsData,以引用数据。

然后,您可以使用从滑块获取值的函数绘制爆炸图。请参阅下面我添加的.filter

function drawExplosions(startDay, endDay) { 
    explosions.selectAll("path") //make a path and attach data 
      .data(collection.features) 
      .enter().append("path") 
      .filter(function (d) { return ((d.day > startDay) && (d.day < endDay))}) 
      .attr("d", path) 
      .style("stroke","red") //color the path points 
      .style("stroke-width",2) //size of point stroke 
      .attr("class","explosionpoint") 
      .append("title") //title is the 'name' field in the json file 
      .text(function(d) { return d.properties.name; }); 

只要你的滑块值发生变化就调用这个函数。