2016-04-27 32 views
3

我是編程新手,我一直在研究O'Reilly Interactive Data Visualization書中的例子。D3 - 在美國地圖上渲染多年的數據狀態數據

現在,我正在努力將州電動汽車的5年數據可視化。每個州的顏色都會根據特定年份內註冊的電動車輛的數量而變化。

問題

每次我點擊下拉菜單中year,它會創建它下面另一個地圖SVG。我怎樣才能得到它重新呈現在同一(現有)地圖SVG的數據?

背景:

我有一個定義了SVG的尺寸全局變量。我也有兩個功能:

  • drawMap有一年的論證,並建立了SVG,從CSV到us_map.json加載數據,並創建所有的國界線。
  • clickEventMap將事件偵聽器附加到每個年份按鈕,然後調用drawMap函數通過與按鈕上年份匹配的年份。最後,我撥打drawMap(2013),以便頁面默認爲2013年的數據,然後致電clickEventMap()

我迄今爲止嘗試:

console.log(year)的D3 color.domain方法和正確的一年之後被存儲爲在該點的一年變量。

另外,如果手動更改參數drawMap()被調用時,我可以成功更改現有地圖上呈現的數據。

我的代碼:

var w = 1200; 
var h = 800; 
var barpadding = 1; 

var drawMap = function(year) { 

    var svg = d3.select("body") 
    .append("svg") 
    .attr("height", h) 
    .attr("width", w); 

    var projection = d3.geo.albersUsa() 
         .translate([w/2, h/2]) 
         .scale([1600]); 

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

    var color = d3.scale.quantize() 
        .range(["rgb(237, 248, 233)", "rgb(186, 228, 179)", "rgb(116,196,118)", "rgb(49, 163, 84)", "rgb(0, 109, 44)"]); 


    color.domain([ 
    d3.min(data, function(d) {return d["electric_vehicles_" + year];}), 
    d3.max(data, function(d) { return d["electric_vehicles_" + year];}) 

    ]); 

    console.log(year); 

    d3.json("us-states.json", function(json) { 
    for (var i = 0; i < data.length; i ++) { 
     var dataState = data[i].state;   
     var dataValue = parseFloat(data[i]["electric_vehicles_" + year]); 
     for (var j = 0; j < json.features.length; j++) { 
     var jsonState = json.features[j].properties.name; 
     if (dataState === jsonState) {      
      json.features[j].properties.value = dataValue; 
      break; 
     } 
     } 
    } 

    var stateView = function() { 
    console.log("State clicked."); 
    location.href="/states/1"; 

    svg.selectAll("path") 
     .data(json.features) 
     .enter() 
     .append("path") 
     .attr("d", path) 
     .style("fill", function(d) { 
     var value = d.properties.value; 
     if (value) { 
      return color(value); 
     } 
     else { 
      return "#ccc"; 
     } 
     }) 
     .on("mouseover", function(d, i) { 
     d3.select(this) 
     .style("fill-opacity", 0.5); 
     }) 
     .on("mouseout", function(d, i) { 
     d3.selectAll("path") 
     .style("fill-opacity", 1); 
     }) 
     .on("click", function() { 
     stateView(); 
     }); 
    }); 
}); 
}; 

var clickEventMap = function() { 
    $("#map2013").on("click", function() { 
    // var year = 2013; 
    drawMap(2013); 
    }); 

    $("#map2012").on("click", function() { 
    // var year = 2012; 
    drawMap(2012); 
    }); 

    $("#map2011").on("click", function() { 
    // var year = 2011; 
    drawMap(2011); 
    }); 

    $("#map2010").on("click", function() { 
    // var year = 2010; 
    drawMap(2010); 
    }); 

    $("#map2009").on("click", function() { 
    // var year = 2009; 
    drawMap(2009); 
    }); 
}; 

drawMap(2013); 
clickEventMap(); 

感謝您的輸入。

+0

你能提供一個工作小提琴/ plnk/jsbin? – iulian

回答

0

您的主要問題是您在drawMap函數中做得太多。很多內容只需要做一次,而不是每次切換多年。這就是爲什麼你得到多個地圖。此代碼每次創建一個新的SVG你打電話drawMap

var svg = d3.select("body") 
    .append("svg") 
    .attr("height", h) 
    .attr("width", w); 

如果你只是移動,高達出drawMap功能的,你只會得到一個SVG。

您每次繪製地圖時都會收到'us-states.json'文件。這可能會在技術上起作用,但會導致很多您不需要的網絡請求。只需在頁面加載時請求一次。這對你的代碼來說是一個非常大的重組改變,因爲基本上所有的事情都需要在回調中調用。

最後,在進行這些更改後,您將需要更改代碼以繪製狀態以使其正確更新。現在,您可以在「輸入」選項上執行所有操作,只能在新路徑上操作。既然你要編輯現有路徑,您的代碼需要看起來更像是這樣的:

var paths = svg.selectAll("path") 
    .data(json.features) 
    .enter() 
    .append("path") 
    .attr("d", path) 
    .on("mouseover", function(d, i) { 
     d3.select(this) 
      .style("fill-opacity", 0.5); 
    }) 
    .on("mouseout", function(d, i) { 
     d3.selectAll("path") 
      .style("fill-opacity", 1); 
    }) 
    .on("click", function() { 
     stateView(); 
    }); 

paths.style("fill", function(d) { 
    var value = d.properties.value; 
    if (value) { 
     return color(value); 
    } else { 
     return "#ccc"; 
    } 
}); 

邁克Bostocks文章Thinking with JoinsThree Little Circles是在D3瞭解更新都是偉大的資源。基本上,只要想一下你只需要做一次什麼事情,每次點擊新的一年就需要改變什麼(更新你的色階併爲每個狀態設置填充樣式)。嘗試將發生的所有事情都放到init函數中,並保持drawMap函數的小。

+0

謝謝你的迴應,詹姆斯。 – arsm800

+0

我移動了drawMap()函數上面的一些變量並創建了一個路徑變量。雖然每次都沒有創建新的svg,但初始映射svg沒有改變。 我最終做的是將地圖svg放在一個ID爲「usmap」的div中,然後做'''var svg = d3.select(「#usmap」)'''。另外,在聲明svg之前,我在drawMap()函數的開頭添加了'''$(「#usmap」)。empty()'''。清空div然後創建一個新的svg,雖然可能不是最有效或最優雅的方式,似乎工作。 – arsm800

+0

嗯,我想清空div是讓它工作的最簡單方法。但我認爲你錯過了沒有利用d3的更新模式。特別是加載地圖json會使重繪速度變慢,因此您至少應該嘗試僅請求一次該請求。 –