Reputation: 6399
I have a circle with few clickable points. When I click one of these, I want it to rotate to the right side (zero degree) position. When I click the point on top (90deg), I want the circle to rotate clockwise and when I click the point at the bottom, (270deg), I want it to rotate anti-clockwise. Essentially, take the shortest path to get to right side. The problem is, when I click the bottom point (blue star), the circle takes the longest path to be at the right side. If you play around with it a bit more, you can see that it seems to set a specific direction to each point and no matter where they are, it follows that direction.
How do I control that direction of rotation please? Any pointers towards this is appreciated.
function rotate(angle) {
d3.select('.container')
.attr('transform', `rotate(${angle})`);
}
body {
margin: 0 auto;
text-align: center;
padding: 10px;
}
.container {
transform-origin: 250px 250px;
transition: all 0.5s ease-in;
}
.star {
cursor: pointer;
}
.star--red {
fill: red;
}
.star--green {
fill: green;
}
.star--blue {
fill: lightblue;
}
.star--pink {
fill: salmon;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500" viewbox="0 0 500 500">
<g class="container">
<ellipse id="main-circle" stroke-width="2" ry="145" rx="145" cy="250" cx="250" stroke="#000" fill="#fff"/>
<path id="svg_8" class="star star--red" onclick="rotate(90);"
d="m228.500007,135.025599l16.424656,0l5.075345,-15.603354l5.075348,15.603354l16.424653,0l-13.287801,9.643293l5.075608,15.603354l-13.287807,-9.643555l-13.287804,9.643555l5.075609,-15.603354l-13.287806,-9.643293z"/>
<path id="svg_9" class="star star--green" onclick="rotate(180);"
d="m119.362495,245.178355l16.424656,0l5.075345,-15.603354l5.075347,15.603354l16.424653,0l-13.287801,9.643293l5.075608,15.603354l-13.287807,-9.643556l-13.287805,9.643556l5.07561,-15.603354l-13.287806,-9.643293z"/>
<path id="svg_10" class="star star--blue" onclick="rotate(270);"
d="m228.500007,355.025599l16.424656,0l5.075345,-15.603354l5.075347,15.603354l16.424653,0l-13.287801,9.643293l5.075608,15.603354l-13.287807,-9.643556l-13.287805,9.643556l5.07561,-15.603354l-13.287806,-9.643293z"/>
<path id="svg_11" class="star star--pink" onclick="rotate(0);"
d="m337.362495,245.178355l16.424656,0l5.075345,-15.603354l5.075347,15.603354l16.424653,0l-13.287801,9.643293l5.075608,15.603354l-13.287807,-9.643556l-13.287805,9.643556l5.07561,-15.603354l-13.287806,-9.643293z"/>
</g>
</svg>
Essentially I've copy pasted the codepen code here, but the pen is also available at https://codepen.io/anon/pen/LjMVzM
Upvotes: 2
Views: 1235
Reputation: 13853
You can't just get away with tracking only the required rotation, you also need to keep track of the total rotation. For example, If you keep clicking whatever star is on top the required degrees to keep going becomes, [0, 90, 180, 270, 360, 450, ...]
. Once keeping track of the total rotation, all you need to do is determine the direction to increment as shown below.
var totAngle = 0;
function rotate(angle) {
d3.select('.container')
.attr('transform', () => {
// Clamp the current rotation to 0-360
var minAngle = ((totAngle % 360) + 360) % 360;
// Calculate the required rotation 0/90/180/270
var rot = (angle - minAngle + 360) % 360;
// Determine the direction clockwise/counter-clockwise
totAngle += rot <= 180 ? rot : -90
return `rotate(${totAngle})`;
});
}
body {
margin: 0 auto;
text-align: center;
padding: 10px;
}
.container {
transform-origin: 250px 250px;
transition: all 0.5s ease-in;
}
.star {
cursor: pointer;
}
.star--red {
fill: red;
}
.star--green {
fill: green;
}
.star--blue {
fill: lightblue;
}
.star--pink {
fill: salmon;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500" viewbox="0 0 500 500">
<g class="container">
<ellipse id="main-circle" stroke-width="2" ry="145" rx="145" cy="250" cx="250" stroke="#000" fill="#fff"/>
<path id="svg_8" class="star star--red" onclick="rotate(90);"
d="m228.500007,135.025599l16.424656,0l5.075345,-15.603354l5.075348,15.603354l16.424653,0l-13.287801,9.643293l5.075608,15.603354l-13.287807,-9.643555l-13.287804,9.643555l5.075609,-15.603354l-13.287806,-9.643293z"/>
<path id="svg_9" class="star star--green" onclick="rotate(180);" d="m119.362495,245.178355l16.424656,0l5.075345,-15.603354l5.075347,15.603354l16.424653,0l-13.287801,9.643293l5.075608,15.603354l-13.287807,-9.643556l-13.287805,9.643556l5.07561,-15.603354l-13.287806,-9.643293z"/>
<path id="svg_10" class="star star--blue" onclick="rotate(270);"
d="m228.500007,355.025599l16.424656,0l5.075345,-15.603354l5.075347,15.603354l16.424653,0l-13.287801,9.643293l5.075608,15.603354l-13.287807,-9.643556l-13.287805,9.643556l5.07561,-15.603354l-13.287806,-9.643293z"/>
<path id="svg_11" class="star star--pink" onclick="rotate(0);"
d="m337.362495,245.178355l16.424656,0l5.075345,-15.603354l5.075347,15.603354l16.424653,0l-13.287801,9.643293l5.075608,15.603354l-13.287807,-9.643556l-13.287805,9.643556l5.07561,-15.603354l-13.287806,-9.643293z"/>
</g>
</svg>
Upvotes: 2