StudioTime
StudioTime

Reputation: 24019

Transition svg element with css

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

Upvotes: 1

Views: 2572

Answers (2)

rby
rby

Reputation: 786

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

Upvotes: 2

r3mainer
r3mainer

Reputation: 24587

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>

Upvotes: 2

Related Questions