Single page scroll with jQuery - javascript

I am struggling to create a web page where there are 2 sections.
The first section is the complete website except for the menu.
The second section should be the menu displayed on full screen.
The user should be able to scroll with a nice effect between the two sections.
Here is a code pen example:
HTML:
<!DOCTYPE html>
<html>
<head>
<style>
/* SCROLL BEGIN */
a.back-to-top {
display: none;
width: 100px;
height: 100px;
text-indent: -9999px;
position: fixed;
z-index: 999;
top: 85%;
left: 45%;
background: url("http://www.cleanmyride.ca/wp-content/uploads/2015/01/Down-Arrow.png");
-webkit-border-radius: 30px;
-moz-border-radius: 30px;
border-radius: 30px;
}
/* SCROLL END*/
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js">
</script>
<link href="https://fonts.googleapis.com/css?family=Bree+Serif" rel="stylesheet">
<link href="test.css" rel="stylesheet">
<title>Pandaniell</title>
</head>
<body>
<a class="back-to-top" href="#">Back To Top</a>
<!-- SCROLL BEGIN -->
<script>
var amountScrolled = 4800;
$('a.back-to-top').fadeIn('slow');
$(window).scroll(function () {
if ($(window).scrollTop() < amountScrolled) {
$('a.back-to-top').fadeIn('slow');
} else {
$('a.back-to-top').fadeOut('slow');
}
});
$('a.back-to-top').click(function () {
$('html, body').animate({
scrollTop: 10000
}, 1000);
return false;
});
</script>
<!-- SCROLL END -->
<div class="container"></div>
<nav>
<ul>
<li>
HOME
</li>
<li>
ABOUT
</li>
<li>
WHERE
</li>
<li>
CONTACT
</li>
<li style="float:right">
PORTFOLIO
</li>
</ul>
</nav>
<div id="gradient"></div>
<script>
// target to give background to
var $div = document.getElementById("gradient");
// rgb vals of the gradients
var gradients = [{
start: [128, 179, 171],
stop: [30, 41, 58]
},
{
start: [255, 207, 160],
stop: [234, 92, 68]
},
{
start: [212, 121, 121],
stop: [130, 105, 151]
}
];
// how long for each transition
var transition_time = 4;
// internal type vars
var currentIndex = 0; // where we are in the gradients array
var nextIndex = 1; // what index of the gradients array is next
var steps_count = 0; // steps counter
var steps_total = Math.round(transition_time * 60); // total amount of steps
var rgb_steps = {
start: [0, 0, 0],
stop: [0, 0, 0]
}; // how much to alter each rgb value
var rgb_values = {
start: [0, 0, 0],
stop: [0, 0, 0]
}; // the current rgb values, gets altered by rgb steps on each interval
var prefixes = ["-webkit-", "-moz-", "-o-", "-ms-", ""]; // for looping through adding styles
var div_style = $div.style; // short cut to actually adding styles
var color1, color2;
// sets next current and next index of gradients array
function set_next(num) {
return (num + 1 < gradients.length) ? num + 1 : 0;
}
// work out how big each rgb step is
function calc_step_size(a, b) {
return (a - b) / steps_total;
}
// populate the rgb_values and rgb_steps objects
function calc_steps() {
for (var key in rgb_values) {
if (rgb_values.hasOwnProperty(key)) {
for (var i = 0; i < 3; i++) {
rgb_values[key][i] = gradients[currentIndex][key][i];
rgb_steps[key][i] = calc_step_size(gradients[nextIndex][key][i],
rgb_values[key][i]);
}
}
}
}
// update current rgb vals, update DOM element with new CSS background
function updateGradient() {
// update the current rgb vals
for (var key in rgb_values) {
if (rgb_values.hasOwnProperty(key)) {
for (var i = 0; i < 3; i++) {
rgb_values[key][i] += rgb_steps[key][i];
}
}
}
// generate CSS rgb values
var t_color1 = "rgb(" + (rgb_values.start[0] | 0) + "," + (rgb_values.start[
1] | 0) + "," + (rgb_values.start[2] | 0) + ")";
var t_color2 = "rgb(" + (rgb_values.stop[0] | 0) + "," + (rgb_values.stop[
1] | 0) + "," + (rgb_values.stop[2] | 0) + ")";
// has anything changed on this interation
if (t_color1 != color1 || t_color2 != color2) {
// update cols strings
color1 = t_color1;
color2 = t_color2;
// update DOM element style attribute
div_style.backgroundImage =
"-webkit-gradient(linear, left bottom, right top, from(" + color1 +
"), to(" + color2 + "))";
for (var i = 0; i < 4; i++) {
div_style.backgroundImage = prefixes[i] + "linear-gradient(45deg, " +
color1 + ", " + color2 + ")";
}
}
// we did another step
steps_count++;
// did we do too many steps?
if (steps_count > steps_total) {
// reset steps count
steps_count = 0;
// set new indexs
currentIndex = set_next(currentIndex);
nextIndex = set_next(nextIndex);
// calc steps
calc_steps();
}
if (div_style.backgroundImage.indexOf("gradient") != -1) {
window.requestAnimationFrame(updateGradient)
}
}
// initial step calc
calc_steps();
// go go go!
window.requestAnimationFrame(updateGradient);
</script>
<h1>Dit is mijn website</h1>
<h2><img alt="Instagram" border="0" class="instagram" height="50" src="https://image.ibb.co/nHgkKQ/Instagram.png" width="50"></h2>
<h3><img alt="Facebook" border="0" class="facebook" height="50" src="https://image.ibb.co/bLf7zQ/Facebook.png" width="50"></h3>
<h4><a href="https://www.dropbox.com/sh/omjvrdt5b3a5x6m/AACYBA_EKBeNzAK1YVQmTtH7a?dl=0"
target="_blank"><img alt="Dropbox" border="0" class="dropbox" height="50" src="https://image.ibb.co/i2fUDk/Dropbox.png" width="50"></a></h4>
<script>
document.addEventListener('DOMContentLoaded', function (event) {
// array with texts to type in typewriter
var dataText = ["Welkom op mijn website! dit is een voorbeeld tekst"];
// type one text in the typwriter
// keeps calling itself until the text is finished
function typeWriter(text, i, fnCallback) {
// chekc if text isn't finished yet
if (i < (text.length)) {
// add next character to h1
document.querySelector("h1").innerHTML = text.substring(0, i + 1) +
'<span aria-hidden="true"><\/span>';
// wait for a while and call this function again for next character
setTimeout(function () {
typeWriter(text, i + 1, fnCallback)
}, 100);
}
// text finished, call callback if there is a callback function
else if (typeof fnCallback == 'function') {
// call callback after timeout
setTimeout(fnCallback, 700);
}
}
// start a typewriter animation for a text in the dataText array
function StartTextAnimation(i) {
if (typeof dataText[i] == 'undefined') {
setTimeout(function () {
StartTextAnimation(0);
}, 20000);
}
// check if dataText[i] exists
if (i < dataText[i].length) {
// text exists! start typewriter animation
typeWriter(dataText[i], 0, function () {
// after callback (and whole text has been animated), start next text
StartTextAnimation(i + 1);
});
}
}
// start the text animation
StartTextAnimation(0);
});
</script>
</body>
</html>
CSS:
.instagram {
margin: auto;
position: absolute;
top: -20 % % ;
left: 5 % ;
bottom: 5 % ;
right: 8 % ;
}
.facebook {
margin: auto;
position: absolute;
top: -20 % % ;
left: 5 % ;
bottom: 5 % ;
right: 16 % ;
}
.dropbox {
margin: auto;
position: absolute;
top: -20 % % ;
left: 5 % ;
bottom: 5 % ;
right: 0 % ;
}
.container {
width: 95 % ;
margin - left: auto;
margin - right: auto;
height: 1000 px;
}
/* Navigation */
nav {
width: 100 % ;
height: 6.5 % ;
background - color: rgba(255, 255, 255, 0.13);
}
ul li {
list - style - type: none;
float: left;
color: #FFFFFF;
font - size: 16 px;
text - align: left;
margin - right: 25 px;
margin - top: 25 px;
letter - spacing: 2 px;
font - weight: bold;
}
ul li a {
color: #FFFFFF;
text - decoration: none;
visibility: visible;
opacity: 1;
transition: 0.2 s ease;
}
ul li: hover a {
color: #1115B4;
visibility: visible;
opacity: 1;
}
# gradient {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: #836997;
}
h1 {
width: 50%;
font-family: 'Bree Serif', serif;
font-size: 80px;
color: white;
margin: auto;
position: absolute;
top: 30%;
left: 5%;
bottom: 5%;
right: 5%;
}
body {
font-family: arial;
background-color: rgb(0, 0, 0);
margin-top: 0px;
margin-right: 0px;
margin-bottom: 100px;
margin-left: 0px;
font-style: normal;
font-weight: 200;
height: 100%;
{

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.

jquery reveal image based on get second clock

I'm struggling to find a solution to this and wonder if anyone can help.
I'd like to make a page where an image would disappear over time revealing another image. I'm hoping to achieve this by using the updatesecond/getseconds function. So essentially it would act as a clock, the more minutes/seconds have passed the more it disappears, and have it cycle. For example at the beginning of the day it would be a full image, at 12 it would be half, and at 24hours it would be gone, and repeat. I figure it would be an if else function about the percentage of the page that's left, I just can't figure out how to word it.
Is this possible at all? Any help would be greatly appreciated. Thanks!
Here is the code I'm working with so far. Thank you in advance.
body
{
background-color: #FFF;
padding: 2%;
color: #ccc;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 1em;
}
a
{
color: #FFF;
text-decoration: none;
}
a:hover
{
color: #DCE808;
text-decoration: underline;
}
#mosaic
{
/* background-color: yellow;
font-size: 500px;
color: black;
height: 1310px;
width: 2000px; */
background-image: url('tomorrow4.png');
}
#mosaic span.hover
{
/* background-color: blue;
font-size: 500px;
color: white;
height: 1310px;
width: 2000px;
left: 100px;*/
float: left;
background-image: url('today4.png');
}
and javascript
$(document).ready(function() {
var width = 1400;
var height = 724;
count = 0;
elements = new Array();
var el = $('#mosaic');
el.width(width).height(height);
var horizontal_pieces = 100;
var vertical_pieces = 100;
total_pieces = horizontal_pieces * vertical_pieces;
var box_width = width / horizontal_pieces;
var box_height = height / vertical_pieces;
var vertical_position = 0;
for (i=0; i<total_pieces; i++)
{
var tempEl = $('<span class="hover" id="hover-' + i + '">
</span>');
var horizontal_position = (i % horizontal_pieces) * box_width;
if(i > 0 && i % horizontal_pieces == 0)
{
vertical_position += box_height;
}
tempEl.css('background-position', '-' + horizontal_position + 'px
-' + vertical_position + 'px');
el.append(tempEl);
elements.push(tempEl);
}
elements = shuffleArray(elements);
$('#mosaic .hover').width(box_width).height(box_height);
setInterval(toggleDisplay, 100);
});
function toggleDisplay()
{
var tempEl = elements[count];
var opacity = tempEl.css('opacity');
if(opacity == 0)
{
tempEl.animate({ opacity: 1 })
}
else
{
tempEl.animate({ opacity: 0 })
}
count = (count + 1) % total_pieces;
}
/* shuffleArray source:
http://stackoverflow.com/questions/2450954/how-to-randomize-a-
javascript-array#12646864 */
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor() * (i + 1);
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
Do you mean something like this? http://jsfiddle.net/1r5qer56/
I used 4 sectors (as skewY tends to screw up over 90 degrees) and had them set to a size relative to the amount of minutes that have passed since midnight.
If you want to test it, just put a custom number in for time.
My code is below:
HTML
<ul class='pie'>
<li class='slice tr'><div class='slice-contents'></div></li>
<li class='slice br'><div class='slice-contents'></div></li>
<li class='slice bl'><div class='slice-contents'></div></li>
<li class='slice tl'><div class='slice-contents'></div></li>
<ul>
CSS
.pie {
position: relative;
margin: 1em auto;
border: dashed 1px;
padding: 0;
width: 32em; height: 32em;
border-radius: 50%;
list-style: none;
background-image: url('http://lorempixel.com/output/animals-q-c-512-512-4.jpg');
}
.slice {
overflow: hidden;
position: absolute;
top: 0; right: 0;
width: 50%; height: 50%;
transform-origin: 0% 100%;
}
.slice.tr {
transform: rotate(0deg) skewY(-0deg);
}
.slice.br {
transform: rotate(90deg) skewY(0deg);
}
.slice.bl {
transform: rotate(180deg) skewY(0deg);
}
.slice.tl {
transform: rotate(270deg) skewY(0deg);
}
.slice-contents {
position: absolute;
left: -100%;
width: 200%; height: 200%;
border-radius: 50%;
background: lightblue;
}
.slice.tr .slice-contents {
transform: skewY(0deg); /* unskew slice contents */
}
.slice.br .slice-contents {
transform: skewY(0deg); /* unskew slice contents */
}
.slice.bl .slice-contents {
transform: skewY(0deg); /* unskew slice contents */
}
.slice.tl .slice-contents {
transform: skewY(0deg); /* unskew slice contents */
}
JS+jQuery
updateClock();
setInterval(function(){updateClock();}, 60000);//check for updates once per minute
function updateClock(){
var dt = new Date();
var time = (dt.getHours() * 60) + dt.getMinutes();//number of minutes since 00.00
var timeToDegrees = time / 4;//1440 minutes in 24hours, 360 degrees in a circle. 1440 / 4 = 360
if(timeToDegrees < 90){//deal with top right sector
$('.slice.tr').css('transform', 'rotate('+timeToDegrees+'deg) skewY(-'+timeToDegrees+'deg)');
$('.slice.tr .slice-contents').css('transform', 'skewY('+timeToDegrees+'deg)');
}
else if(timeToDegrees < 180){//deal with bottom right sector
var localDeg = timeToDegrees - 90;
$('.slice.tr').eq(0).css('transform', 'rotate(90deg) skewY(-90deg)');
$('.slice.tr .slice-contents').css('transform', 'skewY(90deg)');
$('.slice.br').css('transform', 'rotate('+(90+localDeg)+'deg) skewY(-'+localDeg+'deg)');
$('.slice.br .slice-contents').css('transform', 'skewY('+localDeg+'deg)');
}
else if(timeToDegrees < 270){//deal with bottom left sector
var localDeg = timeToDegrees - 180;
$('.slice.tr').css('transform', 'rotate(90deg) skewY(-90deg)');
$('.slice.tr .slice-contents').css('transform', 'skewY(90deg)');
$('.slice.br').css('transform', 'rotate(180deg) skewY(-90deg)');
$('.slice.br .slice-contents').css('transform', 'skewY(90deg)');
$('.slice.bl').css('transform', 'rotate('+(180+localDeg)+'deg) skewY(-'+localDeg+'deg)');
$('.slice.bl .slice-contents').css('transform', 'skewY('+localDeg+'deg)');
}
else if(timeToDegrees <= 360){//deal with top left sector
var localDeg = timeToDegrees - 270;
$('.slice.tr').css('transform', 'rotate(90deg) skewY(-90deg)');
$('.slice.tr .slice-contents').css('transform', 'skewY(90deg)');
$('.slice.br').css('transform', 'rotate(90deg) skewY(-90deg)');
$('.slice.br .slice-contents').css('transform', 'skewY(90deg)');
$('.slice.bl').css('transform', 'rotate(270deg) skewY(-90deg)');
$('.slice.bl .slice-contents').css('transform', 'skewY(90deg)');
$('.slice.tl').css('transform', 'rotate('+(270+localDeg)+'deg) skewY(-'+localDeg+'deg)');
$('.slice.tl .slice-contents').css('transform', 'skewY('+localDeg+'deg)');
}
}
Taking a look at the code, from what I gather, you're looking for a picture that is covered with another picture, proportional to the length of the day in seconds. Like one picture sliding over another? Like this picture:
Take a look at the jsBin I've created here http://jsbin.com/xevinakihe/edit?html,css,js,output
The meat of the code is the timing and height adjustment:
function setCoverHeight() {
var d = new Date();
var curSecs = d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds();
var coverHeight = curSecs * 100 / (24 * 3600);
$('.cover').height(coverHeight + '%');
if (curSecs < 24 * 3600) {
setTimeout(setCoverHeight, 1000);
console.log(coverHeight);
} else {
// reset the cover height to 0%
$('.cover').height(0);
// swap the cover image to the bottom
$('.bottom').css('backround-image', $('.cover').css('background-image'));
// set a new cover image
// ... get from Ajax, array, etc
}
}
setCoverHeight();
That is adjusting the HTML:
<div class="wrapper">
<div class="cover"></div>
<div class="bottom"></div>
</div>
Eventually the day will run out and the cover should be swapped with the bottom image, so that you can cycle through individual daily pictures (ex. 'today.jpg' and 'tomorrow.jpg')
Hope that helps!

Semi-fixed text in a scrolling container

I've got a bunch of horizontal boxes containing text. The boxes are all in a horizontally scrolling container:
// generate some random data
var model = {
leftEdge: ko.observable(0)
};
model.rows = populateArray(10 + randInt(20), randRow);
ko.applyBindings(model);
$(function() {
$('.slide').on('scroll', function() {
model.leftEdge(this.scrollLeft);
})
})
function randRow() {
var events = populateArray(50 + randInt(100), randEvent);
var left = randInt(1000);
events.forEach(function(event) {
event.left = left;
left += 10 + event.width + randInt(1000);
});
return {
events: events
}
}
function randEvent() {
var word = randWord()
var width = 50 + Math.max(8 * word.length, randInt(200));
var event = {
left: 0,
width: width,
label: word
};
event.offset = ko.computed(function() {
// reposition the text to stay
// * within its container
// * fully on-screen (if possible)
var leftEdge = model.leftEdge();
return Math.max(0, Math.min(
leftEdge - event.left,
event.width - 8 * event.label.length
));
});
return event;
}
function randWord() {
var n = 2 + randInt(5);
var ret = "";
while (n-- > 0) {
ret += randElt("rmhntsk");
ret += randElt("aeiou");
}
return ret;
}
function randElt(arr) {
return arr[randInt(arr.length)];
}
function populateArray(n, populate) {
var arr = new Array(n);
for (var i = 0; i < n; i++) {
arr[i] = populate();
}
return arr;
}
function randInt(n) {
return Math.floor(Math.random() * n);
}
.slide {
max-width: 100%;
overflow: auto;
border: 5px solid black;
}
.row {
position: relative;
height: 25px;
}
.event {
position: absolute;
top: 2.5px;
border: 1px solid black;
padding: 2px;
background: #cdffff;
font-size: 14px;
font-family: monospace;
}
.event > span {
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="slide" data-bind="foreach: rows">
<div class="row" data-bind="foreach: events">
<div class="event" data-bind="style: { left: left+'px', width: width+'px' }"><span data-bind="text:label, style: { left: offset() + 'px' }"></div>
</div>
</div>
What I'd like to do is as the user scrolls from left-to-right, reposition the text within each box that partially overlaps the left border of the visible window to keep the text as visible as possible.
Currently I'm doing this by manually repositioning each item of text.
Is there a cleaner way to do this using CSS?
A friend helped me come up with this solution.
In English, the idea is to add an overlay to each row that is positioned relatively to the frame of the scrolling box, rather than the contents.
Then we can place a label for any box that overlaps the left edge in this overlay and it will appear to smoothly move as the box underneath it scrolls.
// generate some random data
var model = {
leftEdge: ko.observable(0),
};
model.rows = populateArray(10 + randInt(20), randRow);
model.width = Math.max.apply(Math, $.map(model.rows, function(row) {
return row.width
}));
ko.applyBindings(model);
$(function() {
$('.slide').on('scroll', function() {
model.leftEdge(this.scrollLeft);
})
})
function randRow() {
var events = populateArray(50 + randInt(100), randEvent);
var left = randInt(1000);
events.forEach(function(event) {
event.left = left;
left += 10 + event.width + randInt(1000);
});
return {
events: events,
width: left
}
}
function randEvent() {
var word = randWord()
var width = 50 + Math.max(8 * word.length, randInt(200));
var event = {
width: width,
label: word,
};
event.tense = ko.computed(function() {
// reposition the text to stay#
// * within its container
// * fully on-screen (if possible)
var leftEdge = model.leftEdge();
return ['future', 'present', 'past'][
(leftEdge >= event.left) +
(leftEdge > event.left + event.width - 8 * event.label.length)
];
});
return event;
}
function randWord() {
var n = 2 + randInt(5);
var ret = "";
while (n-- > 0) {
ret += randElt("rmhntsk");
ret += randElt("aeiou");
}
return ret;
}
function randElt(arr) {
return arr[randInt(arr.length)];
}
function populateArray(n, populate) {
var arr = new Array(n);
for (var i = 0; i < n; i++) {
arr[i] = populate();
}
return arr;
}
function randInt(n) {
return Math.floor(Math.random() * n);
}
.wrapper {
position: relative;
border: 5px solid black;
font-size: 14px;
font-family: monospace;
}
.slide {
max-width: 100%;
overflow: auto;
}
.slide > * {
height: 25px;
}
.overlay {
position: absolute;
width: 100%;
left: 0;
}
.overlay .past {
display: none
}
.overlay .present {
position: absolute;
z-index: 1;
top: 5.5px;
left 0;
}
.overlay .future {
display: none
}
.row {
position: relative;
}
.event {
position: absolute;
top: 2.5px;
border: 1px solid black;
padding: 2px;
background: #cdffff;
height: 14px;
}
.event .past {
float: right;
}
.event .present {
display: none;
}
.event .future {
float: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="wrapper">
<div class="slide" data-bind="foreach: rows, style: { width: width + 'px' }">
<div class="overlay" data-bind="foreach: events">
<span data-bind="text:label, css: tense"></span>
</div>
<div class="row" data-bind="foreach: events">
<div class="event" data-bind="style: { left: left+'px', width: width+'px' }"><span data-bind="text:label, css: tense"></div>
</div>
</div></div>
This doesn't result in less javascript, but it does result in more efficient javascript, as class changes happen much less often than offset changes, so fewer updates to DOM elements are required.
You can avoid processing every "event" (in the above example) by doing some pre-partitioning of the horizontal space, and only updating events in the relevant partition.

Categories

Resources