Working on a scroll bar that will be vertical and as we scroll down the brown bit will not fill up but move bit by bit depending on how far we scroll down. So esentially the brown bit will move three times down if we scroll to the bottom. So far I made a scroll bar that fills up but ideally I would like it to have the movable brown bit like in the example in the attached picture. Anyone able to help out?
My code so far looks like this:
window.onscroll = () => {
var winScroll = document.body.scrollTop || document.documentElement.scrollTop;
var height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
var scrolled = (winScroll / height) * 100;
document.getElementsByClassName("scroll-bar__inner")[0].style.height = scrolled + "%";
};
.scroll-bar {
position: fixed;
top: 50%;
right: 34px;
width: 2.5px;
height: 80px;
background-color: #959595;
display: block;
transform: translateY(-50%);
}
.scroll-bar__inner:first-of-type {
height: 20%;
background: #ffffff;
}
.scroll-bar__inner:nth-of-type(2) {
/* height: 20%; */
background: #ffffff;
}
#mock-content {
width: 150px;
height: 500px;
border: 3px solid red;
border-radius: 5px;
}
<div class="scroll-bar">
<div class="scroll-bar__inner"></div>
</div>
<div id="mock-content">
This div represents some content that causes the body to scroll.
</div>
It was a bit confusing what you were trying to do with your original CSS. I couldn't see why you would alter the height of the container for the scroll bar, instead of just repositioning the block within a full heigh container (i.e. .scroll-bar__inner). In any case here is a snippet that I think accomplishes what you're trying to do:
window.onscroll = () => {
var winScroll = document.body.scrollTop || document.documentElement.scrollTop;
var height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
var containerHeight = document.getElementsByClassName("scroll-bar")[0].clientHeight;
// range from 0 to x% where x% is 100% - (80 / scroll bar height * 100)
// This makes it so the bar doesn't extend off the page.
var scrolled = (winScroll / height) * ((containerHeight - 80) / containerHeight) * 100;
document.getElementsByClassName("scroll-bar__inner")[0].style.top = scrolled + '%';
};
.scroll-bar {
position: fixed;
top: 0;
bottom: 0;
right: 34px;
width: 5px;
background-color: whitesmoke;
}
.scroll-bar__inner {
height: 80px;
background: #333;
position: relative;
}
#mock-content {
width: 150px;
height: 500px;
border: 3px solid red;
border-radius: 5px;
}
<div class="scroll-bar">
<div class="scroll-bar__inner"></div>
</div>
<div id="mock-content">
This div represents some content that causes the body to scroll.
</div>
Related
As you can see from my code, the progress bar doesn't increase by even units. I need the container to remain responsive but the progress bar to increase by even units.
function increaseProgress() {
var progressBar = document.querySelector(".progress-bar")
var currWidth = progressBar.clientWidth;
progressBar.style.width = currWidth + 10 + "%";
}
.progress-container {
width: 100%;
height: 20px;
outline: solid 2px #ccc;
border-radius: 20px;
}
.progress-bar {
width: 0;
height: inherit;
background: blue;
border-radius: 20px;
}
<div class="progress-container">
<div class="progress-bar"></div>
</div>
<button onclick="increaseProgress()">Click to increase</button>
#evolutionxbox makes a good suggestion in the comments. It is far more flexible than this manual approach you're taking.
However, if you are still looking for a fix for your current code, here is one:
First, you need to find out how much the total container width is. In other words, finding out how much "10 percent" is.
Once you find that out, you can simply increase the current bar width by a tenth the container width. We also want to prevent it from increasing beyond 100%.
function increaseProgress() {
var progressBar = document.querySelector(".progress-bar")
var progressContainer = document.querySelector(".progress-container")
var barWidth = progressBar.clientWidth;
var containerWidth = progressContainer.clientWidth;
if (barWidth >= containerWidth) return;
progressBar.style.width = (barWidth + containerWidth / 10) + "px";
}
.progress-container {
width: 100%;
height: 20px;
outline: solid 2px #ccc;
border-radius: 20px;
}
.progress-bar {
width: 0;
height: inherit;
background: blue;
border-radius: 20px;
}
<div class="progress-container">
<div class="progress-bar"></div>
</div>
<button onclick="increaseProgress()">Click to increase</button>
I am trying to make a sticky banner witn html and css and js. My html is this
window.addEventListener('scroll', function(ev) {
var distanceToTop = container.getBoundingClientRect().top;
if (container.getBoundingClientRect().top >= document.documentElement.scrollTop - screen.height + 400) {
sticky.style.top = "100px"
} else {
sticky.style.top = document.documentElement.scrollTop - screen.height + 400 + "px";
}
});
.container {
background: red;
width: 600px;
height: 100px;
position: relative;
}
.sticky {
background: blue;
width: 200px;
height: 200px;
position: absolute;
right: 0;
top: 100px;
}
<div class="container">
<div class="sticky"></div>
</div>
I would want when i scroll the window the stocky div to be center on y axis and when the distance between container and top of the page is less then 200px the two divs to be attached.
Can anyone to give me a clue?
Hey guys I’m trying to make simple point & click game, in background will be some nice landscape which will be moved by arrows on the left and right (same like slider works), I want object to move only within the lower div (#boxMap), I tried to build contructor to main object but together with friend who helps me, we wrote it in way below. The problem is that this object still doesn’t move how it should be, idea is that when game starts, and when I click right arrow, object appears on the left, if I click left arrow object appears on the left side of the div. When I click the mouse, object should moves to position I clicked. I’m kinda desperate as I have ideas how to make It work later but I totally cannot manage this positioning and movement of the object.
I found some nice yt tutorial about moving objects and tried to set statements to move only within the div without getting outside the edge, unfortunately now it moves only on the bottom edge of div.
So I created new object with class .hero inside the boxMap, and set it’s starting position with css properties, then with function getClickPosition I try to manage it’s movement, I try also set that if object is clicked outside the frame of div, it set it’s position on particular value. Unfortunately now it moves only through the bottom edge, right side it doesn’t exceed the edge, left side it does.
Hope I was able to more or less explain what I try to achieve and what I have already done.
Any idea how to set position and some simple movement in much simpler way?
I would be grateful for any tips
HTML
<body>
<div id="emptySpace">
<span class="left"></span>
<span class="right"></span>
</div>
<div id="boxMap">
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="js/app.js"></script>
</body>
CSS
body {
margin: 0;
padding: 0;
background-color: antiquewhite;
#emptySpace {
width: 100%;
height: 70vh;
background-color: azure;
position: relative;
.left {
position: absolute;
left: 10px;
top: 40vh;
border-top: 40px solid transparent;
border-bottom: 40px solid transparent;
border-right:40px solid blue;
//display: none;
}
.right {
position: absolute;
right: 10px;
top: 40vh;
border-top: 40px solid transparent;
border-bottom: 40px solid transparent;
border-left: 40px solid green;
//display: none;
}
}
#boxMap {
width: 100%;
height: 30vh;
border: 1px solid black;
background-color: #d8fffa;
position: relative;
.hero {
position: absolute;
width: 50px;
height: 50px;
display: inline-block;
border: 1px solid black;
border-radius: 50%;
background-color: blue;
transform: translate3d(0px, -45px, 0);
transition: 2s linear;
}
}
}
Javascript
function Game() {
this.hero = new Hero();
this.counter = 0;
var self = this;
this.boxMap = document.querySelector("#boxMap");
// Placing hero on the map
this.showHero = function () {
var heroElement = document.createElement('div');
heroElement.classList.add('hero');
console.log(self, self.boxMap);
self.boxMap.appendChild(heroElement);
$(heroElement).css({top: 130, left: 30})
}
}
var game = new Game();
game.showHero();
var heroMovement = document.querySelector(".hero");
var boxMap = document.querySelector("#boxMap");
boxMap.addEventListener("click", getClickPosition, false);
// Set position on hero and set movement
function getClickPosition(e) {
var xPosition = e.clientX;
var maxWidth = 1350;
var minWidth = -20;
if (xPosition < minWidth) {
xPosition = minWidth;
} else if (xPosition > maxWidth) {
xPosition = maxWidth
} else {
var xPosition = e.clientX - (heroMovement.offsetWidth + 3);
}
var yPosition = e.clientY;
var maxHeight = 60;
var minHeight = -130;
if (yPosition < minHeight) {
yPosition = minHeight;
} else if (yPosition > maxHeight) {
yPosition = maxHeight
} else {
var yPosition = e.clientY - (heroMovement.offsetHeight + 558);
}
console.log(xPosition, yPosition);
var translate3dValue = "translate3d(" + xPosition + "px" + "," + yPosition + "px, 0)";
console.log(translate3dValue);
heroMovement.style.transform = translate3dValue;
}
I'm trying to make a chart like this using JS, HTML and CSS only:
It must have all the things labels, colors and start from 0%. The value is based on user score from quiz in %. When a user gets 5/10 points, the value is 50%. If the user gets -5/10 points, the value is -50%.
This code is the last idea i had, but the negative value didn't show and it wasn't starting at 0% (center div). Also it was changing the width so the center div wasn`t in the center.
if (successRate > 0) {
plus.style.width = (successRate / 100) * 300 + "px";
minus.style.display = "hidden";
} else if (successRate < 0) {
minus.style.width = (successRate / 100) * 300 + "px";
plus.style.display = "hiden";
}
#chart {
display: table;
border: 1px solid black;
}
#chart>* {
height: 30px;
}
#left {
height: 29px;
background: red;
display: table-cell;
}
#center {
max-width: 1px !important;
background: #000;
display: table-cell;
}
#right {
height: 29px;
background: green;
display: table-cell;
}
#container {
width: 600px;
border: 1px solid black;
}
<section id="chart">
<div id="container">
<div id="left"> </div>
<div id="center"> </div>
<div id="right"> </div>
</div>
</section>
Note: In practical use, you need to change just two things in
javascript to make it work for your implementation.
First: var successRate = document.getElementById("rate").value; We're giving values using this
text input, but you can pass your value to successRate in anyway you
desire.
Second: You can change the maxRate which is set to 10 in the code(then use values between -10 and 10) to whatever value you desire
and it will compute the percentage width of the progress bar respect
to that value.
That's it!
You can make use of the following implementation, it is simple and yet effective for varying values.
We're making use of a center div , a bar div which will propagate and change color depending on the successrate and a percent container which dynamically displays the percentage below the bar.
By default we're positioning the center div in center with absolute positioning and bar at the left:50% with top:0 with relation to container having relative positioning.
Now how the does the javascript work?
We're obtaining the rate in a textbox and saving it in successRate and we're using bar as the variable to manipulate the progress bar.
We have set the maximum marks for this 10, in maxrate which can be changed making it flexible.
Then, using if/else condition we can compare when the value entered is positive or negative. If positive or negative we've cooked up a formula to increase % width in that direction.
We're making use of var prograte = (100*Math.abs(successRate))/(2*maxrate); to calculate the width of our progress bar ( the abs method incase the successrate is negative).
Eg, If score is 10/10 then 10 is the success rate and 10 is the max
rate. Using the formula:
prograte = (100*successRate)/(2*maxrate)
We obtain, prograte = 100*10 / 2*10 = 50% thus giving it 50% width from the center. If score is 2/10 we obtain,
100*2/2*10 = 10% of the width.
When successrate > 0, we're starting from the center to the right. So, we move the left to 50%.
And using the above computed value of forward we increase the width of bar to that and change the color to green.
But when the successrate < 0 (i.e the else condition we multiply it by -1 to get the absolute value of the width) then, we compute on how much further we have to move from the left using (50% - prograte) that we compute, which puts it to the right side of the center bar.
Eg, If score is -5/10 then -5 is the success rate and 10 is the max
rate. Using the formula:
prograte = (100*successRate*(-1))/(2*maxrate)
We obtain, prograte = 100*5 / 2*10 = 25% and using (50%-prograte) we obtain 25%. So, we move to 25% from the left and set the width to 25% which makes it look like its in the center decreasing backwards.
To display the percentage when the flag!=1 (which identifies if the limit for the value has been crossed), we make use of:
var percent = document.getElementById("percent");
percent.style.left = "percentage %";
percent.style.color = "color";
percent.innerHTML = prograte * 2 + "%";
function changerate() {
var successRate = document.getElementById("rate").value;
var bar = document.getElementById("bar");
var flag = 0;
var percent = document.getElementById("percent");
var maxrate = 10;
var prograte = (100 * Math.abs(successRate)) / (2 * maxrate);
if (successRate >= 0 && successRate <= maxrate) {
bar.style.left = "50%";
bar.style.background = "green";
bar.style.width = prograte + "%";
} else if (successRate < 0 && (-1 * maxrate) <= successRate) {
bar.style.background = "red";
bar.style.width = prograte + "%";
bar.style.left = (50 - prograte) + "%";
} else {
alert("Limit crossed");
bar.style.left = "50%";
bar.style.width = "0%";
flag = 1;
}
if (flag != 1) {
if (successRate > 0) {
percent.style.left = 50 + prograte + "%";
percent.style.color = "green";
} else {
percent.style.left = 50 - prograte + "%";
percent.style.color = "red";
}
percent.innerHTML = prograte * 2 + "%";
} else {
percent.style.left = prograte + "%";
percent.innerHTML = "";
}
}
#chart {
width: 500px;
position: relative;
}
#container {
height: 29px;
border: 2px solid black;
position: relative;
}
#percent {
height: 30px;
position: absolute;
top: 35px;
left: 50%;
font-weight:bold;
transition: all 0.5s ease-in-out;
}
#bar {
height: 100%;
background: red;
z-index: 1;
position: absolute;
top: 0;
left: 50%;
width: 0px;
transition: all 0.5s ease-in-out;
}
#center {
height: 100%;
max-width: 2px !important;
background: #000;
position: absolute;
left: 50%;
top: 0;
transform: translate(-50%);
z-index: 2;
}
Current max value : (10 which can be modified in javascript in maxrate)
<br><br> Input values between -10 and 10 : <br>
<input type="text" id="rate" />
<input type="button" value="update" onclick="changerate()" />
<section id="chart">
<div id="container">
<div id="bar"></div>
<div id="center"> </div>
</div>
<div id="percent"></div>
</section>
My solution, which certainly can be improved upon is as follows:
Create two container DIVs each containing one child DIV:
<div class="container" id="c1">
<div class="bar" id="contra">
</div>
</div>
<div class="container" id="c2">
<div class="bar" id="pro">
</div>
</div>
Assign them basic CSS properties, such as positioning and border:
.container {
background-color: transparent;
height: 50px;
width: 200px;
}
#c1 {
top: 0px;
left: 0px;
position: absolute;
border: 3px solid;
}
#c2 {
top: 0px;
left: 200px;
position: absolute;
border: 3px solid;
}
#pro {
top: 0px;
left: 0px;
position: absolute;
background-color: green;
width: 30px;
height: 30px;
z-index: -9999;
}
#contra {
top: 0px;
left: 50px;
position: absolute;
background-color: red;
width: 150px;
height: 30px;
z-index: -9999;
}
Now you already have all you need in terms of HTML/CSS. You have two DIVs that serve as containers and provide the black borders as shown in your image. You also have two bars inside those containers, each representing the percentage you want to display.
Obviously they would never be displayed as set with my demo-CSS-properties. As long as nothing has happened they should have zero width or be invisible and of course the bar-DIVs would never have a width above zero both at the same time.
Anyway, the dynamic part comes then with JavaScript:
var proBar = document.getElementById('pro');
var contraBar = document.getElementById('contra');
// ... do your quiz stuff and get the percentage from there
// ... calculate from the max-width of your container the position and
width of the respective bar
var result = 70; // <-- your calculations go here
proBar.setAttribute("style","width:" + result + "px")
console.log("Done.");
The bars are what you want to be dynamic here. So you can set their width to zero in the CSS properties and dynamically assign width and positioning.
So for example your container has a width, which is now the max-width of the child-bar. You get your positive or negative percentage value fro myour quiz and then calculate the width the bar should have from the percentage of the max-width. Example: Your max-width is 200px, because that is the width of the container-DIVs. Your percentage you got from your quiz is 50 percent. Thus the width of the pro bar is 100px and the width of the contra bar is zero, since the percentage value is larger than zero.
For the contra bar you would have to also calculate the left position, not just width. You can get the width from the percentage as described above and then the value of left can be described by subtracting the calculated width from max-width.
You can figure out how to do that and how to calculate the percentage. It's rather simple, but this is obviously an assignment and you should do some work yourself.
You can see the manipulation of "pro" by changing the value of result. All this should be more than plenty to solve the problem you are having. Please give some feedback when you're done.
var proBar = document.getElementById('pro');
var contraBar = document.getElementById('contra');
// ... do your quiz stuff and get the percentage from there
// ... calculate from the max-width of your container the position and width of the respective bar
var result = 70; // <-- your calculations go here
proBar.setAttribute("style","width:" + result + "px")
console.log("Done.");
.container {
background-color: transparent;
height: 50px;
width: 200px;
}
#c1 {
top: 0px;
left: 0px;
position: absolute;
border: 3px solid;
}
#c2 {
top: 0px;
left: 200px;
position: absolute;
border: 3px solid;
}
#pro {
top: 0px;
left: 0px;
position: absolute;
background-color: green;
width: 30px;
height: 50px;
z-index: -9999;
}
#contra {
top: 0px;
left: 50px;
position: absolute;
background-color: red;
width: 150px;
height: 50px;
z-index: -9999;
}
<div class="container" id="c1">
<div class="bar" id="contra">
</div>
</div>
<div class="container" id="c2">
<div class="bar" id="pro">
</div>
</div>
Another variant with less elements.
function calculate(input) {
var chart = document.getElementById('chart');
var bar = document.getElementById('bar');
var width = Math.abs(input.value) * (chart.clientWidth / 2) / 10;
bar.style.width = width + 'px';
if (input.value >= 0) {
bar.style.left = chart.clientWidth / 2 + 'px';
bar.style.background = 'green';
} else if (input.value < 0) {
bar.style.left = chart.clientWidth / 2 - width + 'px';
bar.style.background = 'red';
}
}
#chart {
border: 1px solid black;
height: 30px;
margin-top: 10px;
overflow: hidden;
position: relative;
}
#chart:after {
border-right: 1px solid black;
content: '';
display: block;
height: 30px;
left: 50%;
position: absolute;
top: 0;
}
#bar {
height: 30px;
position: absolute;
top: 0;
}
<input type="number" value="0" min="-10" max="10" onchange="calculate(this)">
<section id="chart">
<div id="bar"></div>
</section>
My code allows scrolling vertically in the bottom section to control scrolling horizontally in the top section.
My jsfiddle
You'll see the colors shift through a gradient. Works pretty well. Problem is that I can't quite seem to get the inverse to work. Scrolling horizontally in the top controls scrolling in the bottom.
Any ideas?
Here's the script that makes it work:
// Add event listener for scrolling
$("#bottom").on("scroll", function bottomScroll() {
var scrolledleft = parseInt($("#bottom").scrollTop()) * 1;
console.log(scrolledleft + scrolledright)
$("#top").scrollLeft(scrolledleft + scrolledright)
})
//Move right column to bottom initially
$("#top").scrollLeft($("#top").height())
//Get actual distance scrolled
var scrolledright = parseInt($("#top").scrollLeft())
Your event handlers need to temporarily cancel each other so that they don't both fire at once. You want to calculate your position percentage based on the current scrollLeft / (width of child div - width of container), then apply that percentage to the other element, and likewise for top/height. Also I changed the height of #top to 50% in CSS.
var handler = function (e) {
var src = e.target;
// the first element that triggers this function becomes the active one, until it's done
if (!activeScroller) activeScroller = src.id;
else if (activeScroller != src.id) return;
var $b = $("#bottom");
var $t = $("#top");
var scrollH = $("#bottom-content").height() - $b.height();
var scrollW = $("#top-content").width() - $t.width();
var scrollPct = 0;
if (src.id == "top") {
if (scrollW > 0) {
scrollPct = $t.scrollLeft() / scrollW;
}
$b.scrollTop(scrollH * scrollPct);
} else {
if (scrollH > 0) {
scrollPct = $b.scrollTop() / scrollH;
}
$t.scrollLeft(scrollW * scrollPct);
}
// give all animations a chance to finish
setTimeout(function () { activeScroller = ""; }, 100);
};
var activeScroller = "";
$("#top,#bottom").on("scroll", handler);
#top {
position: absolute;
margin: auto;
top: 0;
right: 0;
left: 0;
width: 100%;
height: 50%;
position: fixed;
overflow: auto;
background: red;
}
#top-content {
height: 100%;
width: 2000px;
background: linear-gradient(90deg, red, blue);
}
#bottom {
position: absolute;
margin: auto;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 50%;
position: fixed;
overflow: auto;
background: green;
z-index: 100;
}
#bottom-content {
height: 2000px;
width: 100%;
background: linear-gradient(0deg, orange, green);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="top">
<div id="top-content"></div>
</div>
<div id="bottom">
<div id="bottom-content"></div>
</div>
Check out this:
https://jsfiddle.net/1p7gp72h/1/
I'm not sure what your end goal is here.
$("#top").on("scroll", function topScroll() {
var scrolledleft = parseInt($("#top").scrollTop()) * 1;
$("#bottom").scrollLeft(scrolledleft + scrolledright)
});
#top {
top: 0;
right: 0;
left: 0;
width: 5000px;
height: 100%;
overflow: auto;
background: red;
overflow-x: scroll;
overflow-y: hidden;
white-space:nowrap;
}
Scroll to left ::
$('div').scrollLeft(1000);
Scroll back to normal/ scroll to right ::
$('div.slick-viewport').scrollLeft(-1000);