Why doesn't the following element rotate? - javascript

I have the following code that aims to rotate a hamburger icon by 90 deg when it is clicked, but it doesn't work why?
var menu = document.getElementById("menu");
let rotate = function() {
document.getElementById("menu").style.transform = "rotate(90deg)";
};
menu.addEventListener("click", rotate);
#menu {
text-decoration: none;
color: white;
font-size: 5vw;
color: #66fcf1;
cursor: default;
position: fixed;
margin-left: 2.5%;
}
☰
Also on Codepen: https://codepen.io/greatscams/pen/ZEQrYog
Note: It only works once.

You need to check if the element is already rotated or not. It does not happen like just rotating the paper. rotate(90deg) means you are assigning the property and not actually rotating the element.
var rotated = false;
let rotate = function () {
if(rotated) {
document.getElementById("menu").style.transform = "rotate(0deg)";
rotated = false;
} else {
document.getElementById("menu").style.transform = "rotate(90deg)";
rotated = true;
}
};

It's only rotating once as it's being rotated by 90deg, not an additional 90deg each time.
To keep rotating each time the function runs you need something along the lines of this:
let deg = 0
let rotate = function () {
deg = deg + 90;
document.getElementById("menu").style.transform = `rotate(${deg}deg)`
};
So the first invocation will be rotate(90deg) the next rotate(180deg) etc

The demo works only once because you're applying the same transform function over and over again.
The first state of the element is transform: none.
When first clicking on it, you're switching it to transform: rotate(90deg).
The transform works relatively to the initial state, not the current one (it's actually stateless), so the code above will not rotate it again and again.
What you can do, depending on what you want, is:
remember the state and toggle the animation (from rotate(0) to rotate(90deg) and back)
or
count the number of rotations and then multiply 90deg by that number on every click.

It only works once because the second time, you're just telling it to transform the way it's already transformed (rotated 90deg). To rotate it further, you have to tell it to rotate further. It's not additive.
For instance, extracting the angle with a regex and adding 90 to it each time, with wrap-around at 360:
let rotate = function() {
const menuStyle = document.getElementById("menu").style;
const current = /rotate\((\d+)deg\)/.exec(menuStyle.transform);
let angle = current ? +current[1] : 0;
angle = angle + 90 % 360;
menuStyle.transform = `rotate(${angle}deg)`;
};
menu.addEventListener("click", rotate);
#menu {
text-decoration: none;
color: white;
font-size: 5vw;
color: #66fcf1;
cursor: default;
position: fixed;
margin-left: 2.5%;
}
☰

Related

How to animate spining wheel in CSS?

I don't know how to form the question. I have old animation that was done in Flash, that I'm not able to translate to CSS animation.
This is an animation of a Spinning Wheel.
The question is: How can I implement the CSS animation for the crank/handle that drives the wheel? It should work like a Piston but connected to a circe in id="rotator" (inside SVG). The handle is located at 0,0 on the image above. Both small circles should match when the rotator is rotating. I already tried to use translate, and used transform-origin but I have no idea how to implement the animation. I have Action Script code as a reference, but I don't know how to map it to CSS or SCSS.
I was able to convert SWF into SVG, using pyswf. And I have a hard time understanding the math behind the logic I've created long ago and translating it into CSS (I've also tried with JS approach).
The code in Action Script I've extracted long ago, probably some decompiler from the swf file.
// copyright (c) 2006 Jakub "JCubic" Jankiewicz
var
factor1 = 180.0 / Math.PI, // współczynniki dla zamiany
factor2 = Math.PI / 180.0; // radiany stopinie i odwrotnie
// radiany na katy
function rad2deg(rad){
return rad * factor1;
}
// katy na radiany
function deg2rad(deg){
return deg * factor2;
}
// dlugosc odcinka
function line_length(x1, y1, x2, y2){
return Math.sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
}
// funkcja testowa przenoszaca krzyzyk
function show(x, y){ cross._x = x; cross._y = y; }
// funkcja testowa rysująca linie
function line_(x1, y1, x2, y2, ang){
line._height = Math.sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
line._x = (x2 + x1) / 2;
line._y = (y2 + y1) / 2;
line._rotation = ang;
}
function getSpeed(){
return step;
}
function setSpeed(value){
// inicjacja zmiennych
var Ox = 0,
Oy = 360, // punkt zaczepienia
r = 83.0, // promien odleglosc od rotatora
angle = 0,
step = value,
rad = deg2rad(step), // cosinnus i sinus stopnia
sinA = Math.sin(rad), // jednostkowego
cosA = Math.cos(rad),
sinAlpha;
onEnterFrame = function() {
if (angle == 0) {
napedzacz._x = 0; // poczatek obrotu
napedzacz._y = r;
} else {
Bx = napedzacz._x * cosA + napedzacz._y * sinA;
By = napedzacz._y * cosA - napedzacz._x * sinA;
napedzacz._x = Bx;
napedzacz._y = By;
sinAlpha = (Ox - Bx) / line_length(Bx, By, Ox, Oy);
napedzacz._rotation = - rad2deg(Math.asin(sinAlpha));
kolo._rotation = 180 - angle;
szpulka._rotation = 180 - angle * 2;
rotator._rotation = 180 - angle;
}
angle = (angle+step) % 360;
}
}
It has Polish comments but they don't explain how to modify the code.
Here is my CodePen demo where I've tried to create SVG+CSS animation. I was able to rotate part of the spinning wheel, but don't know how to animate the handle (that is used to drive the wheel).
I've wanted to use SCSS and trigonometry functions (included in Pen) to generate every frame of the animation, but I'm not sure how I should go about it.
I have the original SWF file but I'm not able to play it, since the only SWF player I've found doesn't execute code. And I'm not able to install Gnash on Fedora (even that I've written article how to do that long go, the solution doesn't work anymore). That's why I want to create something modern with SVG.
If you have something to open the SWF file here is the link to the original file:
https://jcubic.pl/kolowrotek.swf
the problem is that constants in the Action Script code use different coordinate systems and different scales, I have no idea how to map that code into JavaScript (I was able to run it, but it has issues, there are two commented-out lines in Pen). I also have no idea why the animation rotate in different direction than CSS, I was not able to reverse it. I would prefer not to use JavaScript since it will hard to match CSS animation with JavaScript, and doing aninmation in JavaScript make some delay when handle is in wrong position.
This is a basic implementation of the movement that you want.
I have set only keyframes at every 90 deg , it will get better as you add values.
I have guessed this values, bout you should calculate them and set the appropiate values in the counter rotation.
#wheel {
width: 300px;
height: 300px;
border-radius: 100%;
border: solid 1px blue;
animation: rotate 15s infinite linear;
}
#dot {
width: 5px;
height: 5px;
border-radius: 100%;
border: solid 1px red;
position: absolute;
top: 2px;
left: 150px;
}
#arm {
width: 500px;
height: 5px;
border: solid 1px green;
position: absolute;
top: 2px;
left: 150px;
transform-origin: 0px 0px;
animation: crotate 15s infinite linear;
}
#keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
#keyframes crotate {
0% {
transform: rotate(15deg);
}
25% {
transform: rotate(-90deg);
}
50% {
transform: rotate(-195deg);
}
75% {
transform: rotate(-270deg);
}
99.99% {
transform: rotate(-345deg);
}
100% {
transform: rotate(15deg);
}
}
<div id="wheel">
<div id="dot"></div>
<div id="arm"></div>
</div>
Note, following answer content may be subject to edits in the near future, and is only intended as a starting point to assist the OP's author.
I believe what ya may need for turning the crank is the transform-origin CSS property.
In regards to rotate() direction, the StackExchange -- How to determine direction of rotation in CSS3 transitions? answers may be of use. TLDR; positive numbers rotate clockwise, and negative numbers rotate anticlockwise, however this may be modified via from configuration.
I'll dig into the source a bit over the next few minutes and attempt a more complete answer.
Updates
You were very close to a solution! From what I spotted the #handle element was missing an animation property/value, and the #keyframes handle_rotate needed defined.
Here's a bit of code that should get ya a little closer to a full solution...
:root {
--time: 5s;
--handle-translate-x: 291.59718px;
--handle-translate-y: 210.10511px;
--handle-rotate-start: 20deg;
--handle-transform-origin-x: 4.742px;
--handle-transform-origin-y: 15.799px;
}
/* ... */
#handle {
animation: handle_rotate var(--time) linear infinite;
transform-origin: var(--handle-transform-origin-x) var(--handle-transform-origin-y);
transform:
translate(var(--handle-translate-x), var(--handle-translate-y))
rotate(var(--handle-rotate-start));
}
/* ... */
#keyframes handle_rotate {
to {
transform:
translate(var(--handle-translate-x), var(--handle-translate-y))
rotate(calc(var(--handle-rotate-start) + 360deg));
}
}
... Though be aware values still need a bit of fiddling with to get all the parts to sync-up with one another. In this case I'd suggest leveraging CSS Custom Properties (variables)

CSS transform: translateX( to the right );

I want to make a particle system for my home page. Blue little circular dots should go from left to right and then reapear in the left so that it makes a loop.
Image of particles
The code below will generate 150 dots that all have different properties as speed color and size and will apear at random positions when loading the page. Either by looping the animation or by adding new dots I want to continue the animation infinitely.
// ========== JAVASCRIPT ==========
function Dot(){
var colors = [
"#313146",
"#36364f",
"#3d3d5c",
"#404066"
];
var speed = Math.floor(Math.random() * 20) + 2;
this.obj = document.createElement("div");
this.obj.classList.add("dot");
this.obj.style.top = (window.innerHeight * Math.random()) + 'px'; // random Y-position after page load
this.obj.style.left = (window.innerWidth * Math.random()) + 'px'; // random X-position after page load
this.size = Math.floor(Math.random() * 5) + 4; // random size
this.obj.style.height = this.size + 'px';
this.obj.style.width = this.size + 'px';
this.obj.style.backgroundColor = colors[Math.floor(Math.random()*colors.length)]; // random color
this.obj.style.animation = `move ${speed}s linear`; // start animation
document.body.appendChild(this.obj);
setTimeout(del, speed*1000, this.obj); // THIS FUNCTION SHOULD BE REMOVED IF ANIMATION GETS A LOOP
function del(element) {
element.parentNode.removeChild(element);
};
};
for(var i = 0 ; i < 151 ; i++ ){ // creating 150 dots
new Dot();
};
// ========== CSS ==========
.dot {
border-radius: 50%;
z-index: -1;
}
#keyframes move {
0% {
transform: translateX(0vw);
}
100% {
transform: translateX(100vw);
}
}
My problem is that as the dots apear with random positions, and all of them get a transform: translateX(100vw);, they will move out of the screen for a while before being deleted or reapeared at the beginning. My second image shows in red where the dot is moving to, and where it should move to.
image
What I tried allready:
1.
JS:
this.obj.style.animation = `move ${speed}s linear infinite`; added infinite and deleted the code that deletes the dots.
CSS:
#keyframes move {
0% {
transform: translateX(0vw);
}
100% {
transform: translateX(right);
}
}
<= Does not exist, and couldn't find working code equal to this idea.
This would have been a solution.
2.
Adding a second animation with dots coming from the left when other ones where deleted.
Ended in a gap between the 150 dots of the first animation and the incoming dots of the second animation.
Is there any other possibility of moving the dots from left to right with different properties?
best regards
Since you are setting the position with JS so you can know exactly where each element will appear and use this information to adjust the animation.
Here is a basic example to illustrate:
.dot {
background: blue;
position:fixed;
width: 50px;
height: 50px;
border-radius: 50%;
z-index: -1;
left:var(--x,0px);
animation:move 2s linear infinite;
}
#keyframes move {
0% {
transform: translateX(0vw);
}
100% {
transform: translateX(calc(100vw - var(--x,0px)));
}
}
<div class="dot" style="top:10px;--x:80px;"></div>
<div class="dot" style="top:20px;--x:150px;"></div>
<div class="dot" style="top:100px;--x:350px;"></div>
The variable --x will define left and will get substracted from the 100vw
For better support and since you are using JS, you can get rid of calc() and CSS variables. Simply do a small calculation to find the value of transform.
Here is an example where I am using jQuery for simplicity but you can easily make it a JS-only code:
$('.dot').each(function() {
$(this).css('transform','translateX('+ ($(window).width() - parseInt($(this).css('left')))+'px)');
});
.dot {
background: blue;
position:fixed;
width: 50px;
height: 50px;
border-radius: 50%;
z-index: -1;
animation:move 2s linear infinite;
}
#keyframes move {
0% {
transform: translateX(0px);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="dot" style="top:10px;left:80px;"></div>
<div class="dot" style="top:20px;left:150px;"></div>
<div class="dot" style="top:100px;left:350px;"></div>
Worth to note that you need to update the value on window resize
Another idea to keep the loop effect is to have the same position and the same animation for all and you adjust the delay to simulate the different position:
.dot {
background: blue;
position:fixed;
width: 50px;
height: 50px;
border-radius: 50%;
z-index: -1;
left:0;
animation:move 2s linear infinite;
}
#keyframes move {
0% {
transform: translateX(0px);
}
100% {
transform: translateX(100vw);
}
}
<div class="dot" style="top:10px;animation-delay:-1s;"></div>
<div class="dot" style="top:20px;animation-delay:-0.1s;animation-duration:1s"></div>
<div class="dot" style="top:100px;animation-delay:-0.5s;animation-duration:4s"></div>
The calculation is easy. If the animation duration is D then a delay of -D/2 will place the element in the center intially. -D*0.1 will place the image at 10% and so on.
I would suggest you to use requestAnimationFrame to animate your particles. Take a look at the following example. I've added the move method to the particle which is called from the animation loop and changing the particle's position. It also checks if the particle has reached the end of the screen and resets its position to -10 in this case.
function Dot(){
var colors = [
"yellow",
"red",
"green",
"black"
];
this.x = window.innerWidth * Math.random();
this.speed = Math.floor(Math.random() * 20) + 2;
this.obj = document.createElement("div");
this.obj.classList.add("dot");
this.obj.style.position = "fixed";
this.obj.style.top = (window.innerHeight * Math.random()) + 'px';
this.obj.style.left = this.x + 'px';
this.size = Math.floor(Math.random() * 5) + 4; // random size
this.obj.style.height = this.size + 'px';
this.obj.style.width = this.size + 'px';
this.obj.style.background = colors[Math.floor(Math.random()*colors.length)]; // random color
document.body.appendChild(this.obj);
this.move = function() {
this.x += this.speed;
if (this.x > window.innerWidth) {
this.x = -10;
}
this.obj.style.left = this.x + 'px';
};
};
var dots = Array.apply(null, Array(150)).map(a => new Dot());
requestAnimationFrame(paint);
function paint() {
requestAnimationFrame(paint);
for (dot of dots) {
dot.move();
}
}
.dot {
border-radius: 50%;
z-index: -1;
}
I also recommend you this great book about particle systems. It shows how to implement forces, interaction and complex behavior.

Is there a way to translate/ animate divs/images along a curve path in javascript and css?

I have a list of images , which need to scrolled on left or right arrow key press. But the scrolling needs to along a curve like a parabolic path . Is there a way to do this in javascript and css? If not not what should i use for this?
for your next question, please provide examples of what you have tried, what has failed, what you have researched or found out, etc. In general, please read "How do I ask a good question?" and "How to create a Minimal, Complete, and Verifiable example".
Nonetheless, I wanted to see what I can code in a few minutes before leaving work so here is a little something that might send you along the right way:
const circle = document.querySelector('.circle');
const path = function(x) {
return 0.1 * (x * x); // or any other functon
}
let x = 0;
const updateCircle = function() {
const y = path(x); // get y from x
const speed = 5;
const translateX = speed * x + 'px';
const translatey = speed * y + 'px';
const transform = `transform: translate(${translateX}, -${translatey})`;
circle.setAttribute('style', transform);
}
document.addEventListener('keydown', function(event) {
let move = false; // set move to true if left or right arrow pressed
switch (event.key) {
case "ArrowLeft": // moving left means decreasing x values
x--;
move = true;
break;
case "ArrowRight": // moving right means increasing x values
x++;
move = true;
break;
}
if (move) { // let or right arrow pressed
window.requestAnimationFrame(updateCircle);
}
}, true);
.circle {
background: blue;
width: 50px;
height: 50px;
border-radius: 50%;
position: absolute;
top: calc(100% - 50px);
left: calc(50% - 25px);
transition: transform 170ms linear;
}
body::before {
position: absolute;
top: 1rem;
left: 50%;
transform: translateX(-50%);
display: block;
content: 'click here to focus the snippet';
color: lightgray;
border: 1px solid lightgray;
padding: 1rem;
}
<div class="circle"></div>

Javascript Oscillation

I have this following animation:
<!DOCTYPE HTML>
<html>
<head>
<style>
.example_path {
position: relative;
overflow: hidden;
width: 530px;
height: 30px;
border: 3px solid #000;
}
.example_path .example_block {
position: absolute;
background-color: blue;
width: 30px;
height: 20px;
padding-top: 10px;
text-align: center;
color: #fff;
font-size: 10px;
white-space: nowrap;
}
</style>
<script>
function move(elem) {
var left = 0
function frame() {
left+=10 // update parameters
elem.style.left = left + 'mm' // show frame
if (left == 10000) // check finish condition
clearInterval(id)
}
var id = setInterval(frame, 1) // draw every 1ms
}
</script>
</head>
<body>
<div onclick="move(this.children[0])" class="example_path">
<div class="example_block"></div>
</div>
</body>
</html>
as you see, the blue block moves out of the rectangle if it crosses it. how do i have the blue block oscillate about the rectangular border to and fro keeping the speed constant throughout ...
(in my case the speed is 10 m/s aka 10 mm/ms)
You need to update code as: Here is working JSfiddle
function move(elem) {
var left = 0
var fwdMove = true;
function frame() {
if (left < 0) {
fwdMove = true;
} else if (left > 520) {
fwdMove = false;
}
fwdMove?left += 10:left -= 10
elem.style.left = left + 'px' // show frame
}
var id = setInterval(frame, 1) // draw every 1ms
}
We begin by adding a variable to track the direction that we're heading in. We don't want to modify how fast you're moving, so we use a positive or negative 1 to affect the position.
var direction = 1; // 1=Right, -1=Left
var left = 0
function frame() {
left+=(10 * direction); // update parameters
Because mm are a print-unit, and we're working in the browser, we'll change it to use px. If you really need to use mm, you'll have to find a way of converting between them for the box to stop at the appropriate spot.
elem.style.left = left + 'px' // show frame
Finally, we check whether we've gone past the bounds of the box, and if so, we put it back in the box and reverse the direction;
if (left <= 0) {
direction = 1; // Begin moving to the left
left = 0; // Put the box back in the path
} else if (left >= (530 - 20)) {
direction = -1; // Begin moving to the right
left = (530 - 20); // Put the box back in the path
}
JSFiddle.

How to create circular progress(pie chart) like indicator

I have to show progress graphs exactly in following way where percentage would be in center of circular graph
How can i do this using javascript/jQuery?
Can it be done using Google Chart?
There's a plugin for this at:
http://anthonyterrien.com/knob/
Demo
jQuery Knob
canvas based ; no png or jpg sprites.
touch, mouse and mousewheel, keyboard events implemented.
downward compatible ; overloads an input element...
I searched and know there are at least 5 ways to create Circular progress indicator:
They include:
jquery.polartimer.js
jQuery Knob
CSS3 pie graph timer with jquery
circular progressBar by jQuery andCSS3
ProgressBar.js
I would recommend Highcharts JS for all of your JavaScript graphing needs
Browse through more of the demos; I think you're looking for the Donut Chart :)
You can use CSS sprites (google) for this purpose, if you want to show multiples of 10 (0%, 10%, 20% etc). I guess you need to be a graphics guru to create the sprite..
The sprite is one image containing more than one image. For your purpose, you can create an image, say 16x160px. Imagine that this image is divided into ten 16x16px "slices" and draw the corresponding percentage on that slice. You can then use CSS and JavaScript to show one "frame" from this sprite.
If you are not targeting old browsers, you can easily do that by drawing on a canvas element. This gives you the freedom to do whatever you need with the chart.
That means this solution's only requirement is jQuery and any browser that supports the canvas element...IE9+
Here's a code snippet that demonstrates it...
//input
var dimens = 256;
var color = "rgba(54, 162, 235, 0.9)";
var padding = 12;
var width = 10;
var value = 80;
var maxValue = 100;
var countFontRatio = 0.25; //ratio in relation to the dimens value
$(function() {
$(".chart-total").each(function(idx, element) {
var _render = function() {
var startingPoint = -0.5;
var pointValue = startingPoint;
var currentPoint = startingPoint;
var timer;
var _ctx;
var $canvas = $(element).find("canvas");
var canvas = $canvas.get(0);
pointValue = (value / (maxValue / 20) * 0.1) - 0.5;
canvas.height = dimens;
canvas.width = dimens;
if (!countFontRatio)
$canvas.parent().find(".legend-val").css("font-size", dimens / value.toString().length);
else
$canvas.parent().find(".legend-val").css("font-size", dimens * countFontRatio);
_ctx = canvas.getContext("2d");
var _draw = function() {
_ctx.clearRect(0, 0, dimens, dimens);
_ctx.beginPath();
_ctx.arc(dimens / 2, dimens / 2, (dimens / 2) - padding, startingPoint * Math.PI, 1.5 * Math.PI);
_ctx.strokeStyle = "#ddd";
_ctx.lineWidth = 2;
_ctx.lineCap = "square";
_ctx.stroke();
_ctx.beginPath();
_ctx.arc(dimens / 2, dimens / 2, (dimens / 2) - padding, startingPoint * Math.PI, currentPoint * Math.PI);
_ctx.strokeStyle = color;
_ctx.lineWidth = width;
_ctx.lineCap = "round";
_ctx.stroke();
currentPoint += 0.1;
if (currentPoint > pointValue) {
clearInterval(timer)
}
};
timer = setInterval(_draw, 100);
};
_render();
$(window).resize(function() {
_render();
});
});
})
body {
font-family: 'Open Sans', sans-serif;
color: #757575;
}
.chart-total {
position: relative;
margin: 0 auto;
}
.chart-total-legend {
position: absolute;
top: 50%;
left: 50%;
-ms-transform: translateY(-50%) translateX(-50%);
-o-transform: translateY(-50%) translateX(-50%);
-moz-transform: translateY(-50%) translateX(-50%);
-moz-transform: translateY(-50%) translateX(-50%);
transform: translateY(-50%) translateX(-50%);
}
.legend-val {
font-size: 4em;
display: block;
text-align: center;
font-weight: 300;
font-family: 'Roboto', sans-serif;
}
.legend-desc {
display: block;
margin-top: 5px;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Open+Sans|Roboto:300,400" rel="stylesheet">
<div class="chart-total" style="max-width: 256px;">
<canvas height="256" width="256"></canvas>
<div class="chart-total-legend">
<span class="legend-val" value="3933" style="font-size: 64px;">3,933</span>
<span class="legend-desc">Total Progress</span></div>
</div>
I don't think you can do it with javascript/jquery/css alone. You need to render different images, for each step one and display the proper one.
It could be made with flash (probably there are ready made components) or with svg or html5 canvas element or an api which uses one of the above backends.

Categories

Resources