42

I want to manipulate the transform="translate(x,y)" attribute of a SVG element using JavaScript.

So I got this HTML code:

<body>

<svg id="test" preserveAspectRatio="xMidYMid meet" viewBox="0 0 100% 100%" xmlns="http://www.w3.org/2000/svg" version="1.1">
    <rect transform="translate(100,100)" width="300" height="100" style="fill:rgb(0,0,255);stroke-width:1;stroke:rgb(0,0,0)" />
    <rect transform="translate(400,400)" width="300" height="400" style="fill:red; stroke-width:1; stroke: yellow" />
</svg>

</body>

And this JavaScript code:

var positioner = (function(domUtils){

   var svg = document.getElementById("test");
   var elementOffset = 100;

   function getAbsoluteX(leftElement) {
    return domUtils.getWidth(leftElement) + elementOffset; 
   }

   function getAbsoluteY(topElement) {
    return domUtils.getHeight(topElement) + elementOffset;
   }   

   var rectangles = document.querySelectorAll("rect");
   for(var i = 0; i < rectangles.length; ++i) {
    var spaceLeft = 0;
    if(i > 0) {
      spaceLeft = getAbsoluteX(rectangles[i-1]);
    }
    var rect = rectangles[i];
    var attrValue = "translate(" + spaceLeft + ", 100)";
    rect.setAttribute('transform', attrValue);
   };
 })(domUtils);

Where getAbsoluteX() is a self-defined function.

It's working nice in firefox but not in chrome. Anyone knows a workaround or how to solve this?

Thanks. Regards.

  • 2
    It works fine for me (http://jsfiddle.net/un6ep/). What does the `getAbsoluteX` method do – mihai Apr 27 '12 at 16:52
  • Mysterious.. just pasted it into http://jsfiddle.net/nfRGw/ and it works fine. But if I am trying it offline, it does not work. Maybe jsfiddle uses some frameworks that enable support for Chrome? –  Apr 30 '12 at 19:40
  • 1
    `viewBox="0 0 100% 100%"` looks quite wrong – caub Jun 25 '17 at 10:49

2 Answers2

108

There are two ways to get/set transform values for SVG elements in Chrome, Firefox, IE, or any standards-fearing SVG user agent:

Handling Transforms via Attributes

// Getting
var xforms = myElement.getAttribute('transform');
var parts  = /translate\(\s*([^\s,)]+)[ ,]([^\s,)]+)/.exec(xforms);
var firstX = parts[1],
    firstY = parts[2];

// Setting
myElement.setAttribute('transform','translate(30,100)');

Pros: Simple to set and understand (same as the markup).
Cons: Have to parse the string value to find what you want; for animated values, can't ask for the base value when the animation is active; feels dirty.

Handling Transforms via SVG DOM Bindings

// Getting
var xforms = myElement.transform.baseVal; // An SVGTransformList
var firstXForm = xforms.getItem(0);       // An SVGTransform
if (firstXForm.type == SVGTransform.SVG_TRANSFORM_TRANSLATE){
  var firstX = firstXForm.matrix.e,
      firstY = firstXForm.matrix.f;
}

// Setting
myElement.transform.baseVal.getItem(0).setTranslate(30,100);

Pros: No need to try to parse strings on your own; preserves existing transform lists (you can query or tweak just a single transformation in the list); you get real values, not strings.
Cons: Can be confusing to understand at first; more verbose for setting simple values; no convenient method for extracting rotation, scale, or skew values from the SVGTransform.matrix, lack of browser support.

You may find a tool I wrote for exploring the DOM helpful in this.

  1. Go to http://objjob.phrogz.net/svg/object/131
  2. Click the "Show inherited properties/methods?" checkbox
  3. See that the SVGRectElement has a transform property that is an SVGAnimatedTransformList.
  4. Click on SVGAnimatedTransformList to see the properties and methods that object supports.
  5. Explore!
Yarin
  • 173,523
  • 149
  • 402
  • 512
Phrogz
  • 296,393
  • 112
  • 651
  • 745
  • If you had read my question then you would have figured out that I tried to set the value by using your first suggestion (via attributes). However, either the first or the second way do not work in Chrome but both work fine in firefox. –  Apr 30 '12 at 13:43
  • 1
    @Daniel I did read your question, and I know for certain that both work just fine in Chrime. You are doing something else wrong—perhaps the attribute value string is malformed—but without a reproducible test case I cannot tell you what it is for certain. – Phrogz Apr 30 '12 at 13:46
  • @DanielDinter Not really; without the `getAbsoluteX` function I have no way of knowing of `spaceLeft` gets set to `"kittens!"`; I cannot reproduce your problem—you have _not_ supplied a reproducible test case—and thus I cannot help you further. Sorry :/ – Phrogz Apr 30 '12 at 19:09
  • Now added the full javascript part. I do not think that the function `getAbsoluteX` is relevant to solve the problem, it just returns any integer value. You could also write `function getAbsoluteX() { return 100; }` ... –  Apr 30 '12 at 19:23
  • @DanielDinter And yet you still have not made it reproducible; there is no indication of what `domUtils` is, or how you invoke that function. If you can reproduce it more simply, then you should do so. Go to http://jsfiddle.net and recreate the smallest possible content that reproduces your problem. – Phrogz Apr 30 '12 at 19:24
  • Ok, see my comment above. Just pasted it into jsfiddle.net/nfRGw and it works fine. But if I am trying it offline, it does not work. Maybe jsfiddle uses some frameworks that enable support for Chrome? –  May 01 '12 at 18:43
  • Looks like **SVGTransform** has significant browser-compatibility issues. It's failing for me on Safari 5.1.9, and there's question marks for most browsers- see [SVGTransform#Browser_compatibility](https://developer.mozilla.org/en-US/docs/Web/API/SVGTransform#Browser_compatibility) – Yarin Jul 24 '13 at 01:31
  • @Yarin Please post a test case that fails. It works well for me in Safari. – Phrogz Jul 24 '13 at 04:23
  • 1
    readability would be better if you just renamed xForms to transforms. having variables names like that is confusing at first glance – Sami El Maameri Mar 28 '18 at 11:43
  • If the transform is null on the svg element, I get an error when trying to set it with myElement.transform.baseVal.getItem(0).setTranslate(). Is there a way to create the transform and then run that line? – Chano Apr 15 '21 at 02:44
-9

This is a pretty old question, but the answer, in case you were wondering, is that Chrome doesn't like translate(30, 100) - it needs units. It also prefers -webkit-transform for SVG.

borbulon
  • 1,391
  • 1
  • 11
  • 11
  • 4
    Care to support this with a reference or example? I followed your suggestion in an attempt to fix my own problem, and had no luck. – Nathan Gould Mar 05 '14 at 07:17
  • It must be a confusion with CSS transforms, which do need units - the SVG attribute `transform` doesn't. Also, the comma is redundant, it doesn't hurt but `translate(30 100)` is also compliant. – Robert Monfera Sep 21 '17 at 16:11