infodev
infodev

Reputation: 5235

Scale svg group without changing position

I would like to increase group of elements size when hover it.

I have used transform: scale() CSS property but when I hover object is moving from it's original position

p {
  font-family: Lato;
}

#stops>g:hover  {
        transform: scale(14);

    cursor: pointer;

}
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 775.43 469.98">
    <defs>
        <style>.cls-1{fill:none;stroke-width:5px;}.cls-1,.cls-2{stroke:#a15256;}.cls-2{fill:#fff;}.cls-3{isolation:isolate;font-size:42.79px;font-family:ArialMT, Arial;}</style>
    </defs>
    <title>line</title>
    <path id="path7" class="cls-1" d="M202,67.72,329.33,215.86" transform="translate(-200.1 -66.09)" />
    <path id="path8" class="cls-1" d="M329.35,215.87,449,355" transform="translate(-200.1 -66.09)" />
    <path id="path9" class="cls-1" d="M449,355c41.53,51.11,96.22,63.08,117.9,69.28" transform="translate(-200.1 -66.09)" />
    <path id="path10" class="cls-1" d="M566.86,424.29C655.43,460.48,977.38,391.48,973,536" transform="translate(-200.1 -66.09)" />
    <g id="stops">
        <g id="g3670">
            <circle class="cls-2" cx="129.24" cy="149.78" r="13.58" />
            <text id="text3668" class="cls-3" transform="translate(120.84 114.12)">Station1</text>
        </g>
        <g id="g3700">
            <circle class="cls-2" cx="248.91" cy="288.93" r="13.58" />
            <text id="text3698" class="cls-3" transform="translate(284.5 239)">Station2</text>
        </g>
        <g id="g3750">
            <circle class="cls-2" cx="366.75" cy="358.2" r="13.58" />
            <text id="text3748" class="cls-3" transform="translate(134.96 379.59)">Station3</text>
        </g>
    </g>
</svg>

Expected behaviour

I would like to increase text size and station circle ( and fill it ) without changing their position.

It could be done with css, but if I could have recommendation of libraries because I would make animations on the subway line ( trains circulations ) that would be great

Upvotes: 0

Views: 2268

Answers (1)

enxaneta
enxaneta

Reputation: 33064

In the next demo I'm removing the transformation from the text and I'm adding x and y attributes. The transformation happens when you mouse over the circle. In order to transform the text as well I'm using this selector: #stops g circle:hover + text

Alternatively instead of transformation for the text you could have changed the font size.

text{
  font-family: Lato;
  font-size:16px;
}

#stops g circle:hover  {
    transform: scale(2);
    transform-origin: 50% 50%;
    transform-box: fill-box;
    cursor: pointer;
}

#stops g circle:hover + text{
    transform: scale(2);
    transform-origin: 0% 50%;
    transform-box: fill-box;
    cursor: pointer;
    pointer-events:none;
}
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 775.43 469.98">
    <defs>
        <style>.cls-1{fill:none;stroke-width:5px;}.cls-1,.cls-2{stroke:#a15256;}.cls-2{fill:#fff;}.cls-3{isolation:isolate;font-size:42.79px;font-family:ArialMT, Arial;}</style>
    </defs>
    <title>line</title>
    <path id="path7" class="cls-1" d="M202,67.72,329.33,215.86" transform="translate(-200.1 -66.09)" />
    <path id="path8" class="cls-1" d="M329.35,215.87,449,355" transform="translate(-200.1 -66.09)" />
    <path id="path9" class="cls-1" d="M449,355c41.53,51.11,96.22,63.08,117.9,69.28" transform="translate(-200.1 -66.09)" />
    <path id="path10" class="cls-1" d="M566.86,424.29C655.43,460.48,977.38,391.48,973,536" transform="translate(-200.1 -66.09)" />
    <g id="stops">
        <g id="g3670">
            <circle class="cls-2" cx="129.24" cy="149.78" r="13.58" />
            <text id="text3668" class="cls-3" x="145" y="149.78" >Station1</text>
        </g>
        <g id="g3700">
            <circle class="cls-2" cx="248.91" cy="288.93" r="13.58" />
            <text id="text3698" class="cls-3"  x="270" y="288.93">Station2</text>
        </g>
        <g id="g3750">
            <circle class="cls-2" cx="366.75" cy="358.2" r="13.58" />
            <text id="text3748" class="cls-3" x="385" y="358.2">Station3</text>
        </g>
    </g>
</svg>

The OP is commenting that

The hover should be on g g:hover not g circle:hover

In this case I'm adding a rectangle to the g element. The rectangle is as big as the g's bounding box. Everything in the g element except the rect has pointer-events:none. The transformation happens around the center of the circle.

text{
  font-family: Lato;
  font-size:16px;
}
g * {pointer-events:none;}
g rect{pointer-events:all;}
#stops g{transform: scale(1);}
#stops g:hover {
    transform: scale(2);
    transform-origin: 129.24px 149.78px;
    cursor: pointer;
}
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 775.43 469.98">
    <defs>
        <style>.cls-1{fill:none;stroke-width:5px;}.cls-1,.cls-2{stroke:#a15256;}.cls-2{fill:#fff;}.cls-3{isolation:isolate;font-size:42.79px;font-family:ArialMT, Arial;}</style>
    </defs>
    <title>line</title>
    <path id="path7" class="cls-1" d="M202,67.72,329.33,215.86" transform="translate(-200.1 -66.09)" />
    <path id="path8" class="cls-1" d="M329.35,215.87,449,355" transform="translate(-200.1 -66.09)" />
    <path id="path9" class="cls-1" d="M449,355c41.53,51.11,96.22,63.08,117.9,69.28" transform="translate(-200.1 -66.09)" />
    <path id="path10" class="cls-1" d="M566.86,424.29C655.43,460.48,977.38,391.48,973,536" transform="translate(-200.1 -66.09)" />
    <g id="stops">
        <g id="g3670">
            <rect x="115" y="110" width="187" height="52" fill="none" />
            <circle class="cls-2" cx="129.24" cy="149.78" r="13.58" />
            <text id="text3668" class="cls-3" x="145" y="149.78" >Station1</text>
        </g>
        
    </g>
</svg>

In order to calculate the <g>'s bounding box you can use javascript and the method getBBox().

In order to better understand what happens please add a fill to the <rect>

You can keep the text transformation if this is what you want.

UPDATE 2

the OP is commenting:

Can you make an example with three dots please ?

Next comes the example. In this case I'm using Javascript to set the size of the rects and the value for the transform-origin of every group. If you need only the markup you can copy it from the inspector. Since the OP commented that they would like to keep the text transformation in this example the text keeps the transformation instead of the x and y attributes.

let stops = document.querySelector("#stops");
// all the g elements in the stops 
let gs = stops.querySelectorAll("g");

// for each g in the gs
gs.forEach(g=>{
  // the rectangle in this g element
  let thisRect = g.querySelector("rect");
  // the circle in this g element
  let thisCircle = g.querySelector("circle");
  // the coords of the circle's center used for the transform-origin
  let x = thisCircle.getAttribute("cx");
  let y = thisCircle.getAttribute("cy");
  // the bounding box of the group
  let bb = g.getBBox();
  // set the rect's attributes
  thisRect.setAttributeNS(null, "x", bb.x);
  thisRect.setAttributeNS(null, "y", bb.y);
  thisRect.setAttributeNS(null, "width", bb.width);
  thisRect.setAttributeNS(null, "height", bb.height);
  
  // set the value for the transform-origin for this group
  g.style.transformOrigin =  `${x}px ${y}px`;
  
})
text{
  font-family: Lato;
  font-size:16px;
}
g * {pointer-events:none;}
g rect{pointer-events:all;}
#stops g{transform: scale(1);cursor: pointer;}
#stops g:hover {
    transform: scale(2); 
}
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 775.43 469.98">
    <defs>
        <style>.cls-1{fill:none;stroke-width:5px;}.cls-1,.cls-2{stroke:#a15256;}.cls-2{fill:#fff;}.cls-3{isolation:isolate;font-size:42.79px;font-family:ArialMT, Arial;}</style>
    </defs>
    <title>line</title>
    <path id="path7" class="cls-1" d="M202,67.72,329.33,215.86" transform="translate(-200.1 -66.09)" />
    <path id="path8" class="cls-1" d="M329.35,215.87,449,355" transform="translate(-200.1 -66.09)" />
    <path id="path9" class="cls-1" d="M449,355c41.53,51.11,96.22,63.08,117.9,69.28" transform="translate(-200.1 -66.09)" />
    <path id="path10" class="cls-1" d="M566.86,424.29C655.43,460.48,977.38,391.48,973,536" transform="translate(-200.1 -66.09)" />
    <g id="stops">
        <g id="g3670">
            <rect fill="none"/>
            <circle class="cls-2" cx="129.24" cy="149.78" r="13.58" />
            <text id="text3668" class="cls-3" transform="translate(145 160)">Station1</text>
        </g>
        <g id="g3700">
            <rect fill="none"/>
            <circle class="cls-2" cx="248.91" cy="288.93" r="13.58" />
            <text id="text3698" class="cls-3" transform="translate(270 300)">Station2</text>
        </g>
        <g id="g3750">
            <rect fill="none"/>
            <circle class="cls-2" cx="366.75" cy="358.2" r="13.58" />
            <text id="text3748" class="cls-3" transform="translate(200 400)">Station3</text>
        </g>
    </g>
</svg>

Upvotes: 3

Related Questions