Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

169
Visualizações
Scaling SVG with cursor position as transform origin

I am trying to scale an SVG cirle with trackpad (by moving two fingers up/down) and the origin of the transform must be the position of the cursor. The scaling performs well for the first time, and for every other attempt the circle changes position (it should not). This can be seen clearly if the cursor is inside the circle and near the perimeter of it. Below is the code.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" content="width=device-width">

    <style>
        .container
        {
            position: fixed;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;
        }

    </style>
</head>
<body>


<div class="container">
    <svg id="svg" height="600" width="600">
        <circle cx="300" cy="300" r="300" stroke="black" stroke-width="3" fill="white"/>
    </svg>
</div>

<script>
    let scale = 1;
    const e = document.getElementById("svg");

    function wheelZoom(event)
    {
        event.preventDefault();

        scale += event.deltaY * -0.01;
        scale = Math.min(Math.max(.5, scale), 2);

        x = 100*(event.clientX-e.getBoundingClientRect().x)/e.getBoundingClientRect().width;
        y = 100*(event.clientY-e.getBoundingClientRect().y)/e.getBoundingClientRect().height;

        e.style.transformOrigin = `${x}% ${y}%`;
        e.style.transform = `scale(${scale})`;
    }

    e.addEventListener("wheel", wheelZoom);
</script>


</body>
</html>

about 4 years ago · Juan Pablo Isaza
1 Respostas
Responde à pergunta

0

I'm not sure about a couple of things:

  • what you mean by you don't want the circle to change position
  • also whether you actually want the whole SVG to scale, or just the circle inside the SVG

In the following demo, I went with keeping the SVG unchanged, but scaling the circle based on where inside the SVG you are when you roll the mouse wheel

Hopefully it is what you were after.

//    let scale = 1;
const svg = document.getElementById("svg");
const circle = document.querySelector("svg circle");

// Circle transform. Inits to 1:1 scale (called an "identity transform").
var   circleTransform = svg.createSVGMatrix();  // start

svg.addEventListener("wheel", wheelZoom);


function wheelZoom(event)
{
   event.preventDefault();

   // Get the mouse position as SVG coordinates
   var coords = convertScreenCoordsToSvgCoords(event.clientX, event.clientY);

   // Calculate an appropriate scale adjustment
   var scale = 1.0 + (event.deltaY * 0.001);

   // To scale around the mouse coords, first we transform the coordinate
   // system so that the origin is at the mouse coords.
   circleTransform = circleTransform.translate(coords.x, coords.y);
   // Then we apply the scale
   circleTransform = circleTransform.scale(scale, scale);
   // Finally we move the coordinate system back to where it was
   circleTransform = circleTransform.translate(-coords.x, -coords.y);

   // Now we need to update the circle's transform
   var transform = svg.createSVGTransform();        // An SVGTransform DOM object...
   transform.setMatrix(circleTransform);            // set to the new circleTransform...
   circle.transform.baseVal.initialize(transform);  // and used to update the circle transform property
}


function convertScreenCoordsToSvgCoords(x, y) {
   var pt = svg.createSVGPoint();  // An SVGPoint SVG DOM object
   pt.x = x;
   pt.y = y;
   // getScreenCTM tells us the combined transform that determines where 
   // the circle is rendered. Including any viewBox.
   // We use the inverse of that to convert the mouse X and Y to their
   // equivalent values inside the SVG.
   pt = pt.matrixTransform(circle.getScreenCTM().inverse());
   return {'x': pt.x, 'y': pt.y};
}
svg {
  background-color: linen;
}
<div class="container">
   <svg id="svg" height="600" width="600">
      <circle cx="300" cy="300" r="300" stroke="black" stroke-width="3" fill="white"/>
   </svg>
</div>

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda