2013-04-24 106 views
0

我是一個社會科學人員越來越多地進入網絡編程的數據工作,所以如果這個問題是愚蠢的道歉。我正在製作一個polymaps實現,以便隨時間推移顯示國家級數據。我讀入json時間數據和一個geojson世界地圖,並吐出一個分位數緯線圖,該地圖對每月的條目進行迭代。這個核心是一個國家格式化函數,將colorbrewer類綁定到國家geojson對象(見下文)。這適用於動畫部分。問題是我正在使用顯示當前顯示的數據的日期的自定義d3圖層充當mouseover控件以停止動畫並選擇日期或在動畫完成後選擇日期。它通過創建一個使用d3.scale()函數的鼠標svg元素將鼠標輸入四捨五入到與所需月份的索引相匹配的整數來完成此操作。我已經加載了所有其他的計算負載,以便鼠標懸停時發生的唯一情況是svg類的變化(這與Tom Carden在Bostock的d3頁here上實現的豐富國家基本相同)。不幸的是,這仍然很快超載瀏覽器。有沒有另一種方法可以做到這一點,我完全失蹤了?我承認我是geojson的新成員,所以也許用geojson對象的class屬性來構建一個類的數組呢?感謝大量的幫助。處理Polymaps中的類屬性分配

  function foo(local, geojson){ 
       for(var x=0;x<geojson.length;x++){ 
        var n = geojson[x].data.properties.name; 
        n$(geojson[x].element) 
         .attr("class", geojson[x].data.formats[local]) 
         .add("svg:title"); 
       } 
      } 

編輯:我在下面添加完整的腳本。

<meta charset="utf-8"> 
<script src="scripts/d3.v3.js"></script> 
<script src="scripts/polymaps.js"></script> 
<script src="scripts/nns.js"></script> 

<script> 
    //Polymaps namespace 
    var po = org.polymaps; 

    //Chart dimensions 
    var margin = {top: 20, right: 20, bottom: 20, left: 20}; 
    var w = 960 - margin.right; 
    var h = 500 - margin.top - margin.bottom; 

    // Create the map object, add it to #map div 
    var map = po.map() 
     .container(d3.select("#map").append("svg:svg").attr("width", w + margin.left + margin.right).attr("height",h +margin.top + margin.bottom).node()) 
     .center({lat: 28, lon: 0}) 
     .zoom(1.85) 
     .zoomRange([1.5, 4.5]) 
     .add(po.interact()); 

    // Add the CloudMade image tiles as a base layer… 
    map.add(po.image() 
     .url(po.url("http://{S}tile.cloudmade.com" 
     + "/1a1b06b230af4efdbb989ea99e9841af" // http://cloudmade.com/register 
     + "/20760/256/{Z}/{X}/{Y}.png") 
     .hosts(["a.", "b.", "c.", ""]))); 

    //Import contribution data 
    d3.json("assets/contributionsTCC1990-1991.json", function(data){ 
     //find length of json data object and loop over it at interval 
     var dataLength = Object.keys(data).length; 

     //Create date key/value array using construtor 
     function date_array_constructor() { 
      var dateArray = {}; 
       for(var i = 0; i < dataLength; i++) { 
        var d = i + 1; 
        dateArray[d] = data[i].date; 
       } 
      return dateArray; 
     } 
     var dateArray = date_array_constructor(); 

     // Insert date label/control layer and add SVG elements that take on attributes determined by load function 
     var labelLayer = d3.select("#map svg").insert("svg:g"); 
     map.add(po.geoJson() 
      .url("assets/world.json") 
      .tile(false) 
      .zoom(3) 
      .on("load", load)); 
     map.container().setAttribute("class", "Blues"); 
     map.add(po.compass() 
      .pan("none")); 

     function find_max(data, dataLength) { 
      var max = 0; 
      for(var i in data) { 
       if(data[i] > max) { 
        max = data[i] + 1; 
       } 
      } 
      return max; 
     } 

     function max_array_constructor(data, dataLength) { 
      var maxArray = {}; 
      for(var i=0;i<dataLength;i++) { 
       var d = i+1; 
       maxArray[d] = find_max(data[i].contributions); 
      } 
      return maxArray; 
     } 
     var maxArray = max_array_constructor(data, dataLength); 

     function contribution_array_constructor(data, dataLength, tccName, feature) { 
      var contributions = {}; 
      //iterate over date entries 
      for(var i=0;i<dataLength;i++) { 
       //contribution iterator 
       contributions[i+1] = 0; 
       for(x in data[i].contributions){ 
        if(x == tccName) { 
         contributions[i+1] = data[i].contributions[x]; 
        } 
       } 
      } 
      return contributions; 
     } 


     function format_array_constructor(data, dataLength, maxArray, feature) { 
      var formats = {}; 
      // console.log(feature.data.contributions); 
      //iterate over date entries 
      for(var i=0;i<dataLength;i++) { 
       var percentile = feature.data.contributions[i+1]/maxArray[i+1]; 
       if(percentile != 0){ 
        var v = "q" + ((~~(percentile*7)) + 2) + "-" + 9; 
       }else{ 
        var v = "countries"; 
       } 
       formats[i+1] = v; 
      } 
      return formats; 
     } 


     /////////////////////////////// 
     //load function 
     /////////////////////////////// 
     function load(e) { 
      //Bind geojson and json 
      var geojson = e.features; 
      console.log(geojson); 
      geojson.dates = dateArray; 
      for(var x = 0; x < geojson.length; x++) { 
       // var tccID = geojson[x].data.id; 
       var tccName = geojson[x].data.properties.name; 
       geojson[x].data.contributions = contribution_array_constructor(data, dataLength, tccName, geojson[x]); 
       geojson[x].data.formats = format_array_constructor(data, dataLength, maxArray, geojson[x]); 
      } 


      //Insert date label 
      var dateLabel = labelLayer.append("text") 
       .attr("class", "date label") 
       .attr("text-anchor", "end") 
       .attr("x", w-670) 
       .attr("y", h) 
       .text(dateArray[1]); 

      //Add interactive overlay for date label 
      var box = dateLabel.node().getBBox(); 

      var overlay = labelLayer.append("rect") 
       .attr("class", "overlay") 
       .attr("x", box.x) 
       .attr("y", box.y) 
       .attr("opacity",0) 
       .attr("width", box.width) 
       .attr("height", box.height) 
       .on("mouseover",enable_interaction); 


      function country_class_constructor(local, geojson){ 
       for(var x=0;x<geojson.length;x++){ 
        var n = geojson[x].data.properties.name; 
        n$(geojson[x].element) 
         .attr("class", geojson[x].data.formats[local]) 
         .add("svg:title"); 
       } 
      } 

      function foo(local, geojson){ 
       for(var x=0;x<geojson.length;x++){ 
        var n = geojson[x].data.properties.name; 
        n$(geojson[x].element) 
         .attr("class", geojson[x].data.formats[local]) 
         .add("svg:title"); 
       } 
      } 

      //incrementor function 
      function incrementor(local, geojson, dateArray) { 
       setTimeout(function() { 
        //set date label to current iteration 
        d3.transition(dateLabel).text(dateArray[local]); 
        //construct country classes 
        country_class_constructor(local, geojson); 
        // console.log(geojson); 
       }, 500*local); 
      } 

      /////////////////////////////// 
      //Increment on load 
      /////////////////////////////// 
      country_class_constructor(1, geojson) 
      for(var i=1; i< dataLength; i++) { 
       //Set incrementer as local variable 
       var local = i+1; 
       var timer = incrementor(local, geojson, dateArray); 
      } 


      /////////////////////////////// 
      //interaction element 
      /////////////////////////////// 
      function enable_interaction(){ 
       var dateScale = d3.scale.linear() 
        .domain([1,Object.keys(dateArray).length]) 
        .range([box.x + 10, box.x + box.width - 10]) 
        .clamp(true); 

      timer = null; 


       overlay 
        .on("mouseover", mouse_over) 
        .on("mouseout",mouse_out) 
        .on("mousemove",mouse_move) 
        .on("touchmove",mouse_move); 

       function mouse_over() { 
        dateLabel.classed("active", true); 
       } 

       function mouse_out() { 
        dateLabel.classed("active", false); 
       } 

       function mouse_move() { 
        update_map(dateScale.invert(d3.mouse(this)[0]),data); 
        // displayYear(dateScale.invert(d3.mouse(this)[0])); 
       } 

       function update_map(userInput) { 
        var date = Math.floor(userInput); 
        d3.transition(dateLabel).text(dateArray[date]); 
        // console.log(date); 
        // country_class_constructor(date, geojson); 
        foo(date, geojson); 
       } 
      } 
     } 
    }); 
</script> 

編輯2:我忘了添加JSON格式。請參閱下面兩個月的數據:

[ 
{"date":"11/90", 
"contributions":{ 
    "Algeria":7, 
    "Argentina":39, 
    "Australia":41, 
    "Austria":967, 
    "Bangladesh":5, 
    "Belgium":4, 
    "Brazil":27, 
    "Canada":1002, 
    "Chile":7, 
    "China":5, 
    "Colombia":12, 
    "Czech Republic":6, 
    "Denmark":374, 
    "Ecuador":21, 
    "Fiji":719, 
    "Finland":992, 
    "France":525, 
    "Germany":13, 
    "Ghana":892, 
    "Hungary":15, 
    "India":40, 
    "Indonesia":5, 
    "Ireland":814, 
    "Italy":79, 
    "Jordan":6, 
    "Kenya":7, 
    "Malaysia":15, 
    "Nepal":851, 
    "Netherlands":15, 
    "New Zealand":22, 
    "Nigeria":2, 
    "Norway":924, 
    "Poland":165, 
    "Republic of the Congo":6, 
    "Russia":35, 
    "Senegal":4, 
    "Serbia":17, 
    "Spain":63, 
    "Sweden":738, 
    "Switzerland":5, 
    "Turkey":2, 
    "United Kingdom":769, 
    "United States":33, 
    "Uruguay":10, 
    "Venezuela":23, 
    "Zambia":6 
} 
}, 
{"date":"12/90", 
"contributions":{ 
    "Algeria":7, 
    "Argentina":39, 
    "Australia":41, 
    "Austria":967, 
    "Bangladesh":5, 
    "Belgium":4, 
    "Brazil":27, 
    "Canada":1002, 
    "Chile":7, 
    "China":5, 
    "Colombia":12, 
    "Czech Republic":6, 
    "Denmark":374, 
    "Ecuador":21, 
    "Fiji":719, 
    "Finland":992, 
    "France":525, 
    "Germany":13, 
    "Ghana":892, 
    "Hungary":15, 
    "India":40, 
    "Indonesia":5, 
    "Ireland":814, 
    "Italy":79, 
    "Jordan":6, 
    "Kenya":7, 
    "Malaysia":15, 
    "Nepal":851, 
    "Netherlands":15, 
    "New Zealand":22, 
    "Nigeria":2, 
    "Norway":924, 
    "Poland":165, 
    "Republic of the Congo":6, 
    "Russia":35, 
    "Senegal":4, 
    "Serbia":17, 
    "Spain":63, 
    "Sweden":738, 
    "Switzerland":5, 
    "Turkey":2, 
    "United Kingdom":769, 
    "United States":33, 
    "Uruguay":10, 
    "Venezuela":23, 
    "Zambia":6 
} 
} 

]

+0

這種可視化生活在某個地方嗎?沒有看到它很難理解發生了什麼。 – 2013-04-24 18:06:01

+0

它現在在本地運行。基本上它是一個維和貢獻與時間變化的chloropleth。一個國家月度貢獻的百分位數決定了分位數類別,它決定了顏色釀造者關聯的CSS類。這些捐款每個月都在變化,所以地圖在本月動畫以顯示部隊捐款的變化分佈情況。大日期標籤作爲對正在查看月份的控件的雙重責任。全面的數據傳播是177個geojson元素和266個月的國家級數據。 – 2013-04-24 19:52:52

+0

聽起來像瓶頸可能只是重繪元素而不是數據處理。我不能在沒有看到它的情況下給你提供更多信息 - 聽起來像一個大項目,它可能是各種各樣的事情。如果您不願意公開代碼,請隨時與我私下聯繫。 – 2013-04-24 20:12:34

回答

0

後調試的時間,事實證明,在nns.js庫造成我的問題。動畫的每次迭代都創建了一組新的DOM對象,這些對象在25,000時開始最大化瀏覽器。解決方案是使用nss創建初始狀態,然後使用以下函數更改每個svg元素的類。

function country_class_constructor(local, geojson){ 
       for(var x=0;x<geojson.length;x++){ 
        var n = geojson[x].data.properties.name; 
        element = document.getElementById(n); 
        element.className["animVal"] = geojson[x].data.formats[local]; 
        element.className["baseVal"] = geojson[x].data.formats[local]; 
}