1

我正在使用 d3 库,并且成功使用了 chloropleth 示例,并获得了单击操作以放大到特定状态(有关详细信息,请参阅此问题)。特别是,这是我用于单击以缩放某个状态的事件的代码:

// Since height is smaller than width, 
var baseWidth = 564;
var baseHeight = 400;

d3.selectAll('#states path')
    .on('click', function(d) {
        // getBBox() is a native SVG element method
        var bbox = this.getBBox(),
            centroid = [bbox.x + bbox.width/2, bbox.y + bbox.height/2],
            // since height is smaller than width, I scale based off of it.
            zoomScaleFactor = baseHeight / bbox.height,
            zoomX = -centroid[0],
            zoomY = -centroid[1];

        // set a transform on the parent group element
        d3.select('#states')
            .attr("transform", "scale(" + scaleFactor + ")" +
                "translate(" + zoomX + "," + zoomY + ")");
    });

但是,当我单击以查看状态时,我的变换不在视口的中心,而是在左上角,并且它可能也没有适当的比例。如果我手动对 scaleFactor 或 zoomX/zoomY 参数进行微调,我会完全丢失该项目。我熟悉这样一个概念,即一起进行缩放和变换会产生显着不同的结果,所以我不确定如何调整。

我唯一能想到的另一件事是原始叶绿素图像设置为 960 x 500 图像。为了适应这个。我创建了一个 albersUSA 投影并将我的 d3.geo.path 与此投影一起使用,并继续相应地添加我的路径。

我的变换是否受到投影的影响?如果是,我将如何适应它?

4

2 回答 2

2

缩放变换需要像旋转变换一样处理(没有可选的 cx,cy 参数),也就是说,您要变换的对象必须首先移动到原点。

d3.select('#states')
            .attr("transform",
                  "translate(" + (-zoomX) + "," + (-zoomY) + ")" +
                  "scale(" + scaleFactor + ")" +
                  "translate(" + zoomX + "," + zoomY + ")");
于 2012-09-27T07:24:28.110 回答
2

为了进一步参考,

我找到了这篇文章,您应该可以在其中找到如何使用矩阵变换非常简单地实现缩放和平移效果。

摘录:

<script type="text/ecmascript">
    <![CDATA[
      var transMatrix = [1,0,0,1,0,0];

      function init(evt)
      {
        if ( window.svgDocument == null )
        {
          svgDoc = evt.target.ownerDocument;
        }
        mapMatrix = svgDoc.getElementById("map-matrix");
        width  = evt.target.getAttributeNS(null, "width");
        height = evt.target.getAttributeNS(null, "height");
      }
    ]]>
</script>

function pan(dx, dy)
{      
  transMatrix[4] += dx;
  transMatrix[5] += dy;

  newMatrix = "matrix(" +  transMatrix.join(' ') + ")";
  mapMatrix.setAttributeNS(null, "transform", newMatrix);
}
function zoom(scale)
{
  for (var i=0; i<transMatrix.length; i++)
  {
    transMatrix[i] *= scale;
  }

  transMatrix[4] += (1-scale)*width/2;
  transMatrix[5] += (1-scale)*height/2;

  newMatrix = "matrix(" +  transMatrix.join(' ') + ")";
  mapMatrix.setAttributeNS(null, "transform", newMatrix);
}
于 2012-12-11T17:05:16.550 回答