jQuery .each update automatically and create global variable? - javascript

I'm very new to code. I'm trying to create a scrolling effect using greensock draggable. I'd like my div to drag only if my content of another div exceeds the height value of it's parent's height. Here is the codepen I'm working on - https://codepen.io/kbeats/pen/vVYGOX
So far, I have for my dragging and scrolling code:
Draggable.create("#scrollIcon", {
type: "y",
bounds: "#toc",
onDrag: scroll
});
$(".tile").each(function(){
var height = $(this).height();
});
function scroll(){
if(height > $(toc).height()){
TweenMax.set(".tile", {y: this.y * -1})
}
}
The console.log is saying 'height' is undefined, so I'm guessing it's only being stored as a local variable? Is there a way to iterate through each .tile class and create a global variable of the sum total height that will update automatically when the height changes? (Or maybe just update each time a .tile element is clicked?)
Ultimately, I'm trying to have my 'scroll' div only scroll when the .tile class content exceeds the parent (#toc) height and then somehow create an equation where the scroll amount will adjust depending on the total height of the .tile class. (So it will always be able to scroll through all the content, but not overshoot).

The problem is that in this section:
$(".tile").each(function(){
var height = $(this).height();
});
height is only available in that scope. Also, you want to sum up the heights, not just the height of one of the .tiles. Instead, you should do the each inside of the scroll function, and sum up the heights.
Also, you will want to scale the tween by the height ratio between the tile total and the toc, because the amount you'll want to scroll is not only based on the absolute height of the scrollbar. Instead of this.y * -1, you probably want something more like this.y * height / $(toc).height() * -1.
function scroll(){
var height= 0;
$('.tile').each(function() {
height += $(this).height();
});
if(height > $(toc).height()) {
TweenMax.set(".tile", {
y: this.y * height / $(toc).height() * -1
});
}
var base = document.getElementById("Base");
var tab = document.getElementById("Tab");
var arrows = document.getElementById("tocArrows");
var content = document.getElementsByClassName("tile");
var toc = document.getElementById("toc");
//
// variables for slides
var oneSlideOne = document.getElementById("oneSlideOne");
var oneSlideTwo = document.getElementById("oneSlideTwo");
var twoSlideOne = document.getElementById("twoSlideOne");
var twoSlideTwo = document.getElementById("twoSlideTwo");
// menu open and close timeline
var tl = new TimelineMax({
paused: true,
reversed: true
});
tl.to(base, .5, {
x: 280,
ease: Sine.easeInOut
});
tl.to("#start1", 0.8, {
morphSVG: "#end1",
ease: Back.easeInOut
}, 0);
tl.to("#start2", 0.8, {
morphSVG: "#end2",
ease: Back.easeInOut
}, 0);
arrows.addEventListener("mousedown", openMenu);
function openMenu() {
tl.reversed() ? tl.play() : tl.reverse();
}
// making the accordion menu
var acc = document.getElementsByClassName("tile");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener('click', function() {
this.classList.toggle("active");
var $panel = $("ul, li", this);
this.classList.contains("active") ? $panel.show() : $panel.hide();
})
}
// gsap for custom scroll bar?
Draggable.create("#scrollIcon", {
type: "y",
bounds: "#toc",
onDrag: scroll
});
function scroll() {
var height = 0;
$('.tile').each(function() {
height += $(this).height();
});
if (height > $(toc).height()) {
TweenMax.set(".tile", {
y: this.y * height / $(toc).height() * -1
})
}
}
.base {
height: 250px;
width: 280px;
background-color: #17307F;
position: absolute;
left: -280px;
top: 0px;
}
.tab {
background-color: #17307F;
position: absolute;
width: 80px;
height: 80px;
left: 280px;
border-radius: 0px 0px 20px 0px;
}
#scrollIcon {
background-color: white;
width: 25px;
height: 50px;
position: relative;
float: right;
margin-top: 20px;
margin-right: 15px;
border-radius: 30px;
cursor: pointer;
}
#tocArrows {
width: 50px;
height: 50px;
display: inline;
margin: 0 auto;
padding-top: 15px;
padding-left: 15px;
cursor: pointer;
}
#tocReverse {
width: 50px;
height: 50px;
display: inline;
margin: 0 auto;
cursor: pointer;
position: relative;
top: -52px;
visibility: hidden;
}
ul#toc {
list-style: none;
display: block;
height: 200px;
overflow: hidden;
/*overflow-y: scroll;
overflow-x: hidden;*/
}
li {
position: relative;
left: -40px;
text-decoration: none;
display: block;
}
li .subTile {
display: none;
}
.tile {
background-color: #74A3EB;
width: 220px;
padding-top: 10px;
padding-bottom: 10px;
border-radius: 10px;
color: white;
font-family: lato;
font-weight: 700;
font-size: 24px;
line-height: 40px;
text-align: center;
cursor: pointer;
margin: 10px 2px 0px 10px;
transition: 0.4s ease-in-out;
display: block;
top: 0px;
left: -40px;
}
.active,
.tile:hover {
background-color: #3C72F0;
/* change this color */
}
.subTile {
display: none;
position: relative;
background-color: #99B4FF;
width: 200px;
height: 40px;
border-radius: 10px;
display: none;
overflow: hidden;
max-height: 100%;
color: white;
font-family: lato;
text-align: center;
line-height: 40px;
font-size: 20px;
margin: 0px 10px 6px 10px;
cursor: default;
transition: background-color 0.2s ease-in-out;
}
.subTile:hover {
background-color: #F2BB22;
}
#twoSlideTwo {
font-size: 16px;
height: 60px;
line-height: 30px;
}
#twoSlideThree {
font-size: 16px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.1/utils/Draggable.min.js"></script>
<div class=base id="Base">
<div class=tab id="Tab">
<svg id="tocArrows" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 47.95 63.28"><title>tocArrows</title><polyline id="start1" points="15.07 3 43.71 31.64 15.07 60.28" fill="none" stroke="#fff" stroke-linecap="round" stroke-miterlimit="10" stroke-width="6"/><polyline id="start2" points="3 9.96 24.68 31.64 3 53.32" fill="none" stroke="#fff" stroke-linecap="round" stroke-miterlimit="10" stroke-width="6"/></svg>
<svg id="tocReverse" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 47.95 63.28"><title>tocReverse</title><polyline id="end1" points="32.88 60.28 4.24 31.64 32.88 3" fill="none" stroke="#fff" stroke-linecap="round" stroke-miterlimit="10" stroke-width="6"/><polyline id="end2" points="44.95 53.32 23.27 31.64 44.95 9.96" fill="none" stroke="#fff" stroke-linecap="round" stroke-miterlimit="10" stroke-width="6"/></svg>
</div>
<div class="scrollPane" id="scrollIcon"> </div>
<ul id="toc">
<li class="tile" id="moduleOneTitle"> Module One
<ul>
<li class="subTile modOne" id="oneSlideOne"> Title Slide </li>
<li class="subTile modOne" id="oneSlideTwo"> References </li>
<li class="subTile modOne" id="oneSlideThree"> Introduction </li>
<li class="subTile modOne" id="oneSlideFour"> Next Slide </li>
</ul>
</li>
<li class=tile id="moduleTwoTitle"> Module Two
<ul>
<li class="subTile modTwo" id="twoSlideOne"> Title Slide </li>
<li class="subTile modTwo" id="twoSlideTwo"> Third Slide Long Name </li>
<li class="subTile modTwo" id="twoSlideThree"> Fourth Slide Long </li>
</ul>
</li>
</ul>
</div>

Related

How to use javascript to open the modal when connecting the API so that the user can see the animation effect?

let btn = document.querySelector('.btn');
let modal = document.querySelector('.modal');
let wrap = document.querySelector('.wrap');
let photo = document.querySelector('.photo');
let svg = document.querySelector('svg');
let data = [{
title: "dog",
age: 10,
rank: [{
rankStatus: 'behind'
},
{
rankStatus: 'generally',
rankNum: '20'
},
{
rankStatus: 'excellent'
}
]
}]
let rankStatusArr = data[0].rank.map(item => item.rankStatus);
let rankNum = data[0].rank.find(item => item.rankNum).rankNum;
btn.addEventListener('click', function(e) {
svg.style.display = "block"
axios.get("https://dog.ceo/api/breeds/image/random")
.then((response) => {
// 设置处理程序以在加载图像后显示图像
photo.addEventListener('load', () => {
svg.style.display = "none"
modal.style.display = "flex";
});
// 添加“加载”处理程序后设置图像源
photo.src = response.data.message;
})
.catch((error) => console.log(error));
// 排名狀態在 popup 打開後再載入動畫
let progress = rankNum;
let dot = document.getElementById("dot");
var dotPosition = (progress / 30) * 100;
dot.style.left = dotPosition + "%";
let txt = document.querySelectorAll('.txt');
for (let i = 0; i < txt.length; i++) {
txt[i].innerHTML = rankStatusArr[i];
}
})
wrap.addEventListener('click', function(e) {
e.stopPropagation();
})
modal.addEventListener('click', function() {
modal.style.display = "none"
})
.modal {
width: 100%;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: none;
justify-content: center;
align-items: center;
}
.wrap {
width: 300px;
height: 300px;
padding: 20px;
background-color: #fff;
display: flex;
justify-content: center;
align-items: center;
border-radius: 20px;
flex-direction: column;
}
.wrap .photo {
width: 100%;
height: 200px;
object-fit: cover;
margin-bottom: 20px;
}
.wrap #progress-bar-container {
width: 100%;
height: 5px;
background-color: #fff;
position: relative;
display: flex;
flex-wrap: nowrap;
}
.wrap #progress-bar-container .progress-bar {
width: 33.33%;
height: 5px;
background-color: #ccc;
margin-right: 8px;
border-radius: 20px;
}
.wrap #progress-bar-container .progress-bar .txt {
text-align: center;
color: #ccc;
margin-top: 20px;
}
#progress-bar-1 {
background-color: #ddd;
}
#progress-bar-2 {
background-color: #ddd;
}
#progress-bar-3 {
background-color: #ddd;
margin-right: 0;
}
#dot {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #333;
position: absolute;
top: -3px;
left: 0;
transition: left 0.2s ease-out;
}
svg {
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
svg .load {
stroke-dasharray: 0 500;
animation: rot 1s linear infinite;
}
#keyframes rot {
100% {
stroke-dasharray: 500 500;
}
}
.green {
color: yellowgreen;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.3.2/axios.min.js"></script>
<button class='btn'>open</button>
<div class="modal">
<div class="wrap">
<img class="photo" src="" alt="photo">
<div id="progress-bar-container">
<div class="progress-bar" id="progress-bar-1">
<p class="txt">1</p>
</div>
<div class="progress-bar" id="progress-bar-2">
<p class="txt">2</p>
</div>
<div class="progress-bar" id="progress-bar-3">
<p class="txt">3</p>
</div>
<div id="dot"></div>
</div>
</div>
</div>
<!-- load -->
<svg width="240px" height="240px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="110" cy="110" r="90" stroke-width="10" stroke="gainsboro" fill="none"></circle>
<circle cx="110" cy="110" r="90" stroke-width="10" stroke="darkturquoise" fill="none" class="load"></circle>
</svg>
I encountered a little difficulty in the following requirements. The first difficulty is that I hope that the popup will not be opened until the picture is fully loaded! But I hope that when the popup is opened, the dot can add animation and run to the specified progress position, but it seems that the animation I want to appear has already run before it is opened, and the user will not see the moving animation effect. The second problem is that I want to add a green color to the rankStatus font on the screen if the rankNum is included in the rankStatus object, but I am a novice in programming and don't know which section to add to achieve this. Hope to get your help, thank you.
To solve the first difficulty, you can add an event listener to the photo element which will be triggered when the image is loaded. Inside this event listener, you can set the display of the modal to 'flex' and the display of the svg element to 'none'.
To solve the second difficulty, you can use an if statement inside your rankStatusArr loop. This statement should check if the rankNum is included in the rankStatus object and if so, add a class to the txt element which adds the green color style.
let txt = document.querySelectorAll('.txt');
for (let i = 0; i < txt.length; i++) {
txt[i].innerHTML = rankStatusArr[i];
if (rankNum === rankStatusArr[i]) {
txt[i].classList.add('green');
}
}

Auto-scroll items in navbar according to active section

Can anyone tell me how to make categories navbar like from delivery-club app?
Here is what i have already, you can check it by this link - http://testingsite.tmweb.ru/delivery/
But i can't make autoscroll items in navbar when we scroll from section to section.
I see that new web apps use front-end frameworks but i not good at it yet so i use Jquery.
I tried some stuff but it doesn't work. So some code for you guys as well, hope you can help me.
Html
!-- category navigation -->
<div class="catnav_wrap">
<nav class="catnav" data-toggle="sticky-onscroll">
<span role="button" class="catnav_item" data-scroll="pizza">
pizza
</span>
<span role="button" class="catnav_item" data-scroll="burgers">
burger
</span>
<span role="button" class="catnav_item" data-scroll="salats">
салаты
</span>
<span role="button" class="catnav_item" data-scroll="drinks">
Напитки
</span>
<span role="button" class="catnav_item" data-scroll="souce">
Соуса
</span>
<span role="button" class="catnav_item">
Другое
</span>
<span role="button" class="catnav_item">
Пицца
</span>
</nav>
</div>
<!-- category navigation -->
Jquery
$(document).ready(function(){
$('.catnav span').on('click', function() {
var scrollAnchor = $(this).attr('data-scroll'),
scrollPoint = $('section[data-anchor="' + scrollAnchor + '"]').offset().top - 70;
$('body,html').animate({
scrollTop: scrollPoint
}, 500);
return false;})
// Custom function which toggles between sticky class (is-sticky)
var stickyToggle = function (sticky, stickyWrapper, scrollElement) {
var stickyHeight = sticky.outerHeight();
var stickyTop = stickyWrapper.offset().top;
if (scrollElement.scrollTop() >= stickyTop) {
stickyWrapper.height(stickyHeight);
sticky.addClass("fixed");
}
else {
sticky.removeClass("fixed");
stickyWrapper.height('auto');
}
};
// Find all data-toggle="sticky-onscroll" elements
$('[data-toggle="sticky-onscroll"]').each(function () {
var sticky = $(this);
var stickyWrapper = $('<div>').addClass('sticky-wrapper'); // insert hidden element to maintain actual top offset on page
sticky.before(stickyWrapper);
sticky.addClass('fixed');
// Scroll & resize events
$(window).on('scroll.sticky-onscroll resize.sticky-onscroll', function () {
stickyToggle(sticky, stickyWrapper, $(this));
});
// On page load
stickyToggle(sticky, stickyWrapper, $(window));
});
$(window).scroll(function() {
var windscroll = $(window).scrollTop();
if (windscroll >= 0) {
$('.main .productscat').each(function(i) {
if ($(this).position().top <= windscroll - -80) {
$('.catnav span.active').removeClass('active');
$('.catnav span').eq(i).addClass('active');
}
});
} else {
$('.catnav span.active').removeClass('active');
$('.catnav span:first').addClass('active');
}
}).scroll();
});//Jquery
Css
/*category nav*/
.catnav_wrap{
height: 56px;
width: 100%;
}
.catnav{
height: 56px;
width: 100%;
overflow-x: auto;
background: rgb(255, 255, 255);
display: flex !important;
-webkit-box-align: center;
align-items: center;
top: 0px;
z-index: 99;
will-change: box-shadow;
transition: box-shadow 150ms ease 0s;
user-select: none;
}
.catnav::before, .catnav::after {
content: " ";
display: block;
width: 12px;
height: 56px;
flex: 0 0 auto;
}
.fixed {
position: fixed;
box-shadow: rgb(0 0 0 / 10%) 0px 2px 4px 0px;
}
.catnav_item{
display: block;
margin: 4px;
height: 32px;
color: rgb(69, 75, 84);
font-weight: 500;
font-size: 14px;
line-height: 32px;
padding: 0px 16px;
border-radius: 16px;
flex: 0 0 auto;
opacity: 0.6;
transition-property: opacity;
transition-duration: 200ms;
}
.catnav_item.active {
margin: 4px;
height: 32px;
background: rgb(243, 243, 247);
/*background: rgb(255, 240, 230);
color: rgb(186, 78, 0);*/
font-weight: 500;
font-size: 14px;
line-height: 32px;
padding: 0px 16px;
border-radius: 16px;
flex: 0 0 auto;
opacity: 1;
}
/*end category nav*/

eventListener stops working after scrolling down/changing property in javascript

I have a navigation bar. In it, I have some anchors. One of the anchors has the text 'Guides'. I want a div to appear when I hover over the anchor, and I want it to remain on the screen as long as I am hovering over the anchor. I also want the the div to remain on the screen as long as I am hovering over the div itself. All of this is working fine. When I scroll down, I decrease the size of the navigation bar and change the top position of the div. After I do this, the eventListener that I have set up to keep the div on the screen as long as I am hovering over it stops working. Please note that the div still appears when I hover over the anchor, and it remains on the screen as long as I am hovering over it.
Here's the code. The div is the one with id="dropdown-guides":
// Show dropdown on hovering over 'guides' in navigation bar
let guidesAnchor = document.querySelector('#nav-anchor-guides')
let guidesDropdown = document.querySelector('#dropdown-guides')
function showGuidesDropdown() {
guidesDropdown.style.display = 'block'
}
function hideGuidesDropDown() {
guidesDropdown.style.display = 'none'
}
guidesAnchor.addEventListener('mouseenter', showGuidesDropdown)
guidesAnchor.addEventListener('mouseleave', hideGuidesDropDown)
guidesDropdown.addEventListener('mouseenter', showGuidesDropdown)
guidesDropdown.addEventListener('mouseleave', hideGuidesDropDown)
// Show search bar on clicking search icon
let searchIcon = document.querySelector('#search-icon_anchor')
let searchBar = document.querySelector('#search-bar')
searchIcon.addEventListener('click', function() {
if (searchBar.style.display === 'none') {
searchBar.style.display = 'block'
} else {
searchBar.style.display = 'none'
}
})
// Change navigation bar on scrolling down
let navBar = document.querySelector('nav')
let mainIcon = document.querySelector('#nav-main-icon')
let navAnchors = document.querySelectorAll('nav a')
let iconDesignGuideAnchor = document.querySelector('#nav-dropdown-guides-icon-design-guide')
let pixelPerfectIconsAnchor = document.querySelector('#nav-dropdown-guides-crafting-pixel-perfect-icons')
let dribbbleAudienceAnchor = document.querySelector('#nav-dropdown-guides-build-your-dribbble-audience')
window.onscroll = () => {
if (document.body.scrollTop > 10 || document.documentElement.scrollTop > 10) {
navBar.style.height = '42px'
navBar.style.paddingTop = '10px'
navBar.style.boxShadow = '0px 0px 7px #0000001A'
mainIcon.style.top = '10px'
mainIcon.style.width = '97px'
mainIcon.style.height = '30px'
navAnchors.forEach(navAnchor => {
navAnchor.style.top = '14px'
navAnchor.style.height = '23px'
})
guidesDropdown.style.top = '42px'
searchBar.style.top = '52px'
iconDesignGuideAnchor.style.top = '65px'
pixelPerfectIconsAnchor.style.top = '108px'
dribbbleAudienceAnchor.style.top = '174px'
} else {
navBar.style.height = '80px'
navBar.style.paddingTop = '0px'
navBar.style.boxShadow = 'none'
mainIcon.style.top = '18px'
mainIcon.style.width = '139px'
mainIcon.style.height = '43px'
navAnchors.forEach(navAnchor => {
navAnchor.style.top = '28px'
navAnchor.style.height = '52px'
})
guidesDropdown.style.top = '80px'
searchBar.style.top = '80px'
iconDesignGuideAnchor.style.top = '103px'
pixelPerfectIconsAnchor.style.top = '146px'
dribbbleAudienceAnchor.style.top = '212px'
}
}
body {
margin: 0;
font-family: "Open Sans", Arial, sans-serif;
}
nav {
width: 100%;
height: 80px;
position: fixed;
border-bottom: 1px solid #E5E5E5;
z-index: 1;
background-color: #FFFFFF;
}
#nav-main-icon {
left: 135px;
top: 18px;
width: 139px;
height: 43px;
position: fixed;
}
a {
text-decoration: none;
}
nav a {
position: fixed;
top: 28px;
height: 52px;
font-family: "Open Sans", sans-serif;
font-size: 14px;
color: #666666;
}
nav a:hover {
color: #333333;
}
#nav-anchor-blog {
left: 748px;
}
#nav-anchor-guides {
left: 802px;
}
#nav-anchor-free-icons {
left: 887px;
}
#nav-anchor-free-wallpapers {
left: 979px;
}
#nav-anchor-about-me {
left: 1110px;
}
#nav-search-icon {
position: fixed;
left: 1197px;
width: 18px;
height: 17px;
font-size: 14px;
fill: #00000080;
}
#nav-search-icon:hover {
fill: #E74225;
}
.nav-dropdown {
top: 80px;
box-shadow: 0 2px 5px #0000001A;
border-top: 3px solid #E74225;
background-color: #FFFFFFFF;
display: none;
}
#dropdown-guides {
position: relative;
left: 776px;
width: 200px;
height: 175px;
padding: 20px;
z-index: 3;
}
#dropdown-guides a {
left: 796px;
width: 160px;
padding: 10px 20px;
line-height: 23px;
}
#dropdown-guides a:hover {
background-color: #00000008;
}
#nav-dropdown-guides-icon-design-guide {
top: 103px;
height: 23px;
}
#nav-dropdown-guides-crafting-pixel-perfect-icons {
top: 146px;
height: 46px;
}
#nav-dropdown-guides-build-your-dribbble-audience {
top: 212px;
height: 46px;
}
#search-bar {
position: absolute;
left: 895px;
width: 280px;
height: 35px;
padding: 20px;
z-index: 2;
}
#search-field {
left: 915px;
top: 103px;
width: 240px;
height: 15px;
padding: 10px 20px;
border: hidden;
background-color: #F8F8F8;
font-family: Arial;
font-weight: 400;
font-size: 13.3333px;
color: #757575;
}
#search-field:focus {
outline: none;
}
h1, h3, h4, p, a {
margin: 0;
font-weight: 500;
}
h1, h3, h4 {
text-align: center;
}
h1 {
font-size: 30px;
line-height: 30px;
color: #333333;
}
h3 {
font-size: 22px;
line-height: 22px;
color: #333333;
}
h4 {
font-size: 14px;
line-height: 24px;
color: #666666;
}
p {
font-size: 16px;
line-height: 27px;
color: #666666;
text-align: center;
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Main - Icon Utopia</title>
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="index-styles.css">
<link href="https://fonts.googleapis.com/css2?family=Open+Sans&display=swap" rel="stylesheet">
</head>
<body>
<header>
<nav>
<img id="nav-main-icon" src="icon-utopia.png">
<a id="nav-anchor-blog" href="blog.html">Blog</a>
<a id="nav-anchor-guides" href="www.iconutopia.com">Guides</a>
<a id="nav-anchor-free-icons" href="https://iconutopia.com/free-icons/">Free Icons</a>
<a id="nav-anchor-free-wallpapers" href="https://iconutopia.com/free-phone-wallpapers/">Free Wallpapers</a>
<a id="nav-anchor-about-me" href="https://iconutopia.com/about/">About Me</a>
<a id="search-icon_anchor"><svg id="nav-search-icon" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32.2 32.2"><path d="M19 0C11.8 0 6 5.8 6 13c0 3.1 1.1 5.9 2.9 8.2l-8.6 8.6c-0.5 0.5-0.5 1.4 0 2 0.5 0.5 1.4 0.5 2 0l8.6-8.6C13.1 24.9 15.9 26 19 26c7.2 0 13-5.8 13-13S26.2 0 19 0zM19 24C12.9 24 8 19.1 8 13S12.9 2 19 2 30 6.9 30 13 25.1 24 19 24z"/></svg></a>
<div id="dropdown-guides" class="nav-dropdown">
<a id="nav-dropdown-guides-icon-design-guide" href="free-icon-design-guide.html">Icon Design Guide</a>
<a id="nav-dropdown-guides-crafting-pixel-perfect-icons" href="crafting-pixel-perfect-icons-the-right-way.html">Crafting Pixel Perfect Icons – The Right Way!</a>
<a id="nav-dropdown-guides-build-your-dribbble-audience" href="build-your-dribbble-audience.html">Build your Dribbble audience</a>
</div>
<div id="search-bar" class="nav-dropdown">
<form id="search-form">
<input id="search-field" type="text" placeholder="Search ...">
</form>
</div>
</nav>
</header>
</body>
<script src="nav.js"></script>
</html>
Please note that since the top set in CSS for the div is originally 80px, if I remove the code for changing the top of the div, after scrolling down, I can't reach it if I am hovering over the anchor, before it disappears. That's why I was not able to tell whether the eventListener stopped working because I scrolled down, or because I changed the top of the div.
I figured out the problem. In my javascript, I was setting the height of each navAnchor to fit only the text of the anchor. That's why the dropdown disappeared before I could hover over it. So I increased the height to extend the anchors to reach the bottom of the navigation bar. (I increased the height from 23px to 39px)

Compounding Value within an object used to slide dot across the page incrementally

I am unable to get a variable to function properly as the translateX value within my object. I am wanting to make the dot scroll across the page each time the next button is clicked. My code is only able to move it back and forth for the first step.
I am new to the animation API, and I have already made this work with CSS transitions but I am trying to get a good handle on the API.
html:
<div class="progress__container">
<div class="progress__bar">
<div id="progress__fill" class="step1"></div>
<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 id="progress__dot" class="prog__1"></div>
</div>
<div class="backBar"></div>
<div class="flexrow">
<span class="stepName">Account</span>
<span class="stepName">Frequency</span>
<span class="stepName">Amount</span>
<span class="stepName">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>
js:
// give a starting value for the transformation
var startVal = 0;
// define the keyframes
var moveDot = [
{ transform: `translateX(${startVal}px)`},
{ transform: `translateX(${startVal + 190}px)`}
];
// definte the timing
var dotTiming = {
duration: 400,
fill: "forwards",
easing: 'ease-in',
}
// make the animation happen
var movingDot = document.getElementById("progress__dot").animate(
moveDot,
dotTiming
);
// pause the animation until called
movingDot.pause();
// on click fire the animation
document.getElementById('next').addEventListener('click', function() {
movingDot.playbackRate = 1;
if (startVal <= 380) {
movingDot.play();
startVal += 190;
}
});
document.getElementById('back').addEventListener('click', function() {
movingDot.playbackRate = -1;
if (startVal >= 0) {
movingDot.play();
startVal -= 190;
}
});
css:
#progress__fill {
height:2px;
position: absolute;
top: 7px;
left: 0;
background-color: darkred;
}
#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: 12px;
width: 12px;
display: inline-block;
}
#circ__2, #circ__3 {
margin-left: 30%
}
#circ__4 {
float: right;
}
.passed {
background-color: darkred;
border: 2px solid darkred;
}
.hide {
visibility: hidden
}
.flexrow {
display: flex;
flex-direction: row;
justify-content: space-between;
}
/* Buttons */
.buttonStep {
background: grey;
color: #fff;
padding: 10px 25px;
border-radius: 10px;
font-size: 16px;
}
#back {
float: left;
}
#next {
float: right;
}
.is-active {
background: darkred;
}
The way I have it set up, I expect for the translateX values to increment or decrement depending on the click event listeners which would make the circle slide across the page. What is actually happening is that only the first step works. it will not go past the first stop point. If I log moveDot in the console it gives me the values that I am expecting, but it will only start/stop at 0 and 190. the back button functions the same way. link to fiddle
It is animated from and to the same place every time. Move the definition of moveDot into the event listener:
// give a starting value for the transformation
var startVal = 0;
// definte the timing
var dotTiming = {
duration: 400,
fill: "forwards",
easing: 'ease-in',
}
// on click fire the animation
document.getElementById('next').addEventListener('click', function() {
if (startVal > 380){return;}
// define the keyframes
var moveDot = [{transform: `translateX(${startVal}px)`},
{transform: `translateX(${startVal + 190}px)`}];
// make the animation happen
var movingDot = document.getElementById("progress__dot").animate(
moveDot,
dotTiming
);
movingDot.playbackRate = 1;
movingDot.play();
startVal += 190;
});
document.getElementById('back').addEventListener('click', function() {
movingDot.playbackRate = -1;
if (startVal >= 0) {
movingDot.play();
startVal -= 190;
}
});

build semi circle progress bar with round corners and shadow in java script and CSS

I searched a lot and finding nothing on it. I want to make a progress bar with round corners.progress bar need to have shadow. All I did as of now is here :
$(".progress-bar").each(function(){
var bar = $(this).find(".bar");
var val = $(this).find("span");
var per = parseInt( val.text(), 10);
$({p:0}).animate({p:per}, {
duration: 3000,
easing: "swing",
step: function(p) {
bar.css({
transform: "rotate("+ (45+(p*1.8)) +"deg)"
});
val.text(p|0);
}
});
});
body{
background-color:#3F63D3;
}
.progress-bar{
position: relative;
margin: 4px;
float:left;
text-align: center;
}
.barOverflow{
position: relative;
overflow: hidden;
width: 150px; height: 70px;
margin-bottom: -14px;
}
.bar{
position: absolute;
top: 0; left: 0;
width: 150px; height: 150px;
border-radius: 50%;
box-sizing: border-box;
border: 15px solid gray;
border-bottom-color: white;
border-right-color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="progress-bar">
<div class="barOverflow">
<div class="bar"></div>
</div>
<span>100</span>%
</div>
I want to make corners round and having shadow. below given image represent what actually i want. Shadow is missing because i don't know to draw. :
I have tried Progressbar.js also, but I don't have much knowledge about SVG. Any answer would be appreciated.
#jaromanda for suggestion of learning SVG.
Yes is looks very hard to achieve from border-radius. So i looked into SVG and find it pretty handy. Here is my snippet:
// progressbar.js#1.0.0 version is used
// Docs: http://progressbarjs.readthedocs.org/en/1.0.0/
var bar = new ProgressBar.SemiCircle(container, {
strokeWidth: 10,
color: 'red',
trailColor: '#eee',
trailWidth: 10,
easing: 'easeInOut',
duration: 1400,
svgStyle: null,
text: {
value: '',
alignToBottom: false
},
// Set default step function for all animate calls
step: (state, bar) => {
bar.path.setAttribute('stroke', state.color);
var value = Math.round(bar.value() * 100);
if (value === 0) {
bar.setText('');
} else {
bar.setText(value+"%");
}
bar.text.style.color = state.color;
}
});
bar.text.style.fontFamily = '"Raleway", Helvetica, sans-serif';
bar.text.style.fontSize = '2rem';
bar.animate(0.45); // Number from 0.0 to 1.0
#container {
width: 200px;
height: 100px;
}
svg {
height: 120px;
width: 200px;
fill: none;
stroke: red;
stroke-width: 10;
stroke-linecap: round;
-webkit-filter: drop-shadow( -3px -2px 5px gray );
filter: drop-shadow( -3px -2px 5px gray );
}
<script src="https://rawgit.com/kimmobrunfeldt/progressbar.js/1.0.0/dist/progressbar.js"></script>
<link href="https://fonts.googleapis.com/css?family=Raleway:400,300,600,800,900" rel="stylesheet" type="text/css">
<div id="container"></div>
I want to suggest some stupid but quick solution since you're already using position: absolute. You can add background color to the circles when your animation starts.
html:
<div class="progress-bar">
<div class="left"></div>
<div class="right"><div class="back"></div></div>
<div class="barOverflow">
<div class="bar"></div>
</div>
<span>0</span>%
</div>
css:
/** all your css here **/
body{
background-color:#3F63D3;
}
.progress-bar{
position: relative;
margin: 4px;
float: left;
text-align: center;
}
.barOverflow{
position: relative;
overflow: hidden;
width: 150px; height: 70px;
margin-bottom: -14px;
}
.bar{
position: absolute;
top: 0; left: 0;
width: 150px; height: 150px;
border-radius: 50%;
box-sizing: border-box;
border: 15px solid gray;
border-bottom-color: white;
border-right-color: white;
transform: rotate(45deg);
}
.progress-bar > .left {
position: absolute;
background: white;
width: 15px;
height: 15px;
border-radius: 50%;
left: 0;
bottom: -4px;
overflow: hidden;
}
.progress-bar > .right {
position: absolute;
background: white;
width: 15px;
height: 15px;
border-radius: 50%;
right: 0;
bottom: -4px;
overflow: hidden;
}
.back {
width: 15px;
height: 15px;
background: gray;
position: absolute;
}
jquery:
$(".progress-bar").each(function(){
var bar = $(this).find(".bar");
var val = $(this).find("span");
var per = parseInt( val.text(), 10);
var $right = $('.right');
var $back = $('.back');
$({p:0}).animate({p:per}, {
duration: 3000,
step: function(p) {
bar.css({
transform: "rotate("+ (45+(p*1.8)) +"deg)"
});
val.text(p|0);
}
}).delay( 200 );
if (per == 100) {
$back.delay( 2600 ).animate({'top': '18px'}, 200 );
}
if (per == 0) {
$('.left').css('background', 'gray');
}
});
https://jsfiddle.net/y86qs0a9/7/
Same as the answers above, I found it much easier to implement using SVG instead of pure CSS.
However I couldn't find a single simplistic implementation using only HTML and CSS, or at least with no libraries, no external scripts or no dependencies. I found that given the math that needs to be calculated to make the SVG transformations to represent the percentage, JS needs to be included (if someone knows how to achieve this with only HTML and CSS I'd love to learn how). But what the JS script does is not long or complex enough to justify the overhead of adding yet another dependency to my codebase.
The JS calculations are pretty easy once you read through. You need to calculate the coordinate for the end point of the gauge in the coordinate system of the SVG. so basic trig.
Most of the CSS is not even needed and I added just to style it and to make it pretty. You can add shadow or gradients same as you could with any HTML pure shape.
Here is the codePen https://codepen.io/naticaceres/pen/QWQeyGX
You can easily tinker with this code to achieve any kind of shape of circular gauge (full circle, lower half of the semi-circle, or any variation including ellipsis).
Hope this is helpful.
// # Thanks to mxle for the first rounded corner CSS only solution https://stackoverflow.com/a/42478006/4709712
// # Thanks to Aniket Naik for the styling and the basic idea and implementation https://codepen.io/naikus/pen/BzZoLL
// - Aniket Naik has a library, linked to that codepen you should check out if you don't want to copy-paste or implement yourself
// the arc radius in the meter-value needs to stay the same, and must always be x=y, not lower than the possible circle that can connect the two points (otherwise the ratio is not preserved and the curvature doesn't match the background path).
// to style the gauge, make it bigger or smaller, play with its parent element and transform scale. don't edit width and height of SVG directly
function percentageInRadians(percentage) {
return percentage * (Math.PI / 100);
}
function setGaugeValue(gaugeElement, percentage, color) {
const gaugeRadius = 65;
const startingY = 70;
const startingX = 10;
const zeroBasedY = gaugeRadius * Math.sin(percentageInRadians(percentage));
const y = -zeroBasedY + startingY;
const zeroBasedX = gaugeRadius * Math.cos(percentageInRadians(percentage));
const x = -zeroBasedX + gaugeRadius + startingX;
// # uncomment this to log the calculations of the coordinates for the final point of the gauge value path.
//console.log(
// `percentage: ${percentage}, zeroBasedY: ${zeroBasedY}, y: ${y}, zeroBasedX: ${zeroBasedX}, x: ${x}`
//);
gaugeElement.innerHTML = `<path d="M ${startingX} ${startingY}
A ${gaugeRadius} ${gaugeRadius} 0 0 1 ${x} ${y}
" stroke="${color}" stroke-width="10" stroke-linecap="round" />`;
}
percentageChangedEvent = (gauge, newPercentage, color) => {
const percentage =
newPercentage > 100 ? 100 : newPercentage < 0 ? 0 : newPercentage;
setGaugeValue(gauge, percentage, color);
};
function initialGaugeSetup(gaugeElementId, inputId, meterColor, initialValue) {
const gaugeElement = document.getElementById(gaugeElementId);
setGaugeValue(gaugeElement, 0, meterColor);
const inputElement = document.getElementById(inputId);
inputElement.value = initialValue;
setGaugeValue(gaugeElement, initialValue, meterColor);
inputElement.addEventListener("change", (event) =>
percentageChangedEvent(gaugeElement, event.target.value, meterColor)
);
}
// Gauge Initial Config
initialGaugeSetup(
"svg-graph-meter-value",
"svg-gauge-percentage-2",
"rgb(227 127 215)",
40
);
body {
background-color: rgba(0, 0, 0, 0.8);
color: #999;
font-family: Hevletica, sans-serif;
}
/* SVG Path implementation */
.svg-container {
margin: 20px auto 10px;
height: 80px;
width: 150px;
}
svg {
fill: transparent;
}
.input-percent-container {
text-align: center;
}
.input-percent-container>* {
display: inline;
}
input {
text-align: right;
width: 40px;
margin: auto;
background-color: #5d5d5d;
color: white;
border-radius: 6px;
border: black;
}
<div class="svg-container">
<svg width="150" height="80" xmlns="http://www.w3.org/2000/svg">
<path d="M 10 70
A 65 65 0 1 1 140 70
" stroke="grey" stroke-width="3" stroke-linecap="round" />
<g id="svg-graph-meter-value">
</g>
</svg>
</div>
<div class="input-percent-container"><input id="svg-gauge-percentage-2" /><span>%<span/></div>

Categories

Resources