Search code examples
javascriptsvgsvg-animate

Svg image changes size after setting transform rotate


I've made a svg with a car (image) that follows the mouse and keeps it nose to the center of a circle.

This works very well in Windows. (tested on Chrome, Firefox, Edge).


The problem

When the position changes and the rotation is set, the car changes size for no reason. This happens (I think) on IOS divices (tested on Macbook - Safari and iPhone - Safari & Chrome)

The position is simply changed by setting the x and y of the image. The rotation (what I think is causes the problem) is changed by setting the attribute transform.

image.setAttributeNS(null, 'x', (xy.x - (12 * 0.25)));
image.setAttributeNS(null, 'y', (xy.y - (5.4 / 2)));
image.setAttributeNS(null, 'transform', 'rotate(' + (180 - angle) + ',' + xy.x + ',' + xy.y + ') '); 

I've made a fiddle that toggles the car when clicking a button. Please try it in Safari and Chrome to see the difference.

https://jsfiddle.net/065o4xke/3/


Solution

  • Please let me know if this is the movement you are looking for:

    var circle = document.getElementById("circle");
    var radius = 100 / (2 * Math.PI);
    var xmlns = "http://www.w3.org/2000/svg";
    var procent = 100 / (360 / 15);
    var offset = 0 - procent / 2;
    
    let angle = 0
    
    function rotateCar(){
      requestAnimationFrame(rotateCar);
      angle +=.5;
      car.setAttributeNS(null, 'transform', `rotate(${angle},21,21)`);
    }
    
    rotateCar()
    .wrapper {
      height: 300px;
      width: 300px;
      border: 1px solid black;
    }
    <div class="wrapper">
      <svg id="svg" viewBox="0 0 42 42" width="100%" height="100%">
          <circle cx="21" cy="21" r="16" stroke="red" fill="none" />
          
          <image id="car" xlink:href="//cdn.via.nl/img/mainmot/4.svg" x="2.1450689516760377" y="16.912873272286454" width="12" height="5.4" transform="rotate(0,21,21)"></image>
      </svg>
    </div>

    Also in the case you want to center the car on the path you can do something like this: You wrap the image in a group. Inside the group the car is translated so that is centered. Next you rotate the group.

    var circle = document.getElementById("circle");
    var radius = 100 / (2 * Math.PI);
    var xmlns = "http://www.w3.org/2000/svg";
    var procent = 100 / (360 / 15);
    var offset = 0 - procent / 2;
    
    let angle = 0
    
    function rotateCar(){
      requestAnimationFrame(rotateCar);
      angle +=.5;
      car.setAttributeNS(null, 'transform', `rotate(${angle},21,21)`);
    }
    
    rotateCar()
    .wrapper {
      height: 300px;
      width: 300px;
      border: 1px solid black;
    }
    <div class="wrapper">
      <svg id="svg" viewBox="0 0 42 42" width="100%" height="100%">
          <circle cx="21" cy="21" r="16" stroke="red" fill="none" />
          <g id="car" transform="rotate(0,21,21)">
          <image xlink:href="//cdn.via.nl/img/mainmot/4.svg" x="0" y="21" width="12" height="5.4" transform="translate(0,-2.7)" ></image>
        </g>
      </svg>
    </div>