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>
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'm trying to create the below picture using CSS and javascript.
I'm successfully creating the semi-circle, but I have no idea how I can align the different line bars around the circumference of the circle. I pray to the CSS gods some of you can help me in my quest.
This is the code I have so far
.roll-degrees{
position: absolute;
top: 0px;
z-index: 1;
}
.roll-curve{
width:400px;
height:120px;
border:solid 3px #000;
border-color: black transparent transparent transparent;
border-radius: 50%/120px 120px 0px 0;
}
<div class="roll-degrees">
<div class="roll-curve"></div>
</div>
Updated based on the answer: Now I'm trying to display the arrow at the bottom of the circle. Code below. Is it possible I need to add/subtract the dimensions of the arrow?
.roll-degrees-arrow{
--width: 3px;
--height: 16px;
position: absolute;
width: 0;
height: 0;
border-left: 15px solid transparent;
border-right: 15px solid transparent;
border-bottom: 25px solid white;
z-index: 1;
--arrow-angle-direction: 1; /* default towards right*/
top: calc(50% - var(--height));
left: calc(50% - var(--width) / 2);
transform:
rotate(calc(var(--arrow-angle-direction) * var(--arrow-angle)))
translateY(calc(-1 * var(--circle-radius)))
;
}
<div class="roll-degrees-wrapper">
<div class="roll-degrees">
<div class="roll-degrees-arrow"></div>
...
</div>
</div>
Initial Setup
First, it's easier to do the math using a proper circle rather than an oval, so let's make the roll-curve element a circle (then we can crop the rest using a container). I've also added an additional wrapper around the whole thing that can be used to cut the size, while the original wrapper (roll-degrees) will be the appropriate size for the full circle in order to make tick positioning easier.
Ticks
Then the approach is to control the exact location of each tick by applying absolute positioning (starting at the circle's center) and moving the tick using transform: translateY(). Center all of the ticks in the middle of the roll-curve circle, rotate each, and translate each out to the perimeter of the circle from there. By rotating first, we can just translate each tick up by the radius of the circle and "up" will be in the appropriate direction.
Marker
As for setting the position of the marker dynamically, you can use largely the same approach as for the ticks (using the same CSS styling). You'll just need a way of translating a value to an angle (which can be done fairly simply---see the example below for details) and an angle direction.
The example below includes a range input, but you can provide a value to the marker any way you like.
Example
const minValue = 0;
const maxValue = 100;
function getAngleForValue(value) {
const angleRange = 90;
const angleCenter = angleRange / 2;
return value / maxValue * angleRange - angleCenter;
}
const marker = document.querySelector("#marker");
function setMarkerPosition(value) {
const angle = getAngleForValue(value);
const absAngle = Math.abs(angle);
const angleDirection = Math.sign(angle);
marker.style.setProperty("--tick-angle", `${absAngle}deg`);
marker.style.setProperty("--tick-angle-direction", angleDirection);
}
const markerRangeInput = document.querySelector("#marker-range-input");
markerRangeInput.min = minValue;
markerRangeInput.max = maxValue;
markerRangeInput.value = (maxValue - minValue) / 2;
markerRangeInput.addEventListener("change", (event) => {
setMarkerPosition(event.target.value)
})
* {
box-sizing: border-box;
}
body {
background-color: blue;
}
.roll-degrees-wrapper {
--circle-radius: 200px;
height: calc(var(--circle-radius) / 2);
position: relative;
overflow: hidden;
--tick-1-angle: 45deg;
--tick-2-angle: 30deg;
--tick-3-angle: 15deg;
--tick-4-angle: 0deg; /* middle */
}
.roll-degrees {
box-sizing: content-box;
--size: calc(var(--circle-radius) * 2);
width: var(--size);
height: var(--size);
padding: 16px;
position: relative;
}
.roll-curve {
--size: calc(var(--circle-radius) * 2);
width: var(--size);
height: var(--size);
border: solid 3px #000;
border-color: transparent;
border-top-color: white;
border-radius: 50%;
}
.tick {
--width: 3px;
--height: 16px;
width: var(--width);
height: var(--height);
background-color: white;
position: absolute;
--v-offset: var(--height);
--h-offset: var(--width);
top: calc(50% - var(--v-offset));
left: calc(50% - var(--h-offset) / 2);
--tick-angle-direction: 1;
transform:
rotate(calc(var(--tick-angle-direction) * var(--tick-angle)))
translateY(calc(-1 * var(--circle-radius)))
;
transform-origin: bottom;
}
.tick--tall {
--height: 24px;
}
.tick:nth-child(1),
.tick:nth-child(2),
.tick:nth-child(3) {
--tick-angle-direction: -1;
}
.tick:nth-child(1),
.tick:nth-child(7) {
--tick-angle: var(--tick-1-angle);
}
.tick:nth-child(2),
.tick:nth-child(6) {
--tick-angle: var(--tick-2-angle);
}
.tick:nth-child(3),
.tick:nth-child(5) {
--tick-angle: var(--tick-3-angle);
}
.tick:nth-child(4) {
--tick-angle: var(--tick-4-angle);
}
.tick.marker {
--marker-half-size: 14px;
--marker-full-size: calc(var(--marker-half-size) * 2);
--v-offset: var(--marker-half-size);
--h-offset: var(--marker-full-size);
--tick-angle: 0deg;
background-color: transparent;
width: 0;
height: 0;
border: var(--marker-half-size) solid transparent;
--marker-color: red;
border-top-color: var(--marker-color);
border-bottom-color: var(--marker-color);
transform-origin: center;
}
<div class="roll-degrees-wrapper">
<div class="roll-degrees">
<div class="tick tick--tall"></div>
<div class="tick"></div>
<div class="tick tick--tall"></div>
<div class="tick"></div>
<div class="tick tick--tall"></div>
<div class="tick"></div>
<div class="tick tick--tall"></div>
<div id="marker" class="marker tick"></div>
<div class="roll-curve"></div>
</div>
</div>
<input id="marker-range-input" type="range">
Note: You'll probably want to do a bit better styling on the marker or use an icon of some sort, but this serves as a simple example.
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>
I want to create a div that maintains aspect ratio with height and width changes of the parent.
In the above gif, you can see that I was able to maintain the box div's aspect ratio when changing width but I'm unable to maintain it when changing height of the parent.
.box {
width: 100px;
background-color: #dfdfdf;
max-width: 100%;
}
.box:after {
content: '';
display: block;
width: 100%;
height: 100%;
padding-bottom: 160%;
}
.wrap9 {
width: 125px;
height: 190px;
}
<div class="wrap9">
<div class="box"></div>
</div>
I want the grey box to behave like the following:
With your default width and height:
.box {
width: 100px;
background-color: #dfdfdf;
max-width: 100%;
max-height:100%;
}
.box:after {
content: '';
display: block;
width: 100%;
height: 100%;
padding-bottom: 160%;
}
.wrap9 {
width: 150px;
height: 200px;
border: 1px solid black;
}
<div class="wrap9">
<div class="box"></div>
</div>
width lower width and height:
.box {
width: 100px;
background-color: #dfdfdf;
max-width: 100%;
max-height:100%;
}
.box:after {
content: '';
display: block;
width: 100%;
height: 100%;
padding-bottom: 160%;
}
.wrap9 {
width: 100px;
height: 120px;
border: 1px solid black;
}
<div class="wrap9">
<div class="box"></div>
</div>
Is this the desired effect?
I'd have to say that this is not currently possible. While you can use calc() and variables, there is no way to keep a dynamic reference to object's current width nor height.
When I looked at doing this with js there was no clean way either. You'll just have to write an interval to periodically check if width or height of parent element has changed.
Google is pushing a dom element observer but the spec is currently very limited.
The funny thing is, just like in your example, images do this by default. However, there seems to be absolutely no clean way of doing this with another element.
You can use JavaScript to calculate the ratio of the width and the height between you object and the parent object. Then your can either scale to FILL the parent object (think CSS background-size: contain;) or scale to FIT the parent object (CSS: background-size: cover;)
Example of the two type of scaling methods.
(A) The left shows SCALE-TO-FILL and (B) on the right we are using SCALE-TO-FIT.
// Find the ratio between the destination width and source width.
RATIO-X = DESTINATION-WIDTH / SOURCE-WIDTH
// Find the ratio between the destination height and source height.
RATIO-Y = DESTINATION-HEIGHT / SOURCE-HEIGHT
// To use the SCALE TO FILL method,
// we use the greater of the two ratios,
// let's assume the RATIO-X is greater than RATIO-Y.
SCALE-W = RATIO-X * SOURCE-WIDTH
SCALE-H = RATIO-X * SOURCE-HEIGHT
// To use the SCALE TO FIT method,
// we use the lesser of the two ratios,
// let's assume the RATIO-Y is less than RATIO-X.
SCALE-W = RATIO-Y * SOURCE-WIDTH
SCALE-H = RATIO-Y * SOURCE-HEIGHT
When your parent object scales, you will need to determine these ratios.
Take a look at the embedded example and you can see how it works.
var $parent = $('.parent'),
$child = $('.child'),
w = $parent.width(),
h = $parent.height(),
cw = $child.width(),
ch = $child.height(),
winc = -10,
hinc = -5;
/*
This function is what you need.{
First we grab the ratio for the width (rx).
Then the ratio for the height (ry).
To scale to FIT, we want the MIN of the two.
To scale to FILL, we want the MAX of the two.
r is used to calculate the new size for ther child obj.
*/
function calcChildSize() {
var rx = w / cw,
ry = h / ch,
r1 = Math.min(rx, ry),
r2 = Math.max(rx, ry);
$('.child.fit').css({
width: r1 * cw,
height: r1 * ch
});
$('.child.fill').css({
width: r2 * cw,
height: r2 * ch
});
}
// just a simple function to change the size
// of the parent object
window.setInterval(function() {
if (w < 70) {
winc = 10;
} else if (w > 200) {
winc = -10;
}
if (h < 50) {
hinc = 5;
} else if (h > 200) {
hinc = -5;
}
w += winc;
h += hinc;
$parent.css({
width: w,
height: h
});
calcChildSize();
}, 100);
.parent {
display: inline-block;
width: 200px;
height: 200px;
border: 1px solid #aaa;
margin-right: 50px;
}
.child {
box-sizing: border-box;
width: 50px;
height: 70px;
background: rgba(0, 0, 0, 0.2);
border: 1px solid rgba(255, 0, 0, 0.5);
text-align: center;
font-family: monospace;
font-size: 11px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent fit">
<div class="child fit">FIT</div>
</div>
<div class="parent fill">
<div class="child fill">FILL</div>
</div>
Edit #2: I also went ahead and added an example of the two different scale methods in action.
Add max-width: 100% and object-fit:cover, here's a link https://jsfiddle.net/jv1f4bhL/1/
body {
position: relative;
background-color: wheat;
padding: 0;
margin: 0;
}
img {
object-fit: cover;
max-width: 100%;
width: auto;
}
<img src="https://mdbootstrap.com/img/Others/documentation/img%20(7)-mini.jpg" />
.box {
max-height: 100%;
}
....worked perfect.
How can I get the position of the cursor in percentage? I tried this so far.
$(".outter").click(function(e) {
var perc = e.offsetX / $(this).width() * 100;
if (perc > 100)
perc = 100;
$(this).children(".progress").css("width", perc + "%");
});
$(".outter").dblclick(function(e) {
$(this).children(".progress").css("width", "100%");
});
.outter {
display: inline-block;
width: 33.33%;
box-sizing: border-box;
border: 2px solid black;
padding: 10px;
position: relative;
}
.outter > .content {
position: relative;
z-index: 2;
}
.outter > .progress {
position: absolute;
top: 0;
left: 0;
background-color: #29B6AC;
height: 100%;
width: 50%;
z-index: 1;
transition: all .3s ease;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="outter">
<div class="content">
Some content...
</div>
<div class="progress"></div>
</div>
My problem is, that the value inside perc isn't correct. In the middle at about 50% it seems like ok. But if you click at about 10% od 90% you can see the backgroundbar won't stop at your cursor position. What did I wrong?
The .outter div has a padding of 10px, and since you are using jquery's .width() which will not include those 20 pixels.
You can either can get rid of the padding or you can use .outerWidth() to get the correct size.
Your padding css on the outter class messed up the offsetX module, try setting the padding to 0px and everything will work as intended... read on the offsetX API/doc
The calculation should be something like:
$(".outter").click(function(e) {
var parentOffset = $(this).parent().offset();
var relX = e.pageX - parentOffset.left;
var perc = relX / $(this).width() * 100;
...