-1

I want to change the attributes on an svg element in an html page.

svgElement.setAttribute("width", `${width_}`); //instruction 1
svgElement.setAttribute("height", `${height_}`); //instruction 2
svgElement.setAttribute("viewBox",`${x} ${y} ${width_} ${height_}`); // instruction 3

width_ and height_ are new values, different from the pre existing attribute values.

"instruction 1" causes a horizontal zoom.

"instruction 2" causes a vertical zoom.

"instruction 3" zooms everything back to how it was before, as if there had been no zooming at all.

Is it possible to avoid this effect ?

I was looking into the possibility of setting multiple attributes in one single transaction, but it does not seem possible (correct me if I am wrong).

Ludovic Aubert
  • 9,534
  • 4
  • 16
  • 28
  • Why are you changing the viewBox and the width/height and the same time. You'd generally want to change one or the other, not both. – Robert Longson May 26 '23 at 16:04

1 Answers1

0

If changing the <svg> element's size and viewBox at almost the same time leads to flickering, consider leaving the <svg> element's size and viewBox unchanged and changing only the size of

  • a <div> element surrounding the <svg> element and
  • a <clipPath> element controlling the visible size of the <svg> contents.

function resize1() {
  var s = document.getElementById("s1");
  s.classList.toggle("small");
  s.viewBox.baseVal.width =
  s.viewBox.baseVal.height =
  s.classList.contains("small") ? 100 : 200;
}

function resize2() {
  var s = document.getElementById("s2");
  s.classList.toggle("small");
  s.querySelector("clipPath>rect")
   .classList.toggle("small");
}
.size.small { height: 100px; width: 100px; }
.size:not(.small) { height: 200px; width: 200px; }
div { overflow: hidden; }
<p><button onclick="resize1()">Resize</button></p>
<svg id="s1" viewBox="0 0 100 100" class="size small">
  <circle cx="100" cy="100" r="100"/>
</svg>
<p><button onclick="resize2()">Resize</button></p>
<div id="s2" class="size small">
  <svg viewBox="0 0 200 200" class="size" clip-path="url(#c")>
    <clipPath id="c">
      <rect x="0" y="0" class="size small"/>
    </clipPath>
    <circle cx="100" cy="100" r="100"/>
  </svg>
</div>
<hr>

But in this example at least, I cannot really spot a difference between the two approaches.

Heiko Theißen
  • 12,807
  • 2
  • 7
  • 31