旋转SVG圆形使用组元素

3
我想要旋转一个SVG圆圈,同时保持其他元素不旋转。

enter image description here

当我尝试使用rotateZ(15deg)旋转白色圆圈时,我得到了这个结果: enter image description here 这是我的进展情况: 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>

我希望实现:
  • 点击白色圆圈上的点时,圆圈(白色)会旋转
2个回答

4

我不会旋转一切,而是计算圆上点的位置,并使用这些点的坐标绘制线条和文本。

为此,我使用JavaScript。脚本中最重要的部分是一个用于计算旋转点新位置的函数:rotatePoint(p, c, rot)

请注意,在svg中,我已经消除了无用的变换。

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 + (p.x - c.x) * cos - (p.y - c.y) * sin,
    y: c.y + (p.x - c.x) * sin + (p.y - 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 = {};

  p.x = dot.getAttribute("cx");
  p.y = 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>


1
很棒的答案!对我来说既有趣又有用。 - Alexandr_TT

1
我在想是否可以不使用JavaScript来完成。在下一个演示中,我只是使用JavaScript来更改旋转值。
由于我正在使用SVG变换,角度以度为单位而不是弧度。
主要思路是这样的:我创建了一个嵌套的SVG元素。当我将G向一个方向旋转时,我需要将线和文本以相反的方向旋转同样数量的度数。问题是,在旋转G时,点的位置正在改变,我需要知道该位置以将其用作线和文本的枢轴。
解决方法是将所有内容放入嵌套的SVG中,其中所有内容保持在相同的位置并旋转嵌套的SVG。结果发现在SVG 1.1中,元素不允许使用transform属性。因此,我将每个嵌套的SVG都放在一个组中,并旋转了该组。

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>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接