简体   繁体   中英

Rotating a SVG circle with group element

I'd like to rotate a SVG circle while keeping the other elements from rotating

在此处输入图像描述

when I am trying to rotate the circle(white color) by using rotateZ(15deg), this is what I got: 在此处输入图像描述

This is my progress so far: https://jsfiddle.net/41hrnojs/

<svg viewBox="0 0 1400 900" style="outline:1px solid red;">
            <g>
               <clipPath id="hexagonal-mask">
                  <circle cx="700" cy="100" r="705" ></circle>
               </clipPath>
            </g> 
            <a>
             <image clip-path="url(#hexagonal-mask)" height="100%" width="100%" xlink:href="{{ asset('images/H3z50J2.jpg') }}"  style="transform: translateY(-140px);"/>
            </a>

            <g  style="transform-origin: 701px -5%; transform: rotateZ(15deg)">
                <circle cx="701" cy="0" r="665" stroke="#fff" stroke-width="1px" fill="transparent"  style="transform: translateY(-50px);" ></circle>
               
                <!-- center dot -->
                <g id="g1" >
                    <circle cx="701" cy="615" r="15" fill="#fff">
                        
                    </circle> 
                    <path  stroke="#000" stroke-width="1px" d="M701 630 701 690"></path>
                   
                    <text x="672" y="720" font-family="'Playfair Display', serif" font-size="2em" font-weight="bold" fill="#9d9e9f">2007</text>
                    <text x="640" y="730" font-family="'Playfair Display', serif" font-size="2.85em" font-weight="bold" fill="#000">
                        <tspan x="640" dy="40">Lorem</tspan>
                        <tspan x="640" dy="45">Ipsum</tspan>
                    </text>
                    
                    <animateMotion 
                       xlink:href="#g1"
                       dur="1s"
                       begin="click"
                       fill="freeze"
                       path="M0 100 Q50 80 -399 -135"
                       repeatCount="1">
                        
                    </animateMotion>
                </g>
                
                
                

                <!-- left dot -->
                <g>
                    <!-- <circle cx="305" cy="485" r="15" fill="#fff"></circle> -->
                    <circle cx="302" cy="480" r="15" fill="#fff"></circle>
                    <path stroke="#000" stroke-width="1px" d="M302 495 305 675"></path>
                </g>

                <!-- right dot -->
                <g>
                    <circle cx="1100" cy="480" r="15" fill="#fff"></circle>
                    <path  stroke="#000" stroke-width="1px" d="M1100 495 1100 675"></path>
                </g>
            </g>

        </svg>

I'd like to achieve

  • The circle(white color) rotate while clicking the dots on the white
    circle

Instead of rotating everything I would calculate the position of the dots on the circle and use the coordinates of the dots to draw the line and the text.

For this I'm using javascript. The most important part in the script is a function used to calculate the new position of the rotated point: rotatePoint(p, c, rot)

Please observe that in the svg I've eliminated useless transformations.

 let theG = document.querySelector("#theG"); //the center of the circle let center = { x: 700, y: -40 }; //thr rotation in radians let rot =.6; //a function to calculate the new position of a rotated point function rotatePoint(p, c, rot) { // p: the point // c: the center of rotation // rot: the rotation let cos = Math.cos(rot); let sin = Math.sin(rot); return { x: c.x + (px - c.x) * cos - (py - c.y) * sin, y: c.y + (px - c.x) * sin + (py - c.y) * cos }; } //all the groups with a class of dot let groups = theG.querySelectorAll(".dot"); let points = []; groups.forEach((g) => { let dot = g.querySelector("circle"); let p = {}; px = dot.getAttribute("cx"); py = dot.getAttribute("cy"); points.push(p) }); itr.addEventListener("input",()=>{ let rot = itr.value; groups.forEach((g,i) => { let dot = g.querySelector("circle"); let line = g.querySelector("line"); let t1 = g.querySelectorAll("text")[0]; let newPoint = rotatePoint(points[i], center, rot); dot.setAttribute("cx", newPoint.x); dot.setAttribute("cy", newPoint.y); line.setAttribute("x1", newPoint.x); line.setAttribute("x2", newPoint.x); line.setAttribute("y1", newPoint.y); line.setAttribute("y2", newPoint.y + 180); t1.setAttribute("x", newPoint.x); t1.setAttribute("y", newPoint.y + 200); }); });
 input{width:90vw;} p{text-align:center;} text{text-anchor:middle} line{stroke:#000; stroke-width:1px; }
 <p><input type="range" id="itr" min="-.85" max=".85" value="0" step=".01" /></p> <svg viewBox="0 0 1400 900" style="outline:1px solid red;" > <defs> <clipPath id="hexagonal-mask"> <circle cx="700" cy="-40" r="705"></circle> </clipPath> </defs> <image clip-path="url(#hexagonal-mask)" height="100%" width="100%" xlink:href="https://assets.codepen.io/222579/castell.jpg"></image> <circle cx="700" cy="-40" r="655" stroke="#fff" stroke-width="1px" fill="transparent"></circle> <g id="theG"> <g class="dot"> <circle cx="700" cy="615" r="15" fill="#fff"></circle> <line x1="700" y1="615" x2="700" y2="795"></line> <text x="700" y="815" font-family="'Playfair Display', serif" font-size="2em" font-weight="bold" fill="#9d9e9f">2007</text> </g> <g class="dot"> <circle cx="302" cy="480" r="15" fill="#fff"></circle> <line x1="302" y1="480" x2="302" y2="660"></line> <text x="302" y="680" font-family="'Playfair Display', serif" font-size="2em" font-weight="bold" fill="#9d9e9f">2006</text> </g> <g class="dot"> <circle cx="1100" cy="480" r="15" fill="#fff"></circle> <line x1="1100" y1="480" x2="1100" y2="660"></line> <text x="1100" y="680" font-family="'Playfair Display', serif" font-size="2em" font-weight="bold" fill="#9d9e9f">2008</text> </g> </g> </svg>

I was wondering if it can be done without javascript. In the next demo I'm using javascript just in order to change the rotation value.

Since I'm using svg transforms the angles are in degs not in radians.

The main idea is this: I'm creating a nested svg element. While I'm rotating theG in one direction I need to rotate the line and the text the same number of degrees in the opposite direction. The problem is that while rotating theG, the dots are changing the position and I need to know that position to use it as a hub for the line and the text.

The solution is to put everything in a nested svg where everything stays in the same position and rotate the nested svg. As it comes out in SVG 1.1, the element did not allow the transform attribute . So I've putted every nested svg in a group and rotated the group instead.

 itr.addEventListener("input",()=>{ let rot = itr.value; theG.setAttribute("transform",`rotate(${rot} 700 -40)`) dot2006.setAttribute("transform",`rotate(${-rot} 302 480)`); dot2007.setAttribute("transform",`rotate(${-rot} 700 600)`); dot2008.setAttribute("transform",`rotate(${-rot} 1100 480)`); });
 input{width:90vw;} p{text-align:center;} text{text-anchor:middle; font-family:'Playfair Display' serif; font-size:2em; font-weight:bold; fill:#9d9e9f;} line{stroke:#000; stroke-width:1px; }
 <p><input type="range" id="itr" min="-45" max="45" value="0" /></p> <svg viewBox="0 0 1400 900" style="outline:1px solid red;"> <defs> <clipPath id="hexagonal-mask"> <circle cx="700" cy="-40" r="705"></circle> </clipPath> <g id="cl"> <:--<rect x="-32" y="-15" width="64" height="224" fill="gold"/>--> <circle r="15" fill="#fff"></circle> <line y2="180"></line> </g> </defs> <image clip-path="url(#hexagonal-mask)" height="100%" width="100%" xlink:href="https.//assets.codepen.io/222579/castell:jpg"></image> <circle cx="700" cy="-40" r="655" stroke="#fff" stroke-width="1px" fill="transparent"></circle> <g id="theG" transform="rotate(0 700 -40)"> <g id="dot2007" transform="rotate(0 700 600)"> <:--transform="rotate(-25 668+32 600+15)"--> <svg x="668" y="600" width="64" height="224" viewBox="-32 -15 64 224" > <use xlink:href="#cl"/> <text y="200">2007</text> </svg> </g> <g id="dot2006" transform="rotate(0 302 480)"> <!--transform="rotate(-25 270+32 465+15)"--> <svg x="270" y="465" width="64" height="224" viewBox="-32 -15 64 224"> <use xlink:href="#cl"/> <text y="200">2006</text> </svg> </g> <g id="dot2008" transform="rotate(0 1100 480)"> <!--transform="rotate(-25 1068+32 465+15)"--> <svg x="1068" y="465" width="64" height="224" viewBox="-32 -15 64 224"> <use xlink:href="#cl"/> <text y="200">2008</text> </svg> </g> </g> </svg>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM