如何在SVG中设置变换原点


104

我需要使用JavaScript调整SVG文档中的某些元素的大小并旋转它们。问题是,默认情况下,它始终围绕(0, 0)左上角的原点应用变换。

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

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

这是我的方法:

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

尽管我可以在Firefox中看到正确设置了属性,但似乎没有将枢轴点设置为我指定的点。我尝试之类的东西center bottom,并50% 100%有和没有括号。到目前为止没有任何工作。

有人可以帮忙吗?


FWIW,据说已从Firefox 19 beta 3开始修复,尽管我在Firefox 22中仍然遇到问题。Mozilla bugzilla列表:bugzilla.mozilla.org/show_bug.cgi?
id

Answers:


147

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

要缩放/调整大小,您必须先按(-cx,-cy)进行转换,然后进行缩放,然后再转换回(cx,cy)。您可以使用矩阵变换来做到这一点:

transform="matrix(sx, 0, 0, sy, cx-sx*cx, cy-sy*cy)"

其中sx是x轴的比例因子,sy是y轴。


非常感谢。我认为Rotate可以完美工作,但是缩放/调整大小总是最终有一些随机量。我试着使用矩阵并像“ translate(cx sx,cy sy)scale(sx,sy)” 那样单独进行处理。相同的结果。
CTheDark 2011年

6
会不会是transform =“ matrix(sx,0,0,sy,cx-sx cx,cy-sy cy)”?因为您只想按差异翻译。我认为这种逻辑是正确的,但它仍然给了我职位……
CTheDark 2011年

现在可以了!我只是使用了错误的cx和cy值!非常感谢!
CTheDark

1
@JayStevens是的,矩阵转换将适用于任何系统,这仅仅是数学。唯一的区别可能是符号。据我所知,CSS矩阵转换使用与SVG相同的符号,因此按此顺序使用相同的六个数字即可。
彼得·科林里奇

1
需要澄清的是,cx和cy需要偏移缩放比例的框中心。这让我有些困惑,就像我在CSS框模型中所考虑的那样。@forresto在下面的回答中暗示了这一点。
杰森·法恩斯沃思

22

如果可以使用固定值(而不是“中心”或“ 50%”),则可以使用CSS代替:

-moz-transform-origin: 25px 25px;
-ms-transform-origin:  25px 25px;
-o-transform-origin: 25px 25px;
-webkit-transform-origin:  25px 25px;
transform-origin: 25px 25px;

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


1
哇。如果可以的话,将+10。这挽救了我的一天!谢谢。
Cullub's

如何做到这一点,以及仅在JavaScript中做到这一点?
安德鲁·S

喜欢element.setAttribute('transform-origin', '25px 25px')吗?
尼克·黄

13

如果您像我一样,并且想要平移然后使用转换原点进行缩放,则需要更多。

// <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/


您的github链接
404s

您好@NuclearPeon,这太棒了,但是我似乎无法在我的代码中实现它。我希望将其应用于的SVG元素已经是一个名为“ mainGrid”的变量。我尝试用“ mainGrid”替换“ view”的实例无效。我想念什么?谢谢!
savoferret

@sakeferret要检查的最明显的事情是和文档属性中的id匹配。不看代码就很难确定。如果您不想将其发布为SO问题,则可以尝试使用属性名称创建最简单的示例,直到它起作用/找到问题为止,然后再添加其余部分getElementByIdid="..."
。– NuclearPeon

12

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

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

在CSS中:

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

0

好像我们都错过了这里的把戏: transform-box: fill-box

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

是的,transform-box: fill-box不需要任何复杂的矩阵


-1

我有一个类似的问题。但是我使用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) ...

这让我设置cxcy以及transform-origin使用相同的数据在JavaScript值。

但是,这在Firefox中不起作用!我要做的是将标签包裹circleg标签中,translate并使用与上面相同的定位公式。然后,我circleg标签中附加,并将其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. 使用字符串模板文字时,请注意第一个示例中的换行符。这将在输出中包含换行符,并且可能会破坏您的代码。


2
也许如果您设置了transform-b​​ox:fill-box; Firefox可以按照您想要的方式工作。
罗伯特·朗森18'Mar 21'18

尝试了。似乎没有用。在我更改了Firefox 页面的首选项后,它确实起作用svg:transform-origin.enabledabout:config。但是...这似乎不是一个适当的解决方案。我还发现transform-origin: 50% 50%和之间存在差异transform-origin: center center
Jamie S

svg.transform-origin.enabled首选项已在许多版本中删除。除非您使用的是非常旧的版本,否则50%和center之间应该没有差异。如果Firefox 59或更高版本有所不同,请随时提出bugzilla错误。
罗伯特·朗森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.