2017-10-11 15 views
1

私はD3を初めて使っています。私がする必要があるもの:D3の地図:パスのグループにズーム

  1. 単一の状態のマップを作成します。
  2. 郡の罫線を表示する必要があります。
  3. 州地域北、南、東、西&中央は異なる色で塗りつぶさなければなりません。各地域は郡で構成されています。
  4. ユーザーが領域をクリックすると、マップはその領域を拡大する必要があります。

ここまで達成できたこと: 私には最初の3つの要件があります。問題は、私が郡をクリックすると、その地域の代わりにその郡にズームすることです。

私が書いたコードは、以下の実施例から基づいています。

ズームバウンディングボックスへ

https://bl.ocks.org/mbostock/4699541

クリップされた郡で

NY州

https://bl.ocks.org/gregdevs/a73f8a16f129757c037e72ecdebdd8f2

の一部のみ自分で作成したコード(そして変更が必要な部分)は、regの色付けですイオン。これはif then else statemenentsを使用して次のクラスを設定して行われました。

.attr('class', function (d) { 
        if (d.id == "51105" || d.id == "51169" || d.id == "51191" || d.id == "51520" || d.id == "51077" || d.id == "51035" || 
         d.id == "51141" || d.id == "51089" || d.id == "51143" || d.id == "51590" || d.id == "51195" || d.id == "51051" || 
         d.id == "51027" || d.id == "51167" || d.id == "51185" || d.id == "51173" || d.id == "51021" || d.id == "51197" || 
         d.id == "51071" || d.id == "51590" || d.id == "51155" || d.id == "51063" || d.id == "51067" || d.id == "51121" || 
         d.id == "51161" || d.id == "51770") { 
         return "WesternRegion"; 
        } 
        else if (d.id == "51083" || d.id == "51117" || d.id == "51025" || d.id == "51081" || d.id == "51037" || d.id == "51011" || 
          d.id == "51590" || d.id == "51029" || d.id == "51049" || d.id == "51145" || d.id == "51041" || d.id == "51111" || 
          d.id == "51147" || d.id == "51183" || d.id == "51181" || d.id == "51007" || d.id == "51135" || d.id == "51053" || 
          d.id == "51149" || d.id == "51087" || d.id == "51760") { 
         return "SouthernRegion"; 
        } 
        else if (d.id == "51175" || d.id == "51800" || d.id == "51550" || d.id == "51810" || d.id == "51710" || d.id == "51093" || 
          d.id == "51001" || d.id == "51131") { 
         return "EasternRegion"; 
        } 
        else if (d.id == "51165" || d.id == "51171" || d.id == "51069" || d.id == "51043" || d.id == "51107" || d.id == "51059" || 
          d.id == "51013" || d.id == "51510" || d.id == "51139" || d.id == "51187" || d.id == "51157" || d.id == "51061" || d.id == "51153") { 
         return "NorthernRegion"; 
        } 
        else return "CentralRegion"; 
       }) 
       ; 

以下は完全なコードです。それを有効にするには、https://bl.ocks.org/mbostock/raw/4090846/us.jsonからus.jsonをダウンロードし、それをscriptsというフォルダにコピーする必要があります。以下は

<!DOCTYPE html> 
<meta charset="utf-8"> 
<style> 

    .outline { 
    stroke: #000; 
    stroke-width: 1.5px; 
} 

path { 
    fill: #ccc; 
    stroke: #fff; 
    stroke-width: .5px; 
} 
.background { 
    fill: none; 
    pointer-events: all; 
} 

.feature { 
    fill: #ccc; 
    cursor: pointer; 
} 

.county.active { 
    fill: orange !important; 
} 

.WesternRegion 
{ 
    fill:Green; 
} 

.EasternRegion 
{ 
    fill:Blue; 
} 

.SouthernRegion 
{ 
    fill:#efce43; 
} 
.NorthernRegion 
{ 
    fill:Purple; 
} 

.mesh { 
    fill: none; 
    stroke: #fff; 
    stroke-linecap: round; 
    stroke-linejoin: round; 
} 


</style> 
<body> 
<script src="//d3js.org/d3.v3.min.js"></script> 
<script src="//d3js.org/topojson.v1.min.js"></script> 
<script> 

    var width = 960, 
     height = 500; 
    active = d3.select(null); 

    var projection = d3.geo.albers() 
     .scale(1000) 
     .translate([width/2, height/2]); 

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

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

    svg.append("rect") 
     .attr("class", "background") 
     .attr("width", width) 
     .attr("height", height) 
     .on("click", reset); 

    var g = svg.append("g") 
     .style("stroke-width", "1.5px"); 

    d3.json("/Scripts/us.json", function (error, us) { 
     if (error) throw error; 

     var states = topojson.feature(us, us.objects.states), 
      state = states.features.filter(function (d) { return d.id === 51; })[0]; 

     projection.scale(1) 
      .translate([0, 0]); 

     var b = path.bounds(state), 
      s = .95/Math.max((b[1][0] - b[0][0])/width, (b[1][1] - b[0][1])/height), 
      t = [(width - s * (b[1][0] + b[0][0]))/2, (height - s * (b[1][1] + b[0][1]))/2]; 

     projection.scale(s) 
      .translate(t); 

     g.selectAll("path") 
      .datum(topojson.mesh(us, us.objects.states, function (a, b) { return a !== b; })) 
      .attr("class", "mesh") 
      .attr("d", path) 
      .on("click", clicked); 

     g.append("path") 
      .datum(state) 
      .attr("class", "outline") 
      .attr("d", path) 
      .attr('id', 'land'); 

     g.append("clipPath") 
      .attr("id", "clip-land") 
      .append("use") 
     .attr("xlink:href", "#land"); 

     g.selectAll("path") 
      .data(topojson.feature(us, us.objects.counties).features) 
      .enter().append("path") 
      .attr("d", path) 
      .attr('countyId', function (d) { 
       return d.id 
       }) 
      .attr("clip-path", "url(#clip-land)") 
      .on("click", clicked) 
      .attr('class', function (d) { 
        if (d.id == "51105" || d.id == "51169" || d.id == "51191" || d.id == "51520" || d.id == "51077" || d.id == "51035" || 
         d.id == "51141" || d.id == "51089" || d.id == "51143" || d.id == "51590" || d.id == "51195" || d.id == "51051" || 
         d.id == "51027" || d.id == "51167" || d.id == "51185" || d.id == "51173" || d.id == "51021" || d.id == "51197" || 
         d.id == "51071" || d.id == "51590" || d.id == "51155" || d.id == "51063" || d.id == "51067" || d.id == "51121" || 
         d.id == "51161" || d.id == "51770") { 
         return "WesternRegion"; 
        } 
        else if (d.id == "51083" || d.id == "51117" || d.id == "51025" || d.id == "51081" || d.id == "51037" || d.id == "51011" || 
          d.id == "51590" || d.id == "51029" || d.id == "51049" || d.id == "51145" || d.id == "51041" || d.id == "51111" || 
          d.id == "51147" || d.id == "51183" || d.id == "51181" || d.id == "51007" || d.id == "51135" || d.id == "51053" || 
          d.id == "51149" || d.id == "51087" || d.id == "51760") { 
         return "SouthernRegion"; 
        } 
        else if (d.id == "51175" || d.id == "51800" || d.id == "51550" || d.id == "51810" || d.id == "51710" || d.id == "51093" || 
          d.id == "51001" || d.id == "51131") { 
         return "EasternRegion"; 
        } 
        else if (d.id == "51165" || d.id == "51171" || d.id == "51069" || d.id == "51043" || d.id == "51107" || d.id == "51059" || 
          d.id == "51013" || d.id == "51510" || d.id == "51139" || d.id == "51187" || d.id == "51157" || d.id == "51061" || d.id == "51153") { 
         return "NorthernRegion"; 
        } 
        else return "CentralRegion"; 
       }) 
       ; 

    }); 

    function clicked(d) { 
     //  debugger; 
     if (d3.select(this).classed("NorthernRegion")) { 
      alert("You selected Northern Region"); 
     } 
     else if (d3.select(this).classed("SouthernRegion")) { 
      alert("You selected Southern Region"); 
     } 
     else if (d3.select(this).classed("EasternRegion")) { 
      alert("You selected Eastern Region"); 
     } 
     else if (d3.select(this).classed("WesternRegion")) { 
      alert("You selected Western Region"); 
     } 
     else if (d3.select(this).classed("CentralRegion")) { 
      alert("You selected Central Region"); 
     } 

     if (active.node() === this) return reset(); 
     active.classed("active", false); 
     active = d3.select(this).classed("active", true); 

     var bounds = path.bounds(d ), 
     dx = bounds[1][0] - bounds[0][0], 
     dy = bounds[1][1] - bounds[0][1], 
     x = (bounds[0][0] + bounds[1][0])/2, 
     y = (bounds[0][1] + bounds[1][1])/2, 
     scale = .9/Math.max(dx/width, dy/height), 
     translate = [width/2 - scale * x, height/2 - scale * y]; 

     g.transition() 
     .duration(750) 
     .style("stroke-width", 1.5/scale + "px") 
     .attr("transform", "translate(" + translate + ")scale(" + scale + ")"); 

    } 

    function reset() { 

     active.classed("active", false); 
     active = d3.select(null); 

     g.transition() 
     .duration(750) 
     .style("stroke-width", "1.5px") 
     .attr("transform", ""); 
    } 
</script> 

マップがどのように見えるかです: enter image description here

問題は、それが郡いない領域にズームすることです:すべての enter image description here

答えて

1

まず、あなたは大きなものは必要ありません。 if...elseステートメント。彼らは非常に単純化することができます。例えば、clicked関数の内部クラスを取得する:

var thisClass = d3.select(this).attr("class"); 

戻るあなたの質問に。

溶液がクリックされた要素のクラスにすべてのパスを取得し、アレイの内部にその境界を推進している。

var allBounds = []; 

var allPaths = d3.selectAll("path." + thisClass).each(function(d) { 
    allBounds.push(path.bounds(d)) 
}); 

そしてすべてのそれらの境界の角を計算する:ここ

var bound0 = d3.min(allBounds, function(d) { 
    return d[0][0] 
}); 
var bound1 = d3.min(allBounds, function(d) { 
    return d[0][1] 
}); 
var bound2 = d3.max(allBounds, function(d) { 
    return d[1][0] 
}); 
var bound3 = d3.max(allBounds, function(d) { 
    return d[1][1] 
}); 

var bounds = path.bounds(d), 
    dx = bound2 - bound0, 
    dy = bound3 - bound1, 
    x = (bound0 + bound2)/2, 
    y = (bound1 + bound3)/2, 
    scale = .9/Math.max(dx/width, dy/height), 
    translate = [width/2 - scale * x, height/2 - scale * y]; 

更新されたbl.ocksです:https://bl.ocks.org/anonymous/3e473b01de29cb7a3c0a6d8807b8b247/f6675e001dc7dcdb7ffd4c437944bb3233b417ca

PS:中央の領域(灰色の領域)をクリックすると、はありません。理由は簡単です:あなたのコードでは、クラスを、指定されたIDのないすべてのパスにif...elseステートメントで設定しています。あなたはそれを変更する必要があります。

PPS:すべての郡にactiveクラスを設定するコードをリファクタリングする必要があります。

+0

私の答えに近い!あなたはいつも私の解決策を見ていると、なぜ1つの郡が引き続きフィルタリングされているのでしょうか? – Nick

1

これは私のソリューションですが、これはかなりうまくいくようです。た私が作った重要な変更:のみ関心の状態のものの郡を含む

  • (それははるかに高速に実行可能)
  • 郡がクリックされるたびに、「アクティブ」領域ではなく、郡
  • を示し、私が述べたことを奇妙

何かが非該当の郡をフィルタリングする場合、1つの該当する郡はそう、フィルタリングまま、ということである(これは鍵となった)ズームの最大と最小の境界を取得するためにその領域内のすべての郡を反復処理私は手動でそれを元に戻しました。

var width = 960, 
height = 500, 
active = ""; 

var projection = d3.geo.albers().scale(1000).translate([width/2, height/2]); 
var path = d3.geo.path().projection(projection); 
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height); 
svg.append("rect").attr("class", "background").attr("width", width).attr("height", height).on("click", reset); 
var g = svg.append("g").style("stroke-width", "1.5px"); 
d3.json("scripts/us.json", function(error, us) { 
    if (error) throw error; 
    var states = topojson.feature(us, us.objects.states), 
     state = states.features.filter(function(d) { 
      return d.id === 51; 
     })[0]; 
    projection.scale(1).translate([0, 0]); 
    var b = path.bounds(state), 
     s = .95/Math.max((b[1][0] - b[0][0])/width, (b[1][1] - b[0][1])/height), 
     t = [(width - s * (b[1][0] + b[0][0]))/2, (height - s * (b[1][1] + b[0][1]))/2]; 
    projection.scale(s).translate(t); 
    g.selectAll("path").datum(topojson.mesh(us, us.objects.states, function(a, b) { 
     return a !== b; 
    })).attr("class", "mesh").attr("d", path).on("click", clicked); 
    g.append("path").datum(state).attr("class", "outline").attr("d", path).attr('id', 'land'); 
    g.append("clipPath").attr("id", "clip-land").append("use").attr("xlink:href", "#land"); 
    us.objects.counties.geometries = us.objects.counties.geometries.filter(function(county) { 
     return county.id >= 51000 && county.id < 52000 
    }); 
    // Not sure why this one needs to be re-added 
    us.objects.counties.geometries.push(us.objects.counties.geometries.find(function(d) { 
     return d.id == 51069 
    })); 
    console.log(us.objects); 
    g.selectAll("path").data(topojson.feature(us, us.objects.counties).features).enter().append("path").attr("d", path).attr('countyId', function(d) { 
     return d.id 
    }).attr("clip-path", "url(#clip-land)").on("click", clicked).attr('class', function(d) { 
     if (d.id == "51105" || d.id == "51169" || d.id == "51191" || d.id == "51520" || d.id == "51077" || d.id == "51035" || d.id == "51141" || d.id == "51089" || d.id == "51143" || d.id == "51590" || d.id == "51195" || d.id == "51051" || d.id == "51027" || d.id == "51167" || d.id == "51185" || d.id == "51173" || d.id == "51021" || d.id == "51197" || d.id == "51071" || d.id == "51590" || d.id == "51155" || d.id == "51063" || d.id == "51067" || d.id == "51121" || d.id == "51161" || d.id == "51770") { 
      return "WesternRegion"; 
     } else if (d.id == "51083" || d.id == "51117" || d.id == "51025" || d.id == "51081" || d.id == "51037" || d.id == "51011" || d.id == "51590" || d.id == "51029" || d.id == "51049" || d.id == "51145" || d.id == "51041" || d.id == "51111" || d.id == "51147" || d.id == "51183" || d.id == "51181" || d.id == "51007" || d.id == "51135" || d.id == "51053" || d.id == "51149" || d.id == "51087" || d.id == "51760") { 
      return "SouthernRegion"; 
     } else if (d.id == "51175" || d.id == "51800" || d.id == "51550" || d.id == "51810" || d.id == "51710" || d.id == "51093" || d.id == "51001" || d.id == "51131") { 
      return "EasternRegion"; 
     } else if (d.id == "51165" || d.id == "51171" || d.id == "51069" || d.id == "51043" || d.id == "51107" || d.id == "51059" || d.id == "51013" || d.id == "51510" || d.id == "51139" || d.id == "51187" || d.id == "51157" || d.id == "51061" || d.id == "51153") { 
      return "NorthernRegion"; 
     } else { 
      return "CentralRegion"; 
     } 
    }); 
}); 

function clicked(d) { 
    var selected = d3.select(this).attr('class'); 
    var dxAll = []; 
    var dyAll = []; 
    var xAll = []; 
    var yAll = []; 
    // Iterate through all in class and find max values 
    d3.selectAll('.' + selected).each(function(data) { 
     var bounds = path.bounds(data); 
     dxAll.push(bounds[1][0], bounds[0][0]); 
     dyAll.push(bounds[1][1], bounds[0][1]); 
     xAll.push(bounds[0][0], bounds[1][0]); 
     yAll.push(bounds[0][1], bounds[1][1]); 
    }); 
    dx = Math.max.apply(null, dxAll) - Math.min.apply(null, dxAll); 
    dy = Math.max.apply(null, dyAll) - Math.min.apply(null, dyAll); 
    x = (Math.max.apply(null, xAll) + Math.min.apply(null, xAll))/2; 
    y = (Math.max.apply(null, yAll) + Math.min.apply(null, yAll))/2; 
    if (active === selected) return reset(); 
    active = selected; 
    scale = .9/Math.max(dx/width, dy/height), 
     translate = [width/2 - scale * x, height/2 - scale * y]; 
    g.transition().duration(750).style("stroke-width", 1.5/scale + "px").attr("transform", "translate(" + translate + ")scale(" + scale + ")"); 
} 

function reset() { 
    active = ""; 
    g.transition().duration(750).style("stroke-width", "1.5px").attr("transform", ""); 
} 
関連する問題