7

これは「やり方が間違っている」という典型的なケースかもしれませんが、これまでの私の検索では何の助けにもなりませんでした。

これが私のシナリオです:

albersUSA マップ プロジェクションを国および郡の GeoJson ファイルと組み合わせて使用​​して、すべてを描画しています。

また、各州の主要都市を含む自己作成の「都市」ファイルもあります。座標は正確で、すべてが見栄えがします。

ここに画像の説明を入力

ユーザーが特定の州をクリックすると、すべての州の形状が非表示になり、その州の郡の形状がビューポートに収まるようにするために必要な変換が計算されます。次に、その変換を必要なすべての郡の形状に適用して、「ズーム」ビューを取得します。私のコードは次のとおりです。

function CalculateTransform(objectPath)
{
   var results = '';

   // Define bounds/points of viewport
   var mapDimensions = getMapViewportDimensions();
   var baseWidth = mapDimensions[0];
   var baseHeight = mapDimensions[1];

   var centerX = baseWidth / 2;
   var centerY = baseHeight / 2;

   // Get bounding box of object path and calculate centroid and zoom factor
   // based on viewport.
   var bbox = objectPath.getBBox();
   var centroid = [bbox.x + bbox.width / 2, bbox.y + bbox.height / 2];
   var zoomScaleFactor = baseHeight / bbox.height;
   var zoomX = -centroid[0];
   var zoomY = -centroid[1];

   // If the width of the state is greater than the height, scale by
   // that property instead so that state will still fit in viewport.
   if (bbox.width > bbox.height) {
      zoomScaleFactor = baseHeight / bbox.width;
   }

   // Calculate how far to move the object path from it's current position to
   // the center of the viewport.
   var augmentX = -(centroid[0] - centerX);
   var augmentY = -(centroid[1] - centerY);

   // Our transform logic consists of:
   // 1. Move the state to the center of the screen.
   // 2. Move the state based on our anticipated scale.
   // 3. Scale the state.
   // 4. Move the state back to accomodate for the scaling.   
   var transform = "translate(" + (augmentX) + "," + (augmentY) + ")" +
                 "translate(" + (-zoomX) + "," + (-zoomY) + ")" +
                 "scale(" + zoomScaleFactor + ")" +
                 "translate(" + (zoomX) + "," + (zoomY) + ")";

   return results;
}

...そしてバインディング機能

// Load county data for the state specified.
d3.json(jsonUrl, function (json) {
    if (json === undefined || json == null || json.features.length == 0) 
    {
       logging.error("Failed to retrieve county structure data.");
       showMapErrorMessage("Unable to retrieve county structure data.");
       return false;
    }
    else 
    {
       counties.selectAll("path")
                .data(json.features)
                .enter()
                   .append("path")
                      .attr("id", function (d, i) {
                         return "county_" + d.properties.GEO_ID
                      })
                      .attr("data-id", function (d, i) { return d.properties.GEO_ID })
                      .attr("data-name", function (d, i) { return countyLookup[d.properties.GEO_ID] })
                      .attr("data-stateid", function (d, i) { return d.properties.STATE })
                      .attr("d", path);

        // Show all counties for state specified and apply zoom transform.
        d3.selectAll(countySelector).attr("visibility", "visible");
        d3.selectAll(countySelector).attr("transform", stateTransform);

        // Show all cities for the state specified and apply zoom transform
        d3.selectAll(citySelector).attr("visibility", "visible");
        d3.selectAll(citySelector).attr("transform", stateTransform);
    }
});

ここに画像の説明を入力

これはここでは問題なく機能しますが、非常に小さな状態を除いて、ズーム係数がはるかに大きくなり、円が歪んでしまいます。

ここに画像の説明を入力

変換が発生した後でも、ポイントのサイズを強制的に固定サイズ (半径 15px など) にする方法はありますか?

4

2 に答える 2

6

拡大縮小したくないものについては、 'scale' で割ってください。私の場合、

var zoom = d3.behavior.zoom()
    .on("zoom",function() {
        g.attr("transform","translate("+d3.event.translate.join(",")+")scale("+d3.event.scale+")");

        g.selectAll(".mapmarker")  
        .attr("r",6/d3.event.scale)
        .attr("stroke-width",1/d3.event.scale);

});
于 2013-08-09T04:35:23.783 に答える
4

これは、位置をスケーリングする代わりにスケール変換を設定しているために発生しています。ここで違いがわかります。基本的には、次の違いです。

// Thick lines because they are scaled too
var bottom = svg.append('g').attr('transform', 'scale('+scale+','+scale+')');
bottom.selectAll('circle')
    .data(data)
    .enter().append('circle')
    .attr('cx', function(d) { return d.x; })
    .attr('cy', function(d) { return d.y; });

// line thicknesses are nice and thin
var top = svg.append('g');
top.selectAll('circle')
    .data(data)
    .enter().append('circle')
    .attr('cx', function(d) { return d.x * scale; })
    .attr('cy', function(d) { return d.y * scale; });

マッピングを使用する場合、おそらく最善の解決策は、オフセットとスケールを計算してから、それらを投影関数に追加することです。つまり、投影後のx値とy値を直接変更する必要があります。投影関数を適切に更新すれば、マップに適切なズームを適用するために他に何もする必要はありません。

于 2013-02-28T18:48:27.897 に答える