2016-04-27 8 views
3

私はプログラミングが初めてで、O'Reillyの例を作業しています対話型データ視覚化D3 - 米国地図上での複数年の価値あるデータの表示

現在、私は電気自動車に関する5年間のデータを州ごとに視覚化しています。各州の色は、その特定の年の登録電気自動車の数によって変わります。

質問

私はドロップダウンメニューにyearをクリックするたびに、それはそれの下に別のマップのSVGを作成します。どうすれば同じ(既存の)マップsvg上のデータを再レンダリングすることができますか?

背景:私は、SVGの寸法を定義するグローバル変数を持って

  • drawMapは、年の引数を持ち、SVGを構築し、us_map.jsonへのcsvファイルからデータをロードすると、すべての州の境界を作成します。私はまた、2つの機能を持ちます。
  • clickEventMapは、各年のボタンにイベントリスナーを関連付けて、drawMap関数を呼び出し、その年にボタンに一致する年を渡します。最後に、drawMap(2013)に電話して、ページが2013年のデータにデフォルト設定されてからclickEventMap()に電話します。私がこれまで試してみました何

:D3 color.domain方法と正しい年後

私はconsole.log(year)は、その時点で年間の変数として格納されます。

また、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

あなたはfiddle/plnk/jsbinを提供できますか? – iulian

答えて

0

あなたの主な問題は、drawMap機能の中であまりにも多くのことをしていることです。そこにあるものの多くは、あなたが何年も変わるたびに一度だけ行う必要があります。これが複数の地図を取得している理由です。このコードは、あなたがちょうどdrawMap機能のうち、それを上に移動した場合、あなたは唯一のSVGを取得しますdrawMap

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

を呼び出すたびに新しい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

あなたの返事をありがとう、James。 – arsm800

+0

私はdrawMap()関数の上にあるいくつかの変数を移動し、paths変数を作成しました。新しいsvgは毎回作成されませんでしたが、初期マップsvgは変更されませんでした。 私がやったことは、マップsvgをidの "usmap"を持つdivの中に入れてから、 '' 'var svg = d3.select("#usmap ")' ''を実行することでした。さらに、svgを宣言する直前にdrawMap()関数の先頭に '' $( "#usmap")。empty() '' 'を追加しました。おそらく最も効率的でエレガントな方法ではないのに、divを空にして新しいsvgを作成すると、うまくいくように見えました。 – arsm800

+0

さて、私はdivを空にして、それを働かせる最も簡単な方法だと思います。しかし、私はd3の更新パターンを利用しないことであなたが欠けていると思います。地図を読み込むjsonは、特に再描画を遅くするため、少なくともそのリクエストを1回だけ行うようにしてください。 –

関連する問題