1

Problem

I'm trying to simply move an svg element using transform=matrix(a,b,c,d,e,f)

The element is moving fine but when I apply a css transition it has no effect.

Question

Is this possible on svg elements without an external library like d3?

Code I'm trying

html:

<svg width="100%" height="100%" viewbox="0 0 200 200">
    <rect x="20" y="20" width="50" height="50"
      style="fill: #3333cc"
      transform="matrix(1,0,0,1,1,1)"
      id="blueBox"
        />    
</svg>
<button id="boxMover">
    Move it
</button>

jQuery

$(function(){
    $('#boxMover').click(function(){
  var blueBox = $('#blueBox');
    if(blueBox.attr('transform')=='matrix(1,0,0,1,1,1)'){
        blueBox.attr('transform', 'matrix(1,0,0,1,100,30)');
    } else {
        blueBox.attr('transform', 'matrix(1,0,0,1,1,1)');
    }
  })
})

CSS

svg {
  display: block
}
#boxMover {
  position: absolute;
  left: 20px;
  top: 20px;
  transition: transform .5s ease;
}

Here's a fiddle I created to test it

StudioTime
  • 22,603
  • 38
  • 120
  • 207

2 Answers2

2

There's a horrible grey area between the CSS and SVG namespaces where things like this happen all the time.

However, you can fix your problem as follows:

  1. Move the transform CSS statement out of the #boxMover rules and put it somewhere it can actually affect the behaviour of your #blueBox SVG element.

  2. Changing the transform attributes of the SVG element directly still won't work because you're talking to the SVG namespace, and the CSS rules aren't having any say in the matter. Instead, set up CSS classes containing the required transform attributes, and switch between those instead. There is no class attribute in the SVG namespace, so the CSS rules will come to life.

  3. Also note that you can't use JQuery's addClass() and removeClass() methods to change the class of an SVG element, so use attr('class') instead

This should work:

$(function() {
  $('#boxMover').click(function() {
    var blueBox = $('#blueBox');
    if (blueBox.attr('class') == 'overHere') {
      blueBox.attr('class', 'overThere');
    } else {
      blueBox.attr('class', 'overHere');
    }
  })
})
svg {
  display: block
}
#boxMover {
  position: absolute;
  left: 20px;
  top: 20px;
}
#blueBox {
  transition: transform .5s ease;
}
.overHere {
  transform: matrix(1, 0, 0, 1, 1, 1);
}
.overThere {
  transform: matrix(1, 0, 0, 1, 100, 30);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg width="100%" height="100%" viewbox="0 0 200 200">
  <rect x="20" y="20" width="50" height="50"
        style="fill: #3333cc" class="overHere" id="blueBox" />
</svg>
<button id="boxMover">
  Move it
</button>
Community
  • 1
  • 1
r3mainer
  • 23,981
  • 3
  • 51
  • 88
  • Thanks, this is good but the position the element is going to is dynamic, based on a couple of hundred different combinations, hence why I did it with jQuery - is there a way to do it with dynamic matrix setting? – StudioTime Mar 11 '16 at 21:57
2

A simpler solution:

  1. Create the following class:

    .boxEase { transform: matrix(1,0,0,1,100,30); transition: all .5s ease; }

  2. Change your jQuery code to just attach the above class to your box when the button is clicked:

    $(function(){ $('#boxMover').click(function(){ var blueBox = $('#blueBox'); blueBox.attr('class', 'boxEase'); }) })

Added dynamic case with variable ending (starting) positions

Use the following jQuery code where transform and transition properties are added to the box conditionally. I imagine you can adjust the conditional to something else but I have used your original example for this case:

`$(function(){
   $('#boxMover').click(function(){
     var startPos = 'matrix(1,0,0,1,1,1)',
         endPos = 'matrix(1,0,0,1,100,30)';

     var blueBox = $('#blueBox');
     if(blueBox.attr('transform') == startPos){
       blueBox.attr('transform', endPos);
       blueBox.css({'transform': endPos, 'transition': 'all 0.5s ease'});
     } else {
     blueBox.attr('transform', startPos);
     blueBox.css({'transform': startPos, 'transition': 'all 0.5s ease'});
     }
   })
}); `
rby
  • 754
  • 6
  • 10
  • Thanks, as I said in comment to @squeamish, the "to" position is somewhat dynamic so can't be added by preset class unfortunately – StudioTime Mar 11 '16 at 21:59
  • @DarrenSweeney I have added a dynamic case that should allow you to vary the "to" position as you said (and also the starting position). Hope this helps a bit at least. – rby Mar 11 '16 at 23:17