Вращение круга SVG с элементом группы
Я хотел бы вращать SVG-круг, не давая вращаться другим элементам
Когда я пытаюсь повернуть круг (белого цвета) с помощью rotateZ (15 градусов), то это выглядит, как на рисунке ниже:
Это мой прогресс до сих пор: jsfiddle
Я хотел бы достичь
Круг (белого цвета) вращается, когда происходит клик по белому кругу
Свободный перевод вопроса Rotating a SVG circle with group element от участника @JackPowell.
Ответы (2 шт):
Вместо того, чтобы вращать все, я бы вычислял положение точек на круге и использовал координаты точек, чтобы нарисовать линию и текст.
Для этого я использую JavaScript. Наиболее важной частью в скрипте является функция, используемая для вычисления новой позиции повернутой точки: rotatePoint (p, c, rot)
Обратите внимание, что в SVG я устранил бесполезные преобразования.
let theG = document.querySelector("#theG");
//координаты центра круга
let center = { x: 700, y: -40 };
//вращение в радианах
let rot = .6;
//функция для расчета новой позиции повернутой точки
function rotatePoint(p, c, rot) {
// p: точка
// c: центр вращеня
// rot: вращение
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
};
}
//все группы с классом .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>
Свободный перевод ответа Rotating a SVG circle with group element от участника @enxaneta.
Мне было интересно, можно ли сделать это без JavaScript. В следующей демонстрации я использую JavaScript только для того, чтобы изменить значение поворота.
Поскольку я использую svg-преобразования, углы в градусах, а не в радианах.
Основная идея заключается в следующем: я создаю вложенный элемент SVG. Пока я поворачиваю theG в одном направлении, мне нужно повернуть линию и текст на одинаковое количество градусов в противоположном направлении. Проблема в том, что при вращении theG точки меняют положение, и мне нужно знать это положение, чтобы использовать его в качестве отправной точки для строки и текста.
Решение состоит в том, чтобы поместить всё в вложенный 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>
Свободный перевод ответа Rotating a SVG circle with group element от участника @enxaneta.

