如何根据视口调整SVG变换?

时间:2012-09-27 05:17:19

标签: svg zoom scale transformation

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

// 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进行此投影,并继续相应地添加我的路径。

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

2 个答案:

答案 0 :(得分:2)

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

d3.select('#states')
            .attr("transform",
                  "translate(" + (-zoomX) + "," + (-zoomY) + ")" +
                  "scale(" + scaleFactor + ")" +
                  "translate(" + zoomX + "," + zoomY + ")");

答案 1 :(得分:2)

供进一步参考,

我发现this article你应该找到如何使用矩阵变换来实现变焦和平移效果非常简单。

例外:

<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);
}