How to rotate a pie chart by progressbar plugin counterclockwise? - javascript

I use an open-source plugin in github, here is the link:
https://github.com/yxfanxiao/jQuery-plugin-progressbar
Please see the codes below:
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Progress Bar</title>
<link rel="stylesheet" href="jQuery-plugin-progressbar.css">
<script src="jquery-1.11.3.js"></script>
<script src="jQuery-plugin-progressbar.js"></script>
</head>
<body>
<div class="progress-bar position"></div>
<div class="progress-bar position" data-percent="60" data-duration="1000" data-color="#ccc,yellow"></div>
<div class="progress-bar position" data-percent="20" data-color="#a456b1,#12b321"></div>
<input type="submit" value="加载">
<script>
$(".progress-bar").loading();
$('input').on('click', function () {
$(".progress-bar").loading();
});
</script>
</body>
</html>
JS:
;
(function ($) {
$.fn.loading = function () {
var DEFAULTS = {
backgroundColor: '#b3cef6',
progressColor: '#4b86db',
percent: 75,
duration: 2000
};
$(this).each(function () {
var $target = $(this);
var opts = {
backgroundColor: $target.data('color') ? $target.data('color').split(',')[0] : DEFAULTS.backgroundColor,
progressColor: $target.data('color') ? $target.data('color').split(',')[1] : DEFAULTS.progressColor,
percent: $target.data('percent') ? $target.data('percent') : DEFAULTS.percent,
duration: $target.data('duration') ? $target.data('duration') : DEFAULTS.duration
};
// console.log(opts);
$target.append('<div class="background"></div><div class="rotate"></div><div class="left"></div><div class="right"></div><div class=""><span>' + opts.percent + '%</span></div>');
$target.find('.background').css('background-color', opts.backgroundColor);
$target.find('.left').css('background-color', opts.backgroundColor);
$target.find('.rotate').css('background-color', opts.progressColor);
$target.find('.right').css('background-color', opts.progressColor);
var $rotate = $target.find('.rotate');
setTimeout(function () {
$rotate.css({
'transition': 'transform ' + opts.duration + 'ms linear',
'transform': 'rotate(' + opts.percent * 3.6 + 'deg)'
});
},1);
if (opts.percent > 50) {
var animationRight = 'toggle ' + (opts.duration / opts.percent * 50) + 'ms step-end';
var animationLeft = 'toggle ' + (opts.duration / opts.percent * 50) + 'ms step-start';
$target.find('.right').css({
animation: animationRight,
opacity: 1
});
$target.find('.left').css({
animation: animationLeft,
opacity: 0
});
}
});
}
})(jQuery);
CSS:
.position {
float: left;
margin: 100px 50px;
}
.progress-bar {
position: relative;
height: 100px;
width: 100px;
}
.progress-bar div {
position: absolute;
height: 100px;
width: 100px;
border-radius: 50%;
}
.progress-bar div span {
position: absolute;
font-family: Arial;
font-size: 25px;
line-height: 75px;
height: 75px;
width: 75px;
left: 12.5px;
top: 12.5px;
text-align: center;
border-radius: 50%;
background-color: white;
}
.progress-bar .background {
background-color: #b3cef6;
}
.progress-bar .rotate {
clip: rect(0 50px 100px 0);
background-color: #4b86db;
}
.progress-bar .left {
clip: rect(0 50px 100px 0);
opacity: 1;
background-color: #b3cef6;
}
.progress-bar .right {
clip: rect(0 50px 100px 0);
transform: rotate(180deg);
opacity: 0;
background-color: #4b86db;
}
#keyframes toggle {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
Note that you can download a zip-file from the link provided including those codes. As to be seen, originally the pie charts are rotating clockwise. All I need is to make them rotate counterclockwise. That was looking easy but I could not manage to do it for hours unfortunately. Any help or advise would be so appreciated! Thanks!!
Edit: Please note that the starting point (origin) of the animation should not be changed, should start from the top (north).

You should start by multiplying your rotate value by its minus value; -3.6 instead of 3.6. You'd also have to update the CSS accordingly as otherwise it will start animating from bottom contrary to original version where it starts from top.
You can trick it via swapping left and right components, but that will affect the progress values less than 50%, thus you should add an else statement to handle that as well.
Hence final JS file becomes like below;
JS:
;
(function ($) {
$.fn.loading = function () {
var DEFAULTS = {
backgroundColor: '#f00',
progressColor: '#adadad',
percent: 75,
duration: 2000
};
$(this).each(function () {
var $target = $(this);
var opts = {
backgroundColor: $target.data('color') ? $target.data('color').split(',')[0] : DEFAULTS.backgroundColor,
progressColor: $target.data('color') ? $target.data('color').split(',')[1] : DEFAULTS.progressColor,
percent: $target.data('percent') ? $target.data('percent') : DEFAULTS.percent,
duration: $target.data('duration') ? $target.data('duration') : DEFAULTS.duration
};
$target.append('<div class="background"></div><div class="rotate"></div>'+
'<div class="left"></div>'+
'<div class="right"></div><div class=""><span>' +
+ opts.percent + '%</span></div>');
$target.find('.background').css('background-color', opts.backgroundColor);
$target.find('.left').css('background-color', opts.backgroundColor);
$target.find('.rotate').css('background-color', opts.progressColor);
$target.find('.right').css('background-color', opts.progressColor);
var $rotate = $target.find('.rotate');
setTimeout(function () {
$rotate.css({
'transition': 'transform ' + opts.duration + 'ms linear',
'transform': 'rotateZ(' + -opts.percent * 3.6 + 'deg)'
});
},1);
if (opts.percent > 50) {
var animationRight = 'toggle ' + (opts.duration / opts.percent * 50) + 'ms step-end';
var animationLeft = 'toggle ' + (opts.duration / opts.percent * 50) + 'ms step-start';
$target.find('.left').css({
animation: animationRight,
opacity: 1
});
$target.find('.right').css({
animation: animationLeft,
opacity: 0
});
}
else {
var animationRight = 'toggle ' + (opts.duration / opts.percent * 50) + 'ms step-end';
var animationLeft = 'toggle ' + (opts.duration / opts.percent * 50) + 'ms step-start';
$target.find('.left').css({
animation: animationRight,
opacity: 0
});
$target.find('.right').css({
animation: animationLeft,
opacity: 1
});
}
});
}
})(jQuery);

Related

Javascript carosel animation

I'm trying to make an image carousel with center animation. I don't want to use CSS animations, instead I'd like to use jQuery.
By pressing the 'Prev' button the animation will start. One of the slides which will be central begins to grow. I've used jQuery's animate() to animate width and height. Everything works as required except I can't understand why the animation makes the central slide jump.
I have created this sample. If you push the 'Prev' button the animation will start.
var scroll_speed = 4000;
var items_cnt = $('.mg_item').length;
var container_size = $(".main_cnt").innerWidth();
var item_avg_w = container_size / 5;
var item_center_w = ((item_avg_w / 100) * 20) + item_avg_w;
var item_center_h = (item_center_w / 16) * 9 + 30;
var item_w = ((container_size - item_center_w) / 4) - 2;
var item_h = ((item_w / 16) * 9);
var gallery_content = $('.gallery_body').html();
$('.gallery_body').html(gallery_content + gallery_content + gallery_content);
var items_offset = items_cnt * item_w + 14;
$('.gallery_body').css('left', -items_offset);
$('.mg_item').css("width", item_w);
$('.mg_item').css("height", item_h);
//$('.mg_item').css("margin-bottom", (item_center_h - item_h) / 2);
//$('.mg_item').css("margin-top", (item_center_h - item_h) / 2);
//$('.mg_item_с').css("width", item_center_w);
//$('.mg_item_с').css("height", item_center_h);
//document.documentElement.style.setProperty('--center_width', item_center_w + "px");
//document.documentElement.style.setProperty('--center_height', item_center_h + "px");
$('.main_cnt').css("height", item_center_h);
check_visible();
AssignCenter(0);
function gonext() {
AssignCenter(-1);
ZoomIn();
$('.gallery_body').animate({
left: '+=' + (item_w + 2),
}, scroll_speed, "linear", function() {
LoopSlides();
});
}
function goprev() {
AssignCenter(1);
ZoomIn();
$('.gallery_body').animate({
left: '-=' + (item_w + 2),
}, scroll_speed, "linear", function() {
LoopSlides();
});
}
function ZoomIn() {
$('.center').animate({
width: item_center_w + 'px',
height: item_center_h + 'px',
}, scroll_speed, function() {});
}
function LoopSlides() {
var cur_pos = $('.gallery_body').position().left
var left_margin = Math.abs(items_offset * 2 - item_w) * -1;
var right_margin = 0 - item_w;
if (cur_pos < left_margin) {
$('.gallery_body').css('left', -items_offset);
}
if (cur_pos >= 0) {
$('.gallery_body').css('left', -items_offset);
}
check_visible();
AssignCenter(0);
}
function check_visible() {
$('.mg_item').each(function(i, obj) {
var pos = $(this).offset().left;
if (pos < 0 || pos > container_size) {
$(this).addClass("invisible");
$(this).removeClass("active");
} else {
$(this).addClass("active");
$(this).removeClass("invisible");
}
});
}
function AssignCenter(offset) {
var center_slide = $('.active')[2 + offset];
$('.center').each(function(i, obj) {
$(this).removeClass("center");
});
$(center_slide).addClass("center");
//$(center_slide).css("width", item_center_w);
//$(center_slide).css("height", item_center_h);
}
:root {
--center_width: 0px;
--center_height: 0px;
}
.main_cnt {
background-color: rgb(255, 0, 0);
padding: 0px;
overflow: hidden;
margin: 0px;
}
.gallery_body {
width: 500%;
background-color: rgb(128, 128, 128);
position: relative;
}
.mg_item {
width: 198px;
height: 150px;
background-color: blue;
display: inline-block;
position: relative;
margin: -1px;
padding: 0px;
font-size: 120px;
}
.center {
background-color: brown;
/*width: var(--center_width) !important;
height: var(--center_height) !important;*/
}
.item_c {
width: 410px;
height: 150px;
background-color: blueviolet;
display: inline-block;
position: relative;
margin: -1px;
padding: 0px;
font-size: 120px;
}
.video-js .vjs-dock-text {
text-align: right;
}
<script src="https://code.jquery.com/jquery-2.2.0.min.js" type="text/javascript"></script>
<div class="main_cnt">
<div class="gallery_body">
<div class="mg_item">1</div>
<div class="mg_item">2</div>
<div class="mg_item">3</div>
<div class="mg_item">4</div>
<div class="mg_item">5</div>
<div class="mg_item">6</div>
<div class="mg_item">7</div>
</div>
</div>
<br><br>
<button onclick="gonext()">GONEXT</button>
<button onclick="goprev()">GOPREV</button>
<button onclick="check_visible()">CHEVIS</button>

Issues with ScaleX() on browser Zoom

When zooming in the browser, the scaleX() property is not staying consistent. TranslateX() works exactly as it should which is why I'm reaching out.
I am building out a stepped progress bar with the Web Animations API and Vanilla JS, the intention is that there will be a form inserted into this so as we step through form steps the animation/steps will show progress through it.
The issue I am encountering is when I am testing for ADA compliance, specifically when zooming in on the page. And even more specifically, it's only when the zoom percentage is not a multiple of 100. So 100, 200, 300, and 400% work perfectly. But 110, 125, 250%, just to name a few, are having issues. The dot that slides across the screen is working as it should.
The unexpected behavior is in the bar that expands across the screen along with the dot, sometimes it goes too far sometimes it doesn't go far enough. The thing that is really confusing me is that both the bar and the dot are both being "controlled" by the same measurements, which is taking the parent div's width and dividing by 3 and then multiplying by the current step. This is what leads me to assuming the issue is in the scaleX transform. I am still testing this overall in IE, encountering the issue in chrome and firefox.
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>My stepped progress bar</title>
<link href="style.css" type="text/css" rel="stylesheet" />
<link href="fonts.css" type="text/css" rel="stylesheet" />
<!-- Web Animation API polyfill-->
<script src="https://rawgit.com/web-animations/web-animations-js/master/web-animations.min.js"></script>
</head>
<body>
<section>
<div class="progress__container">
<div class="progress__bar">
<div id="progress__fill" class="step1"></div>
<div class="circ__container">
<div class="circ" id="circ__1"></div>
<div class="circ" id="circ__2"></div>
<div class="circ" id="circ__3"></div>
<div class="circ" id="circ__4"></div>
</div>
<div id="progress__dot" class="prog__1"></div>
</div>
<div class="backBar"></div>
<div class="flexrow">
<span class="stepName tab-1">Account</span>
<span class="stepName tab-2">Frequency</span>
<span class="stepName tab-3">Amount</span>
<span class="stepName tab-4">Taxes</span>
</div>
<div class="button__container">
<button class="buttonStep" id="back">Back</button>
<button class="buttonStep is-active" id="next">Next</button>
</div>
</div>
</section>
<script src="script-api.js"></script>
</body>
</html>
CSS:
/* General Styles */
body {
font-family: Arial, helvetica, sans-serif;
}
/* Slider Bar Animation */
#progress__fill {
height:2px;
position: absolute;
top: 7px;
left: 0;
background-color: darkred;
width: 1px;
}
#progress__dot {
background-color: darkred;
color: #fff;
border-radius: 50%;
height: 8px;
width: 8px;
position: absolute;
text-align:center;
line-height: 8px;
padding: 6px;
top: 0;
font-size: 12px;
}
/* Static Bar Elements */
.progress__container {
width: 600px;
margin: 20px auto;
position: relative;
}
.backBar {
height:2px;
width:96%;
position: absolute;
top: 7px;
left: 2%;
background-color: lightgrey;
}
.progress__bar {
z-index: 100;
position: relative;
width: 96%;
margin: 0 auto;
}
.circ {
background-color: #fff;
border: 2px solid lightgrey;
border-radius: 50%;
height: 8px;
width: 8px;
display: inline-block;
position: absolute;
}
.hide {
visibility: hidden
}
.flexrow {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.circ__container {
padding-top: 3px;
}
.flexrow {
margin-top: 20px;
}
.stepName {
font-size: 12px;
text-align: center;
}
.stepName:first-child {
text-align: left;
}
.stepName:last-child {
text-align: right;
}
.stepName.bold {
font-weight: 600;
}
/* Buttons */
.button__container {
padding-top: 100px;
}
.buttonStep {
background: grey;
color: #fff;
padding: 10px 25px;
border-radius: 10px;
font-size: 16px;
}
#back {
float: left;
}
#next {
float: right;
}
.is-active {
background: darkred;
}
JS:
// give a starting value for the transformation
var slideBarWidth = 0,
slideBarScalePoint = 0,
currentStep = 1,
dot = document.getElementById('progress__dot'),
boxWidth = dot.parentElement.offsetWidth;
// insert the current step number into the progress dot
dot.innerHTML = currentStep;
// place the background dots on the bar
for (var x = 1; x < 5; x++) {
document.getElementById('circ__' + x).setAttribute('style', 'left: ' + ((boxWidth / 3) * (x - 1)) + 'px');
if (x == 4) {
document.getElementById('circ__' + x).setAttribute('style', 'left: ' + (((boxWidth / 3) * (x - 1)) - document.getElementById('circ__' + x).offsetWidth)+ 'px');
}
}
// define the timing for progress dot
var dotTiming = {
duration: 500,
fill: "both",
easing: 'ease-in-out'
}
// define the timing for sliding bar
var barTiming = {
duration: 500,
fill: "both",
easing: 'ease-in-out'
}
var passedTiming = {
fill: "both"
}
// make the first step name bold
document.getElementsByClassName('tab-' + currentStep)[0].classList.add('bold');
// on click fire the animation
document.getElementById('next').addEventListener('click', function() {
// make sure the slider does not go further than it should
if (currentStep > 3){return;}
// define the keyframes for the progress dot
if (currentStep == 3) {
var moveDot = [
{transform: 'translateX(' + ((boxWidth / 3) * (currentStep - 1)) + 'px)'},
{transform: 'translateX(' + (((boxWidth / 3) * (currentStep)) - dot.offsetWidth) + 'px)'}
];
} else {
var moveDot = [
{transform: 'translateX(' + ((boxWidth / 3) * (currentStep - 1)) + 'px)'},
{transform: 'translateX(' + ((boxWidth / 3) * (currentStep)) + 'px)'},
];
}
// define the keyframes for the sliding bar
var slideBar = [
{
transform: 'scaleX(' + ((boxWidth / 3) * (currentStep - 1)) + ')',
transformOrigin: 'left'
},
{
transform: 'scaleX(' + ((boxWidth / 3) * (currentStep)) + ')',
transformOrigin: 'left'
}
];
var showDot = [
{backgroundColor: '#fff', border: '2px solid lightgrey' },
{backgroundColor: 'darkred', border: '2px solid darkred' }
];
// putting the keyframes and timings together (progress dot)
var movingDot = document.getElementById("progress__dot").animate(
moveDot,
dotTiming
);
// putting the keyframes and timings together (sliding bar)
var slidingBar = document.getElementById("progress__fill").animate(
slideBar,
barTiming
);
var passingDot = document.getElementById('circ__' + currentStep).animate(
showDot,
passedTiming
);
// making the animation play forwards
movingDot.playbackRate = 1;
slidingBar.playbackRate = 1;
passingDot.playbackRate = 1;
// starting the animations
movingDot.play();
slidingBar.play();
movingDot.onfinish = passingDot;
// incrementing and setting the step counter
currentStep++;
document.getElementById("progress__dot").innerHTML = currentStep;
if (currentStep > 1) {
document.getElementById('back').classList.add('is-active');
}
if (currentStep > 3) {
document.getElementById('next').classList.remove('is-active');
}
// toggling the bold class for the step names
document.getElementsByClassName('tab-' + (currentStep - 1))[0].classList.remove('bold');
setTimeout(() =>
{
document.getElementsByClassName('tab-' + currentStep)[0].classList.add('bold');
}, 600);
});
document.getElementById('back').addEventListener('click', function() {
// make sure the slider does not go back past the beginning
if (currentStep < 2){return;}
// define the keyframes
if (currentStep == 4) {
var moveDot = [
{transform: 'translateX(' + ((boxWidth / 3) * (currentStep - 2)) + 'px)'},
{transform: 'translateX(' + (((boxWidth / 3) * (currentStep - 1)) - dot.offsetWidth) + 'px)'}
];
} else {
var moveDot = [
{transform: 'translateX(' + ((boxWidth / 3) * (currentStep - 2)) + 'px)'},
{transform: 'translateX(' + ((boxWidth / 3) * (currentStep - 1)) + 'px)'}
];
}
var slideBar = [
{
transform: 'scaleX(' + ((boxWidth / 3) * (currentStep - 2)) + ')',
transformOrigin: 'left'
},
{
transform: 'scaleX(' + ((boxWidth / 3) * (currentStep -1 )) + ')',
transformOrigin: 'left'
}
];
var showDot = [
{backgroundColor: 'darkred', border: '2px solid darkred' },
{backgroundColor: '#fff', border: '2px solid lightgrey' }
];
// putting the keyframes and timings together
var movingDot = document.getElementById("progress__dot").animate(
moveDot,
dotTiming
);
var slidingBar = document.getElementById("progress__fill").animate(
slideBar,
barTiming
);
var passingDot = document.getElementById('circ__' + currentStep).animate(
showDot,
passedTiming
);
// making the animation reverse
movingDot.playbackRate = -1;
slidingBar.playbackRate = -1;
passingDot.playbackrate = -1;
// starting the animation
movingDot.play();
slidingBar.play();
movingDot.onfinish = passingDot;
// decrementing and setting the step counter
currentStep--;
// set the current step number as the number in the progress dot on the page
document.getElementById("progress__dot").innerHTML = currentStep;
if (currentStep < 4) {
document.getElementById('next').classList.add('is-active');
}
if (currentStep < 2) {
document.getElementById('back').classList.remove('is-active');
}
// toggling the bold class for the step names
document.getElementsByClassName('tab-' + (currentStep + 1))[0].classList.remove('bold');
setTimeout(() =>
{
document.getElementsByClassName('tab-' + currentStep)[0].classList.add('bold');
}, 400);
});
I expect the dot and the slider to be aligned as they go across the page, regardless of zoom percentage
In doing some experimenting, I figured out that I could just use "width" to transform the item rather than scaleX. Here is what I ended up using:
next button event:
var slideBar = [
{
width: ((boxWidth / 3) * (currentStep - 1)) + 'px'
},
{
width: ((boxWidth / 3) * (currentStep)) + 'px'
}
];
back button event:
var slideBar = [
{
width: ((boxWidth / 3) * (currentStep - 2)) + 'px'
},
{
width: ((boxWidth / 3) * (currentStep -1 )) + 'px'
}
];

Animating newly created objects with different keyframes values

So I'm trying to make simple animation. When you press somewhere inside blue container, a circle should be created in this place and then go up. After some research I found how to put JS values into keyframes, but it's changing values for every object not just for freshly created. If you run snipped and press somewhere high and then somewhere low you will see what I'm talking about.
I found some AWESOME solution with Raphael library, but I'm a beginner and I'm trying to make something like this in JS. Is it even possible? How?
var bubble = {
posX: 0,
posY: 0,
size: 0
};
var aquarium = document.getElementById("container");
var ss = document.styleSheets;
var keyframesRule = [];
function findAnimation(animName) { //function to find keyframes and insert replace values in them
for (var i = 0; i < ss.length; i++) {
for (var j = 0; j < ss[i].cssRules.length; j++) {
if (window.CSSRule.KEYFRAMES_RULE == ss[i].cssRules[j].type && ss[i].cssRules[j].name == animName) {
keyframesRule.push(ss[i].cssRules[j]);
}
}
}
return keyframesRule;
}
function changeAnimation (nameAnim) { //changing top value to cursor position when clicked
var keyframesArr = findAnimation(nameAnim);
for (var i = 0; i < keyframesArr.length; i++) {
keyframesArr[i].deleteRule("0%");
keyframesArr[i].appendRule("0% {top: " + bubble.posY + "px}");
}
}
function createBubble(e) {
"use strict";
bubble.posX = e.clientX;
bubble.posY = e.clientY;
bubble.size = Math.round(Math.random() * 100);
var bubbleCircle = document.createElement("div");
aquarium.appendChild(bubbleCircle);
bubbleCircle.className = "bubble";
var bubbleStyle = bubbleCircle.style;
bubbleStyle.width = bubble.size + "px";
bubbleStyle.height = bubble.size + "px";
bubbleStyle.borderRadius = (bubble.size / 2) + "px";
//bubbleStyle.top = bubble.posY - (bubble.size / 2) + "px";
bubbleStyle.left = bubble.posX - (bubble.size / 2) + "px";
changeAnimation("moveUp");
bubbleCircle.className += " animate";
}
aquarium.addEventListener("click", createBubble);
//console.log(bubble);
body {
background-color: red;
margin: 0;
padding: 0;
}
#container {
width: 100%;
height: 100%;
position: fixed;
top: 80px;
left: 0;
background-color: rgb(20,255,200);
}
#surface {
width: 100%;
height: 40px;
position: fixed;
top: 40px;
opacity: 0.5;
background-color: rgb(250,250,250);
}
.bubble {
position: fixed;
border: 1px solid blue;
}
.animate {
animation: moveUp 5s linear;//cubic-bezier(1, 0, 1, 1);
-webkit-animation: moveUp 5s linear;//cubic-bezier(1, 0, 1, 1);
}
#keyframes moveUp{
0% {
top: 400px;
}
100% {
top: 80px;
}
}
#-webkit-keyframes moveUp{
0% {
top: 400px;
}
100% {
top: 80px;
}
}
<body>
<div id="container">
</div>
<div id="surface">
</div>
</body>
Here is a possible solution. What I did:
Remove your functions changeAnimation () and findAnimation() - we don't need them
Update the keyframe to look like - only take care for the 100%
#keyframes moveUp { 100% {top: 80px;} }
Assign top of the new bubble with the clientY value
After 5 seconds set top of the bubble to the offset of the #container(80px) - exactly when animation is over to keep the position of the bubble, otherwise it will return to initial position
var bubble = {
posX: 0,
posY: 0,
size: 0
};
var aquarium = document.getElementById("container");
function createBubble(e) {
"use strict";
bubble.posX = e.clientX;
bubble.posY = e.clientY;
bubble.size = Math.round(Math.random() * 100);
var bubbleCircle = document.createElement("div");
aquarium.appendChild(bubbleCircle);
bubbleCircle.className = "bubble";
var bubbleStyle = bubbleCircle.style;
bubbleStyle.width = bubble.size + "px";
bubbleStyle.height = bubble.size + "px";
bubbleStyle.borderRadius = (bubble.size / 2) + "px";
bubbleStyle.top = bubble.posY - (bubble.size / 2) + "px";
bubbleStyle.left = bubble.posX - (bubble.size / 2) + "px";
bubbleCircle.className += " animate";
// The following code will take care to reset top to the top
// offset of #container which is 80px, otherwise circle will return to
// the position of which it was created
(function(style) {
setTimeout(function() {
style.top = '80px';
}, 5000);
})(bubbleStyle);
}
aquarium.addEventListener("click", createBubble);
body {
background-color: red;
margin: 0;
padding: 0;
}
#container {
width: 100%;
height: 100%;
position: fixed;
top: 80px;
left: 0;
background-color: rgb(20, 255, 200);
}
#surface {
width: 100%;
height: 40px;
position: fixed;
top: 40px;
opacity: 0.5;
background-color: rgb(250, 250, 250);
}
.bubble {
position: fixed;
border: 1px solid blue;
}
.animate {
animation: moveUp 5s linear;
/*cubic-bezier(1, 0, 1, 1);*/
-webkit-animation: moveUp 5s linear;
/*cubic-bezier(1, 0, 1, 1);*/
}
#keyframes moveUp {
100% {
top: 80px;
}
}
#-webkit-keyframes moveUp {
100% {
top: 80px;
}
}
<body>
<div id="container"></div>
<div id="surface"></div>
</body>
The problem about your code was that it is globally changing the #keyframes moveUp which is causing all the bubbles to move.
The problem with your code is that you're updating keyframes which are applied to all bubbles. I tried another way of doing it by using transition and changing the top position after the element was added to the DOM (otherwise it wouldn't be animated).
The main problem here is to wait the element to be added to the DOM. I tried using MutationObserver but it seems to be called before the element is actually added to the DOM (or at least rendered). So the only way I found is using a timeout which will simulate this waiting, although there must be a better one (because it may be called too early, causing the bubble to directly stick to the top), which I would be happy to hear about.
var bubble = {
posX: 0,
posY: 0,
size: 0
};
var aquarium = document.getElementById("container");
function createBubble(e) {
"use strict";
bubble.posX = e.clientX;
bubble.posY = e.clientY;
bubble.size = Math.round(Math.random() * 100);
var bubbleCircle = document.createElement("div");
aquarium.appendChild(bubbleCircle);
bubbleCircle.classList.add("bubble");
var bubbleStyle = bubbleCircle.style;
bubbleStyle.width = bubble.size + "px";
bubbleStyle.height = bubble.size + "px";
bubbleStyle.borderRadius = (bubble.size / 2) + "px";
bubbleStyle.top = bubble.posY - (bubble.size / 2) + "px";
bubbleStyle.left = bubble.posX - (bubble.size / 2) + "px";
setTimeout(function() {
bubbleCircle.classList.add("moveUp");
}, 50);
}
aquarium.addEventListener("click", createBubble);
body {
background-color: red;
margin: 0;
padding: 0;
}
#container {
width: 100%;
height: 100%;
position: fixed;
top: 80px;
left: 0;
background-color: rgb(20, 255, 200);
}
#surface {
width: 100%;
height: 40px;
position: fixed;
top: 40px;
opacity: 0.5;
background-color: rgb(250, 250, 250);
}
.bubble {
position: fixed;
border: 1px solid blue;
transition: 5s;
}
.moveUp {
top: 80px !important;
}
<body>
<div id="container">
</div>
<div id="surface">
</div>
</body>
Also, I used the classList object instead of className += ... because it is more reliable.

Dynamically creating divs with position absolute which can expand to whole screen when clicked

I'm trying to create something like this :
https://tympanus.net/Development/FullscreenLayoutPageTransitions/
But the problem I face is that my divs are dynamic - could be any number that comes from a xhr service call. I'm trying to stack up divs but on click, they don't grow from their position to occupy the whole screen but grow from top left like this:
https://codepen.io/anon/pen/vJPNOq.
How can I achieve the same effect as in the first link for a dynamic list whose count can be unknown?
<div>
<h1>Your dashboard</h1>
<span class="close">X</span>
<section class="parent">
<section>room1</section>
<section>room2</section>
<section>room3</section>
<section>room4</section>
<section>room5</section>
<sectoin>room6</sectoin>
</section>
</div>
section section{
width:150px;
height:150px;
background-color:green;
margin:10px;
padding:30px;
transition:all .5s linear;
}
.parent{
position:relative;
height:100%;
width:100%;
background-color:red;
}
.expanded{
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
z-index:999;
background-color:red;
}
.close{
position:absolute;
top:100;
right:0;
z-index:1000;
cursor:pointer;
}
$('.parent section').click(function(){
$(this).addClass('expanded');
})
$('.close').click(function(){
$('.parent section').each(function(){
$(this).removeClass('expanded');
})
})
Here's a demo that shows how you can do this dynamically, it has a few issues if you spam click it but if you disable the click handler until it finishes the animation, they won't matter. Alternatively you could cache the bounding values (you might want to anyway simply to avoid some of the reflows), but the specifics can change a lot depending on the website you're using this effect on.
Also I didn't implement the shrinking effect but I think it's probably fairly obvious how to do it based on the grow effect.
const numberOfTiles = 9;
const totalColumns = 3;
const totalRows = Math.ceil(numberOfTiles / totalColumns);
const container = document.createElement('div');
Object.assign(container.style, {
width: '80vw',
height: '80vh',
background: 'rgb(60, 61, 60)',
transform: 'translate(10vw, 10vh)',
lineHeight: 1 / totalRows * 100 + '%'
});
const tiles = [];
for (let row = 0; row < totalRows; ++row) {
for (let col = 0; col < totalColumns; ++col) {
if (tiles.length < numberOfTiles) {
const tileContainer = document.createElement('div');
Object.assign(tileContainer.style, {
position: 'relative',
width: 1 / totalColumns * 100 + '%',
height: 1 / totalRows * 100 + '%',
display: 'inline-block'
});
let randomColor = Math.ceil((Math.random() * Math.pow(255, 3))).toString(16);
while (randomColor.length < 6) {
randomColor = '0' + randomColor;
}
randomColor = '#' + randomColor;
const tile = document.createElement('div');
tile.classList.add('tile');
Object.assign(tile.style, {
width: '100%',
height: '100%',
background: randomColor,
willChange: 'transform, left, top'
});
tile.addEventListener('click', (evt) => {
if (tile.classList.toggle('fullscreen')) {
let clientRect = tile.getClientRects();
Object.assign(tile.style, {
position: 'absolute',
width: clientRect.width + 'px',
height: clientRect.height + 'px',
left: clientRect.left + 'px',
top: clientRect.top + 'px',
transition: '1s width, 1s height, 1s transform, 1s left, 1s top',
zIndex: 100
});
setTimeout(() => {
let clientRect = tile.getBoundingClientRect();
Object.assign(tile.style, {
left: 0,
top: 0,
width: '100vw',
height: '100vh',
transform: `translate(${-clientRect.left}px, ${-clientRect.top}px)`
});
}, 0);
} else {
Object.assign(tile.style, {
width: '100%',
height: '100%',
left: 0,
top: 0,
transform: '',
zIndex: 1
});
setTimeout(() => {
Object.assign(tile.style, {
zIndex: 0
});
}, 1000);
}
});
tiles.push(tile);
tileContainer.appendChild(tile);
container.appendChild(tileContainer);
}
}
}
document.body.appendChild(container);
* {
margin: 0;
padding: 0;
}

Rotating an image when user scrolls up and down the screen

I am fairly new to writing in html, css, and coding in javascript.
I digress; i am trying to have an image of a gear rotate when the a user scrolls up and down the screen (i am hoping to give it an elevator effect when i add a belt).
I am using the jquery $(window).scroll(function(). I know it is working because when i use console.log("hi") it writes every time i scroll. My problem is the .animate() function that doesn't seem to work. I even tried downloading "http://jqueryrotate.com/" and using that to rotate.
Any help would be much appreciated!
## HTML ##
<div class="left_pulley">
<img src="gear2.png" />
</div>
<div class="right_pulley">
<img src="gear2.png" />
</div>
## CSS ##
.left_pulley
{
position: absolute;
margin: 0;
padding: 0;
top: 263px;
left: 87%;
height: 35px;
width: 35px;
}
.left_pulley img
{
width: 100%;
}
.right_pulley
{
position: absolute;
margin: 0;
padding: 0;
top: 263px;
left: 94.2%;
height: 35px;
width: 35px;
}
.right_pulley img
{
width: 100%;
}
## JS ##
First using .rotate({})
$(".left_pulley").rotate({bind:
$(window).scroll(function() {
if ($(this).scrollTop() > 0) {
$(.left_pulley).rotate({
angle: 0,
animateTo: 180,
})
})
})
})
Now using .animate({}) to try and just move it at all.
$(window).scroll(function() {
if ($(this).scrollTop() > 0) {
var scott = $('img');
scott.animate({
left: 180
}
}
});
$(window).scroll(function() {
if ($(this).scrollTop() > 0) {
var scott = $('img');
scott.animate({
left: 180
}
function() {
console.log("hi");
}
});
console.log("hi2");
}
});
.left_pulley {
position: absolute;
margin: 0;
padding: 0;
top: 263px;
left: 87%;
height: 35px;
width: 35px;
}
.left_pulley img {
width: 100%;
}
.right_pulley {
position: absolute;
margin: 0;
padding: 0;
top: 263px;
left: 94.2%;
height: 35px;
width: 35px;
}
.right_pulley img {
width: 100%;
}
<div class="left_pulley">
<img src="gear2.png" />
</div>
<div class="right_pulley">
<img src="gear2.png" />
</div>
[
picture of gears i want to rotate.
]1
You should look into the CSS3 transform property, more specifically the rotate() function. Here
It would also be beneficial to add a transistion property to create an animated 'tween' between rotation values. Here. Make sure to add this transition to the transition property (as this is where rotation is set).\
You can then change the rotation of the gear (with automatic animation!) using jquery by setting the css value of the transition property, for example:
#gear{
transition: transform 300ms;
transform: rotate(7deg);
transform-origin:90% 90%;
position:absolute;
left:100px;
top:100px;
font-size:10rem;
width:100px;
height:100px;
}
You can test it out here by hitting run.
https://jsfiddle.net/oc4hhons/
Borrowing heavily from https://stackoverflow.com/a/17348698/2026508
You could do something like this:
var degrees = 0;
var prevScroll = 0;
$(window).scroll(function() {
if ($(window).scrollTop() > 0) {
if (prevScroll > $(window).scrollTop()) {
$('.woo').css({
'-webkit-transform': 'rotate(' + degrees+++'deg)',
'-moz-transform': 'rotate(' + degrees+++'deg)',
'-ms-transform': 'rotate(' + degrees+++'deg)',
'transform': 'rotate(' + degrees+++'deg)'
});
console.log('prevScroll greater:', prevScroll)
} else if (prevScroll < $(window).scrollTop()) {
$('.woo').css({
'-webkit-transform': 'rotate(' + degrees--+'deg)',
'-moz-transform': 'rotate(' + degrees--+'deg)',
'-ms-transform': 'rotate(' + degrees--+'deg)',
'transform': 'rotate(' + degrees--+'deg)'
});
console.log('prevScroll less:', prevScroll)
}
prevScroll = $(window).scrollTop()
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="height: 40px; width: 100px;background-image: url(' gear2.png ');background-color:blue;" class="woo">turn</div>
JS Fiddle-Updated, now they rotate together same direction but the rotation is depending on whether the scroll is up or down:
JS:
var $gears = $('.gear'),
$i = 0,
$scrollBefore = 0;
$(window).scroll(function () {
if($(this).scrollTop() > $scrollBefore){
$scrollBefore = $(this).scrollTop();
$gears.css("transform", "rotate(" + ($i+=4) + "deg)");
}else if($(this).scrollTop() < $scrollBefore){
$scrollBefore = $(this).scrollTop();
$gears.css("transform", "rotate(" + ($i-=4) + "deg)");
}
});
this JS Fiddle 2, makes them rotate in opposite directions, and each gear direction switches depending if the scrolling is up or down:
JS:
var $gearLeft = $('.left_pulley'),
$gearRight = $('.right_pulley'),
$i = 0,
$j = 0,
$scrollBefore = 0;
$(window).scroll(function() {
if ($(this).scrollTop() > $scrollBefore) {
$scrollBefore = $(this).scrollTop();
$gearLeft.css("transform", "rotate(" + ($i += 4) + "deg)");
$gearRight.css("transform", "rotate(" + ($j -= 4) + "deg)");
} else if ($(this).scrollTop() < $scrollBefore) {
$scrollBefore = $(this).scrollTop();
$gearLeft.css("transform", "rotate(" + ($i -= 4) + "deg)");
$gearRight.css("transform", "rotate(" + ($j += 4) + "deg)");
}
});
Thanks for all the help everyone!
Just want to post my finial code in case anyone else needs help in the future.
/* Scott Louzon 11/24/15
This code is used to rotate two images of a gears when user scrolls */
/*This function see's when user scrolls then calls rotate_right & rotate_left
accordingly */
var scroll_at = 0; //variable to keep track of
//scroll postion
$(window).scroll(function() {
if ($(this).scrollTop() > 0) //if scroll postion is not at
{ //top do this
if ($(this).scrollTop() > scroll_at) //if scroll postion is > than b4
{
rotate_down();
}
else if ($(this).scrollTop() < scroll_at) //if scroll postion is < than b4
{
rotate_up();
}
scroll_at = $(this).scrollTop(); //set varible to were scroll
//postion is at now
}
})
//Both these functions call css to rotate the image of a gear
var rotation = 0;
function rotate_down()
{
rotation+= 8;
$(".left_pulley").css("transform","rotate("+ rotation +"deg)");
$(".right_pulley").css("transform","rotate("+ (-1 * rotation) +"deg)");
}
function rotate_up()
{
rotation += 8;
$(".left_pulley").css("transform","rotate("+ (-1 * rotation)+"deg)");
$(".right_pulley").css("transform","rotate("+ rotation +"deg)");
}
.left_pulley
{
position: absolute;
margin: 0;
padding: 0;
/*Used for gear rotation */
transition: transform 1ms;
transform-origin:50% 50%;
top: 263px;
left: 87%;
height: 35px;
width: 35px;
}
.left_pulley img
{
width: 100%;
}
.right_pulley
{
position: absolute;
margin: 0;
padding: 0;
/* Used for gear rotation */
transition: transform 1ms;
transform-origin:50% 50%;
top: 263px;
left: 94.2%;
height: 35px;
width: 35px;
}
.right_pulley img
{
width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="left_pulley">
<img src="gear2.png" />
</div>
<div class="right_pulley">
<img src="gear2.png" />
</div>

Categories

Resources