如何在SVG中设置变换原点

时间:2011-07-15 18:29:28

标签: svg coordinate-transformation

我需要使用javascript调整SVG文档中的某些元素并调整其大小。问题是,默认情况下,它总是在(0, 0) - 左上角的原点周围应用变换。

如何重新定义此变换锚点?

我尝试使用transform-origin属性,但它不会影响任何内容。

我就这样做了:

svg.getDocumentById('someId').setAttribute('transform-origin', '75 240');

虽然我可以在Firefox中看到属性设置正确,但它似乎没有将关键点设置为我指定的点。我尝试了center bottom50% 100%这样的事情,有或没有括号。到目前为止没有任何工作。

有人可以帮忙吗?

7 个答案:

答案 0 :(得分:129)

旋转使用transform="rotate(deg, cx, cy)",其中deg是您想要旋转的度数,(cx,cy)定义旋转中心。

对于缩放/调整大小,你必须翻译(-cx,-cy),然后缩放然后转换回(cx,cy)。您可以使用matrix transform

执行此操作
transform="matrix(sx, 0, 0, sy, cx-sx*cx, cy-sy*cy)"

其中sx是x轴的缩放系数,sy是y轴。

答案 1 :(得分:18)

如果您可以使用固定值(不是"中心"或" 50%"),您可以改用CSS:

AppWidget

某些浏览器(如Firefox)无法正确处理相对值。

答案 2 :(得分:11)

如果你像我一样想要平移然后用变换原点进行缩放,你需要多一点。

// <g id="view"></g>
var view = document.getElementById("view");

var state = {
  x: 0,
  y: 0,
  scale: 1
};

// Origin of transform, set to mouse position or pinch center
var oX = window.innerWidth/2;
var oY = window.innerHeight/2;

var changeScale = function (scale) {
  // Limit the scale here if you want
  // Zoom and pan transform-origin equivalent
  var scaleD = scale / state.scale;
  var currentX = state.x;
  var currentY = state.y;
  // The magic
  var x = scaleD * (currentX - oX) + oX;
  var y = scaleD * (currentY - oY) + oY;

  state.scale = scale;
  state.x = x;
  state.y = y;

  var transform = "matrix("+scale+",0,0,"+scale+","+x+","+y+")";
  //var transform = "translate("+x+","+y+") scale("+scale+")"; //same
  view.setAttributeNS(null, "transform", transform);
};

这里有效:http://forresto.github.io/dataflow-prototyping/react/

答案 3 :(得分:11)

svg { 
  transform-box: fill-box;
}

应用transform-box: fill-box将使SVG中的元素的行为像普通的HTML元素一样。然后,您可以像平常一样应用transform-origin: center(或其他方法)

是的,transform-box: fill-box。如今,不需要任何复杂的矩阵东西

答案 4 :(得分:8)

无需使用matrix转换即可进行缩放:

transform="translate(cx, cy) scale(sx sy) translate(-cx, -cy)"

这里是CSS:

transform: translate(cxpx, cypx) scale(sx, sy) translate(-cxpx, -cypx)

答案 5 :(得分:0)

我有类似的问题。但我使用 D3 来定位我的元素,并希望CSS处理转换转换。这是我原来的代码,我在Chrome 65中工作:

//...
this.layerGroups.selectAll('.dot')
  .data(data)
  .enter()
  .append('circle')
  .attr('transform-origin', (d,i)=> `${valueScale(d.value) * Math.sin( sliceSize * i)} 
                                     ${valueScale(d.value) * Math.cos( sliceSize * i + Math.PI)}`)
//... etc (set the cx, cy and r below) ...

这允许我使用相同的数据在javascript中设置cxcytransform-origin值。

但这在Firefox中无效!我要做的就是将circle包裹在g标记中并translate使用它与上面相同的定位公式。然后,我在circle标记中添加g,并将其cxcy值设置为0。从那里开始,transform: scale(2)将按预期从中心扩展。最终的代码看起来像这样。

this.layerGroups.selectAll('.dot')
  .data(data)
  .enter()
  .append('g')
  .attrs({
    class: d => `dot ${d.metric}`,
    transform: (d,i) => `translate(${valueScale(d.value) * Math.sin( sliceSize * i)} ${valueScale(d.value) * Math.cos( sliceSize * i + Math.PI)})`
  })
  .append('circle')
  .attrs({
    r: this.opts.dotRadius,
    cx: 0,
    cy: 0,
  })

进行此更改后,我将CSS更改为定位circle而不是.dot,以添加transform: scale(2)。我甚至不需要使用transform-origin

注意:

  1. 我在第二个例子中使用d3-selection-multi。这允许我将对象传递给.attrs,而不是为每个属性重复.attr

  2. 使用字符串模板文字时,请注意第一个示例中所示的换行符。这将在输出中包含换行符,可能会破坏您的代码。

答案 6 :(得分:-1)

在DOM内部设置嵌入元素的属性(transform-origin="center"对我来说很成功

          <circle
          fill="#FFFFFF"
          cx="82"
          cy="81.625"
          r="81.5"
          transform-origin="center"
        ></circle>

使用CSS转换效果很好