I am developing a ReactJs app, I need to animate a bus in a visual path.
The bus should make stops. So the bus first go from A -> B , then when the user click a button it goes from B -> C , ect..
I have already made the animations and the logic
.bus_0 {
animation: move 3s linear forwards;
}
.bus_1 {
animation: move2nd 3s linear forwards;
}
#keyframes move {
20% {
transform: translate(50px, 0px);
}
40% {
transform: translate(50px, 0px) rotate(-90deg);
}
80% {
transform: translate(50px, -130px) rotate(-90deg);
}
100% {
transform: translate(50px, -125px) rotate(0deg);
}
}
#keyframes move2nd {
20% {
transform: translate(100px, 0px);
}
40% {
transform: translate(100px, 0px) rotate(-90deg);
}
100% {
transform: translate(100px, -50px) rotate(-90deg);
}
}
Here I add classNames based on an index
let bus = document.getElementById('bus');
bus && bus.classList.add(`bus_${data.selectedIndex}`);
The problem is when the first animation starts, the bus reachs point B , but for the second animation , it starts from point A.
Example the bus first position (0, 0), after the first animation (100, 100), when the second animation plays it start from (0, 0) but i need it the start from the last position reached.
There must be a better way probably but that is what i got and i think it will solve your problem
So i collect boxes x and y coordinates when animation button clicks and after the animationend event, i collect both x and y coordinates again and calculate difference of them and add to box style.
const firstButton = document.querySelectorAll('button')[0];
const secondButton = document.querySelectorAll('button')[1];
const myBox = document.querySelector('div')
let rectBefore;
let rectAfter;
let positionBeforeX;
let positionBeforeY;
let positionAfterX;
let positionAfterY;
let differenceX;
let differenceY;
firstButton.addEventListener('click', () => {
rectBefore = myBox.getBoundingClientRect();
positionBeforeX = rectBefore.left;
positionBeforeY = rectBefore.top;
myBox.classList.toggle('first');
})
secondButton.addEventListener('click', () => {
rectBefore = myBox.getBoundingClientRect();
positionBeforeX = rectBefore.left;
positionBeforeY = rectBefore.top;
myBox.classList.toggle('second');
})
myBox.addEventListener('animationend', (event) =>{
rectAfter = myBox.getBoundingClientRect();
positionAfterX = rectAfter.left;
positionAfterY = rectAfter.top;
differenceX = positionAfterX - positionBeforeX;
differenceY = positionAfterY - positionBeforeY;
if(myBox.style.left !== ""){
myBox.style.left = `${parseInt(myBox.style.left.split('px')) + differenceX}px`;
myBox.style.top = `${parseInt(myBox.style.top.split('px')) + differenceY}px`;
}
else{
myBox.style.left = `${differenceX}px`;
myBox.style.top = `${differenceY}px`;
}
myBox.classList.remove(`${event.animationName}`);
})
*,
*::before,
*::after {
box-sizing: border-box;
}
body{
min-height: 100vh;
position: relative;
display: grid;
place-content: center;
}
button{
position: absolute;
background-color: greenyellow;
width: 5rem;
height: 5rem;
}
button:nth-of-type(1){
top:5rem;
right: 10rem;
margin-right: 1rem;
}
button:nth-of-type(2){
top:5rem;
right: 5rem;
}
.box{
position:relative;
width: 100px;
height: 100px;
background-color: blue;
}
.first {
animation: first 3.0s linear forwards;
}
.second {
animation: second 3.0s linear forwards;
}
#keyframes first {
20% {
transform: translate(50px, 0px);
}
40% {
transform: translate(50px, 0px) rotate(-90deg);
}
80% {
transform: translate(50px, -130px) rotate(-90deg);
}
100% {
transform: translate(50px, -125px) rotate(0deg);
}
}
#keyframes second {
20% {
transform: translate(100px, 0px);
}
40% {
transform: translate(100px, 0px) rotate(-90deg);
}
100% {
transform: translate(100px, -50px) rotate(-90deg);
}
}
<div class="box"></div>
<button>First Animation</button>
<button>Second Animation</button>
Related
I want my drawer to animate on the way in, and on the way out and when the animation ends, to turn to display: none but when the drawer is closed, it disappears and doesn't animate out.
const Drawer = ({ closeDrawer, isDrawerOpen }) => {
const [isAnimating, setIsAnimating] = useState()
let drawerClassName
if (isDrawerOpen) {
drawerClassName = "drawer-in"
} else if (!isDrawerOpen && isAnimating) {
drawerClassName = "drawer-animating"
} else if (!isDrawerOpen && !isAnimating) {
drawerClassName = "drawer-out"
}
return (
<>
<div
className={`drawer ${drawerClassName}`}
onAnimationStart={() => setIsAnimating(true)}
onAnimationEnd={() => setIsAnimating(false)}
></div>
<div onClick={closeDrawer}></div>
</>
)
}
CSS:
.drawer {
height: 100%;
width: 60%;
background-color: #fff;
position: absolute;
right: 0;
top: 0;
opacity: 1;
z-index: 3;
transform: translateX(100%);
}
.drawer-in {
animation: 0.7s drawerIn;
transform: translateX(0);
display: block;
}
.drawer-animating {
animation: 0.7s drawerOut;
display: block;
}
.drawer-out {
animation: 0.7s drawerOut;
display: none;
}
#keyframes drawerIn {
0% {
transform: translateX(100%);
}
1% {
transform: translateX(100%);
}
100% {
transform: translateX(0);
}
}
#keyframes drawerOut {
0% {
transform: translateX(0);
}
99% {
transform: translateX(100%);
}
100% {
transform: translateX(100%);
}
}
it's because when you set the drawer-out class to the element display: none; is activated immediately and you don't see the animation.
One solution is to run a setTimeout function within your JavaScript to wait for the animation to finish, then change the elements display property to none. This will allow your 'closing animation' to complete before removing the element. See my snippet below for working example.
Basically what's happening in my example snippet is I'm triggering the closing animation by adding a class associated with the animation. Then I'm setting a time out function that waits for the animation to complete (set time out in milliseconds to match your animation time within your CSS). Once the timeout is complete, the animation class is removed and the element's data attribute is set to closed which will trigger the display none. Hope this helps.
const menu = document.querySelector('.menu');
const menuToggle = document.querySelector('.menu_toggle');
menuToggle.checked=false
menuToggle.addEventListener('change',(e)=>{
menuToggle.disabled=true
let menuState = menu.dataset.menuState
if(menuState==='closed'){
menu.dataset.menuState='opened'
setTimeout(() => {
menuToggle.disabled=false
}, 500);
}else{
menu.classList.add('animate_close')
setTimeout(() => {
menu.classList.remove('animate_close')
menu.dataset.menuState='closed'
menuToggle.disabled=false
}, 500);
}
})
body {
background-color: rgb(235, 235, 235);
}
.menu {
background-color: black;
color: white;
width: fit-content;
}
.menu {
transition: all .5s ease-in-out;
}
.menu[data-menu-state="closed"] {
background-color: red;
display: none;
}
.menu[data-menu-state="opened"] {
animation: openMenu .5s ease-in-out;
transform: translateX(100%);
background-color: green;
}
.menu.animate_close{
background-color: rgb(0, 30, 128);
animation: closeMenu .5s ease-in-out;
opacity: 0;
}
#keyframes openMenu {
0% {
transform: translateX(0);
}
100% {
transform: translateX(100%);
}
}
#keyframes closeMenu {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(0);
}
}
<body>
<label for="menu_toggle">Menu Toggle</label>
<input id="menu_toggle" type="checkbox" class="menu_toggle">
<div class="menu_container">
<div class="menu" data-menu-state="closed">
<ul>
<li>Item1</li>
<li>Item2</li>
<li>Item3</li>
</ul>
</div>
</div>
<script src="main.js"></script>
</body>
Given :
function App() {
return (
<div className="container">
<span>
</span>
</div>
);
}
ReactDOM.render(<App />, document.querySelector("#app"));
.container {
background-color: black;
width: 100vw;
height:100px;
display: flex;
position: relative;
}
.container::before {
background: url('https://s9.gifyu.com/images/chain.gif');
background-size:cover;
content: '';
width: 100px;
height:100px;
right:35px;
bottom:-10px;
position:absolute;
z-index: 999 !important;
}
.container::after {
background: url('https://s9.gifyu.com/images/chain.gif');
background-size:cover;
content: '';
width: 100px;
height:100px;
right:80px;
bottom:-15px;
position:absolute;
rotate: -10deg;
z-index: 999 !important;
}
.container > span:before {
content: '';
background-color: rgb(231, 231, 231);
width: 75px;
height:40px;
right:80px;
bottom:-55px;
rotate: -7deg;
border: 3px solid rgb(126, 126, 126);
border-radius: 10px 10px 10px 10px;
position:absolute;
z-index: 999 !important;
/* transform: rotate(1deg) translate(279px, 28px);
animation: T-animation 3s linear infinite alternate-reverse; */
animation: animationFrames linear 6.25s;
animation-iteration-count: infinite;
transform-origin: 100% 0%;
animation-fill-mode:forwards; /*when the spec is finished*/
-webkit-animation: animationFrames linear 6.25s;
-webkit-animation-iteration-count: infinite;
-webkit-transform-origin: 100% 0%;
-webkit-animation-fill-mode:forwards; /*Chrome 16+, Safari 4+*/
}
#keyframes animationFrames{
0% {
transform: translate(35px,-2px) rotate(-3deg) ;
}
20% {
transform: translate(-14px,-8px) rotate(-3deg) ;
}
29% {
transform: translate(-14px,-8px) rotate(-3deg) ;
}
51% {
transform: translate(35px,-2px) rotate(-3deg) ;
}
72% {
transform: translate(65px,-1px) rotate(7deg) ;
}
79% {
transform: translate(65px,-1px) rotate(7deg) ;
}
100% {
transform: translate(35px,-2px) rotate(-3deg) ;
}
}
#-webkit-keyframes animationFrames {
0% {
-webkit-transform: translate(35px,-2px) rotate(-3deg) ;
}
20% {
-webkit-transform: translate(-14px,-8px) rotate(-3deg) ;
}
29% {
-webkit-transform: translate(-14px,-8px) rotate(-3deg) ;
}
51% {
-webkit-transform: translate(35px,-2px) rotate(-3deg) ;
}
72% {
-webkit-transform: translate(65px,-1px) rotate(7deg) ;
}
79% {
-webkit-transform: translate(65px,-1px) rotate(7deg) ;
}
100% {
-webkit-transform: translate(35px,-2px) rotate(-3deg) ;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>
with JSFiddle link here,
I want to find a way to run the background gifs and the animations at the same time upon refresh or something similar. Currently, if you click run code snippet they are probably synchronized, but if the page is refreshed the gifs keep playing in the background whilst the animation is reloaded.
For instance if the run code snippet is clicked multiple times, the gif just keeps playing continuously while the animation restarts.
It is tedious for me to design this animation if every time I restart my program the gif and the animation are unsynchronized.
Things I have tried
I have tried changing <div className="container" /> to <div />, refresh, then change back, but that doesn't seem to fix it. I have also tried to change my App.js to
const [loaded,setState] = React.useState("container");
const reloadGif = () => {
React.setState({loaded: ''})
setTimeout(() => {
React.setState({loaded: "container"})
}, 0)
}
return (
<div className={loaded}>
<button onClick={reloadGif}>Reset</button>
<span>
</span>
</div>
);
}
ReactDOM.render(, document.querySelector("#app"));
but clicking on the replay button doesn't reset the gif and animation at all.
Does anyone know how I can solve this problem ?
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I have a picture that I want to rotate from 0 to 90 stop 2s then continue from 90 to 180 then stop 2s to the 360 degrees any ideas thanks.
You can do that with CSS animations:
div {
width: 80px;
height: 80px;
background: linear-gradient(#e66465, #9198e5);;
animation: rotate-stop 10s infinite linear;
transform: rotate();
}
#keyframes rotate-stop{
0%{
transform: rotate(0deg);
}
5%, 25%{
transform: rotate(90deg);
}
30%, 50%{
transform: rotate(180deg);
}
55%, 75%{
transform: rotate(270deg);
}
80%, 100%{
transform: rotate(360deg);
}
}
<div></div>
You could use setTimeout and setInterval appropriately:
const rotate = (image, degrees) => {
image.style.transform = `rotate(${+degrees}deg)`;
}
const img = document.getElementById('js-logo');
const oneLoop = () => {
setTimeout(() => rotate(img, 90), 2000);
setTimeout(() => rotate(img, 180), 4000);
setTimeout(() => rotate(img, 360), 6000);
}
oneLoop();
setInterval(() => oneLoop(), 6000);
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/JavaScript-logo.png/240px-JavaScript-logo.png" alt="JS Logo" width="120" height="120" id="js-logo">
An example for javascript.
window.onload = function() {
var box = document.querySelector('.box');
setInterval(function() {
box.classList.toggle('rotate');
}, 2000);
}
.box {
width: 200px;
height: 200px;
background-color: green;
}
.rotate {
animation: rotate 1s;
}
#keyframes rotate {
from {
transform: rotate(0);
}
to {
transform: rotate(90deg);
}
}
<div class="box"></div>
Here is pure css example using animation keyframes.
If you calculate the time for each rotation animation, and each pause time, you can use css animate keyframe percentages to perform a sequence of desired css.
Here is an example below, see comments in css...
/* any kind of html elem, img, div etc */
DIV {
background: magenta;
color: white;
position: absolute;
top: 50%;
left: 50%;
padding: .5rem .75rem;
transform: translate(-50%);
transform-origin: center;
/* 4 rotations */
/* 4 2sec pauses */
/* 8 keyframes total */
/* 2sec rotation time example */
/* 8*2sec is 16s for complete sequence */
animation: rotate-pause 16s infinite;
}
/* rotate and pause key frames */
#keyframes rotate-pause {
/* 0 seconds */
0% {
transform: translate(-50%) rotate(0deg);
}
/* 2 seconds */
12.5% {
transform: translate(-50%) rotate(90deg);
}
/* 4 seconds */
25% {
transform: translate(-50%) rotate(90deg);
}
/* 6 seconds */
37.5% {
transform: translate(-50%) rotate(180deg);
}
/* 8 seconds */
50% {
transform: translate(-50%) rotate(180deg);
}
/* 10 seconds */
62.5% {
transform: translate(-50%) rotate(270deg);
}
/* 12 seconds */
75% {
transform: translate(-50%) rotate(270deg);
}
/* 14 seconds */
87.5% {
transform: translate(-50%) rotate(360deg);
}
/* 16 seconds */
100% {
transform: translate(-50%) rotate(360deg);
}
/* reloop if animate set to infinite */
}
/* demo reset css */
HTML {
width: 100%;
height: 100%;
min-height: 100%;
}
BODY {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
min-height: 100%;
overflow: hidden;
position: relative;
}
<div>Any kind of html elem: img, div...</div>
I have a basic fixed animation on an element that runs when the user click on "space" :
&.pop {
animation: pop 1s ease-in 20ms 1 normal both;
}
#keyframes pop {
0% {
transform: rotate(0deg);
transform-origin: 30px;
}
20% {
transform: rotate(-30deg);
transform-origin: 30px;
}
40% {
transform: rotate(-10deg) translate(-2px, -20px);
transform-origin: 30px;
}
60% {
transform: rotate(0deg) translate(0, -40px);
transform-origin: 30px;
}
80% {
transform: rotate(3deg) translate(2px, -20px);
transform-origin: 30px;
}
100% {
transform:translate(0,0);
transform-origin: 30px;
}
}
Now, i want to add different other transform animations onkeydown that will run simultaneously with the current animation, for example :
&.spin {
animation: spin 500ms ease-out 20ms 1 forwards;
}
#keyframes spin {
0% {
transform: rotateY(0);
}
100% {
transform: rotateY(180deg);
}
}
So my problam is that when i am adding the second "spin" class, it runs over my first "pop" animation.
what will be the way to add it instead of running over ?
if i understood your question correctly:
you can use multiple animations within the transform :
just like this :
transform: rotate(90deg) translate(150px, -230px);
or you can use another approach:
you can wrap your target element with two outer divs and assign an animation for every div..
just like this
<div class="apply_this_animation">
<div class="apply_this_animation_also">
<img src="https://via.placeholder.com/300x300" alt="#" />
</div>
</div>
and use this in you CSS just like this:
<style>
.apply_this_animation {
transform: rotate(90deg);
}
.apply_this_animation_also {
transform: translate(150px, -230px);
}
</style>
Read More
I'm attempting to create a circular navigation with n elements navigable by clicking the keyboard's right and left arrows. I use classes with specific CSS3 rotate and translate values and a little bit of javascript in order to change the classes to do so.
My problem is that the transition between elements with classes four and five, the one that translates between 360deg and 30deg, which goes in the opposite direction than I want it to. You can see the obvious unwanted behavior here in this jsFiddle
.one { transform: rotate(270deg) translate(200px); }
.two { transform: rotate(300deg) translate(200px); }
.three { transform: rotate(330deg) translate(200px); }
.four { transform: rotate(360deg) translate(200px); }<-- Problematic transition
.five { transform: rotate(30deg) translate(200px); }<-- Problematic transition
.six { transform: rotate(60deg) translate(200px); }
.seven { transform: rotate(90deg) translate(200px); }
.eight { transform: rotate(120deg) translate(200px); }
.nine { transform: rotate(150deg) translate(200px); }
.ten { transform: rotate(180deg) translate(200px); }
.eleven { transform: rotate(210deg) translate(200px); }
.twelve { transform: rotate(240deg) translate(200px); }
I would prefer a CSS fix for this, but I also attempted a javascript one which can be found here. I only attempted using the left arrow in this example. My approach with javascript is to obtain the current translated value in string form, strip the rotate degree from it, and add or subtract 30 degrees from it depending on whether or not the right or left arrow is pressed. The current problem with this approach is that it does not give me a value for element.style.webkitTransform (I'm using the Chrome), it's just empty for some reason. Also I'd prefer not to have to prefix everything in the javascript, thus the reason why I would like a CSS only fix
My attempt at the javascript (untested because the first line won't work for some reason):
var thisTransform = circleArray[i].style.webkitTransform;
if (thisTransform.indexOf("rotate(") >= 0) {
var newDeg = parseInt(thisTransform.split("rotate(")[1].substring(thisTransform.indexOf("deg"))) - 30;
circleArray[i].style.webkitTransform = "rotate(" + newDeg + "deg) translate(200px) !important;";
}
Side note: I use prefixfree.min.js in my project to prevent form having to manually input all of the browser prefixes
Is there a CSS only fix for my problem that I am unaware of? What is causing the error when attempting to obtain the translate value using javascript?
First of all, let me say that I think that probably the best solution would be just rotate the base circle; I am almost sure that the results would be better and easier.
But this is just an by side idea, let's go to the problem that you post.
I have done a workaroud to your problem creating a class that will move correctly the problematic classes. My idea is to provide an animation that does the movement ok:
.foura { -webkit-transform: rotate(360deg) translate(200px);
-webkit-animation: aclock .3s linear 1;
transform: rotate(360deg) translate(200px);
animation: aclock .3s linear 1;
transition: none;
}
#keyframes aclock {
0% {transform: rotate(30deg) translate(200px);}
100% {transform: rotate(0deg) translate(200px);}
}
The idea is that the movement from 30 deg to 360 deg, being done thru an animation, can be changed to go from 30 deg to 0 deg.
I provide another similar class for class five.
The remaining problem is that the script must set the element to class four or foura depending on the rotation sense, and the same for five and fivea.
This lead to that (somewhat messy) script:
document.onkeydown = function (e) {
e = e || window.event;
switch(e.which || e.keyCode) {
case 37:
for (var i = 0, j = circleArray.length; i < j; i++) {
var curClassList = circleArray[i].classList,
curClass = curClassList.toString().split(' ')[1];
baseClass = curClass;
if (baseClass == "fivea") {
baseClass = "five";
}
if (baseClass == "foura") {
baseClass = "four";
}
if(circleClassArray.indexOf(baseClass) - 1 >= 0)
{
var newClass = circleClassArray[circleClassArray.indexOf(baseClass) - 1];
if (newClass == "four") {
newClass = "foura";
}
curClassList.add(newClass)
curClassList.remove(curClass);
} else {
curClassList.add(circleClassArray[j - 1]);
curClassList.remove(curClass);
}
}
break;
case 39:
for (var i = 0, j = circleArray.length; i < j; i++) {
var curClassList = circleArray[i].classList,
curClass = curClassList.toString().split(' ')[1];
baseClass = curClass;
if (baseClass == "fivea") {
baseClass = "five";
}
if (baseClass == "foura") {
baseClass = "four";
}
if(circleClassArray.indexOf(baseClass) + 1 < j)
{
var newClass = circleClassArray[circleClassArray.indexOf(baseClass) + 1];
if (newClass == "five") {
newClass = "fivea";
}
curClassList.add(newClass)
curClassList.remove(curClass);
} else {
curClassList.add(circleClassArray[0]);
curClassList.remove(curClass);
}
}
break;
}
}
And this is the full CSS:
.circle-big {
position: relative;
height:500px;
width:500px;
background:red;
border-radius: 50% 50%;
margin: 10% 10%;
border:5px solid black;
}
.circle-inner {
border-radius: 50%;
width: 300px;
height: 300px;
border: 5px solid white;
background-color: black;
display: block;
position: absolute;
overflow: hidden;
top: 50%;
left: 50%;
margin-top:-155px;
margin-left:-155px;
}
.circle {
border-radius: 50%;
width: 70px;
height: 70px;
background-color: white;
display: block;
position: absolute;
overflow: hidden;
top: 50%;
left: 50%;
margin-top:-35px;
margin-left:-35px;
transition: all .3s linear;
}
.one { -webkit-transform: rotate(270deg) translate(200px);
transform: rotate(270deg) translate(200px);
background:blue; }
.two { -webkit-transform: rotate(300deg) translate(200px);
transform: rotate(300deg) translate(200px); }
.three { -webkit-transform: rotate(330deg) translate(200px);
transform: rotate(330deg) translate(200px);
}
.four { -webkit-transform: rotate(360deg) translate(200px);
transform: rotate(360deg) translate(200px);}
.foura { -webkit-transform: rotate(360deg) translate(200px);
-webkit-animation: aclock .3s linear 1;
transform: rotate(360deg) translate(200px);
animation: aclock .3s linear 1;
transition: none;
}
.five { -webkit-transform: rotate(30deg) translate(200px);
transform: rotate(30deg) translate(200px);}
.fivea { -webkit-transform: rotate(30deg) translate(200px);
-webkit-animation: clock .3s linear 1;
transform: rotate(30deg) translate(200px);
animation: clock .3s linear 1;
transition: none;
}
.six { -webkit-transform: rotate(60deg) translate(200px);
transform: rotate(60deg) translate(200px);}
.seven { -webkit-transform: rotate(90deg) translate(200px);
transform: rotate(90deg) translate(200px);}
.eight { -webkit-transform: rotate(120deg) translate(200px);
transform: rotate(120deg) translate(200px);}
.nine { -webkit-transform: rotate(150deg) translate(200px);
transform: rotate(150deg) translate(200px); }
.ten { -webkit-transform: rotate(180deg) translate(200px);
transform: rotate(180deg) translate(200px);}
.eleven { -webkit-transform: rotate(210deg) translate(200px);
transform: rotate(210deg) translate(200px);}
.twelve { -webkit-transform: rotate(240deg) translate(200px);
transform: rotate(240deg) translate(200px);}
#-webkit-keyframes clock {
0% {-webkit-transform: rotate(0deg) translate(200px);}
100% {-webkit-transform: rotate(30deg) translate(200px);}
}
#-webkit-keyframes aclock {
0% {-webkit-transform: rotate(30deg) translate(200px);}
100% {-webkit-transform: rotate(0deg) translate(200px);}
}
#keyframes clock {
0% {transform: rotate(0deg) translate(200px);}
100% {transform: rotate(30deg) translate(200px);}
}
#keyframes aclock {
0% {transform: rotate(30deg) translate(200px);}
100% {transform: rotate(0deg) translate(200px);}
}
updated fiddle
Following my first idea, I have added the following code to the script:
case 38:
angle = angle + 30;
var circleBig = document.getElementsByClassName("circle-big")[0];
var style = "rotate(" + angle + "deg)";
circleBig.style.webkitTransform = style;
break;
case 40:
angle = angle - 30;
var circleBig = document.getElementsByClassName("circle-big")[0];
var style = "rotate(" + angle + "deg)";
circleBig.style.webkitTransform = style;
break;
And added also transition to the big circle. Now I think it works ok (on up and down arrow !)
second version
Brand new version
For the new requirement (to keep the inner circles upright) I have redesigned most of the fiddle. I have adapted an idea that I saw from Lea Verou, to make the rotation without auxiliar divs. It consists in setting the transform to angle + translation + oposite angle. That makes the div go where you want, unrotated.
Once decided to go this way, the script has to modified the styles of the inner circles, and not the style of the base circle. To do that easily, I have stored in every element the angle of that particular element (in a data- property).
Brand New demo
The resulting HTML is similiar:
<div class="circle-big">
<div class="circle one" data-angle=270>1</div>
<div class="circle two" data-angle=300>2</div>
<div class="circle three" data-angle=330>3</div>
<div class="circle four" data-angle=0>4</div>
<div class="circle five" data-angle=30>5</div>
<div class="circle six" data-angle=60>6</div>
<div class="circle seven" data-angle=90>7</div>
<div class="circle eight" data-angle=120>8</div>
<div class="circle nine" data-angle=150>9</div>
<div class="circle ten" data-angle=180>10</div>
<div class="circle eleven" data-angle=210>11</div>
<div class="circle twelve" data-angle=240>12</div>
<div class="circle-inner"></div>
</div>
And the script is
var circleArray = document.getElementsByClassName("circle");
var angle = 0;
window.onload = chargearray;
function chargearray () {
for (var i = 0, j = circleArray.length; i < j; i++) {
var circle = circleArray[i];
var circleAngle = parseInt (circle.dataset.angle);
var totalAngle = angle + circleAngle
var style = "rotate(" + totalAngle + "deg) translate(200px)";
totalAngle = - totalAngle;
style = style + " rotate(" + totalAngle + "deg)"
circle.style.webkitTransform = style;
circle.style.Transform = style;
}
}
document.onkeydown = function (e) {
e = e || window.event;
switch(e.which || e.keyCode) {
case 37:
angle = angle + 30;
chargearray ();
break;
case 39:
angle = angle - 30;
chargearray ();
break;
}
}