How to make Semi circle progress bar? [duplicate] - javascript

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>

Related

setting line bars on the circumference of a circle

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.

Line across any device and in the centre, using canvas or html,css

I'm making an app using JavaScript and JQuery, which will tell the user if there device is straight or not, basically like a spirit level. I want to draw a line a straight line across the middle of the screen and i want this to be responsive no matter the size of the device. This will be used on mobiles and tablets. I used a canvas to the draw a line and so far i'm not sure if this is the right way to approach this?
if anyone could give me any advice i would really appreciate it. Below is my canvas line so far. And I've included some rough drawing of what i mean.
const c = document.getElementById("LineCanvas");
const drw = c.getContext("2d");
drw.beginPath();
drw.moveTo(10,45);
drw.lineTo(180,47);
drw.lineWidth = 5;
drw.strokeStyle = '#006400';
drw.stroke();
If the phone is aligned straight the line will be green else red
to draw the line you can use a pseudo element from HTML or body or any specific tag that you want to use in a specific page or click , then update rotation via transform:rotate() ; or rotate3D()
example ( without javascript, rotate values will have to be taken from your device via your app ):
let level = document.querySelector("#level");
document.querySelector("#spirit").onclick = function() {
level.classList.toggle('show');
}
#level {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
display: none;
pointer-events: none;
}
#level.show {
display: block;
}
#level::before {
content: '';
position: absolute;
width: 200vmax;
margin: 0 -50vmax;
border-top: 1px solid;
box-shadow: 0 0 1px 5px #bee;
top: 50%;
transform: rotate(0deg);
}
#level.show~#spirit::before {
content: 'Hide';
}
#level:not(.show)~#spirit::before {
content: 'Show';
}
/* animation to fake phone device moving */
#level::before {
animation: rt 10s infinite;
}
#keyframes rt {
20% {
transform: rotate3d(1, -1, 1, -0.25turn);
}
40% {
transform: rotate3d(1, 1, 1, 0.5turn);
}
60% {
transform: rotate3d(1, -1, 1, -0.75turn);
}
80% {
transform: rotate3d(1, 1, -1, -0.5turn);
}
}
<div id="level">
<!-- to show on a single page or via js on user request -->
</div>
<button id="spirit" type=button> that spirit level</button>
While drawing a line with canvas can work you might find it more straightforward to draw it with a simple div element. When you sense a slope you can change its color to red and back to green if it's level.
Of course you will have to do some calculations to decide what angle you want the line to be - but I guess that is the whole point of your webapp to show people how far off they are.
When you know the angle you want the line to be call slope(n) where n is the number of degrees. I've also put in a simple button so the user can choose whether to show the line or not but I expect you'll have your own code for that.
On any page where you want the user to be able to show the line put this in the head:
<style>
* {
margin: 0;
padding: 0;
}
.linecontainer {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
z-index: 99999;
}
#line {
width: 200vmax;
height: 5px;
position: relative;
top: 50%;
left: calc(50vw - 100vmax);
transform: rotate(45deg);
background-color:red;
}
.hideline {
display: none;
}
#showbtn {
font-size: 20px;
background-color: blue;
color: white;
height: 2em;
width: auto;
padding: 2px;
}
</style>
and put this in the main body of the page:
<div class="linecontainer">
<div id="showbtn" onclick="document.getElementById('line').classList.toggle('hideline');">
Click me to show/hide the line
</div>
<div id="line"></div>
</div>
<script>
function slope(deg) {
let line = document.getElementById('line');
line.style.backgroundColor = ( deg%180 == 0 ) ? 'green' : 'red';
line.style.transform = 'rotate(' + deg + 'deg)';
}
</script>
Here's a snippet where you can show the line at different angles.
function slope(deg) {
let line = document.getElementById('line');
line.style.backgroundColor = ( deg%180 == 0 ) ? 'green' : 'red';
line.style.transform = 'rotate(' + deg + 'deg)';
}
* {
margin: 0;
padding: 0;
}
.linecontainer {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
z-index: 99999;
}
#line {
width: 200vmax;
height: 5px;
position: relative;
top: 50%;
left: calc(50vw - 100vmax);
transform: rotate(45deg);
background-color:red;
}
.hideline {
display: none;
}
#showbtn {
font-size: 20px;
background-color: blue;
color: white;
height: 2em;
width: auto;
padding: 2px;
}
<div class="linecontainer">
<div id="showbtn" onclick="document.getElementById('line').classList.toggle('hideline');">
Click me to show/hide the line
</div>
<div id="line"></div>
</div>
<!-- this is just for the demo -->
<div style="background-#eeeeee;font-size: 20px;position:fixed;z-index:100000;bottom:0;left:0;">How many degrees do you want me to rotate? <input style="font-size:20px;"value="45" onchange="slope(this.value);"/></div>

Changing div left property set in % using javascript/jQuery?

Hope you can help me!! So I have a div inside another div and I'd like to move the second one back and forth with a step of 14.5% left and right stopping it before the black edges. I've managed to do it setting the left property in px but I'd like to to that with percentages..how can I do that? Thanks in advance!
PS. of course now the code doesn't work well because of the px changing..for this reason I'd like to work with %s...
$(document).ready(function() {
$('#min_oct').click(function() {
var left = parseFloat($('.highlighted').css('left'));
console.log(left);
if(left<99.495){
$('.highlighted').css('left',left);
}
else{
left= left - 103.108;
$('.highlighted').css('left',left);
}
});
});
$(document).ready(function() {
$('#plus_oct').click(function() {
var left = parseFloat($('.highlighted').css('left'));
console.log(left);
if(left>411.111){
$('#highlighted').css('left',left);
}
else{
left= left + 103.108;
$('#highlighted').css('left',left);
}
});
});
.mini_keyboard{
position: relative;
width: 700px;;
height: 90px;
top: 22.5%;
transform: translate(35%);
border: 0.5rem solid;
box-shadow:
inset 0 0 18rem black,
inset 0 0 4rem black,
0 0 10rem black;
padding: 0.5%;
bottom: 5px;
}
.highlighted{
position: absolute;
background-color: yellow;
width: 198px;;
height: 93px;
left: 57.5%;
top: 0.5%;
opacity: 0.6;
padding: 0.5%;
bottom: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="mini_keyboard">
<div id=highlight class="highlighted"></div>
</div>
<button id="min_oct">-1 octave</button>
<button id="plus_oct">+1 octave</button>
First, your highlighted id is missing " and you're are trying to get your element by calling the id attribute with the class value.
You can get the container width with .width() function, and then calculate the percentage by multiplying it by 0.145.
$(document).ready(function() {
$('#min_oct').click(function() {
var containerWidth = $(".mini_keyboard").width();
var left = parseFloat($('.highlighted').css('left'));
console.log(left);
var step = (containerWidth * 0.145);
if(left < step){
$('#highlight').css('left',left);
}
else{
left= left - step;
$('#highlight').css('left',left);
}
});
});
$(document).ready(function() {
$('#plus_oct').click(function() {
var containerWidth = $(".mini_keyboard").width();
var left = parseFloat($('.highlighted').css('left'));
console.log(left);
var step = (containerWidth * 0.145);
if(left > (containerWidth - (2*step))){
$('#highlight').css('left',left);
}
else{
left = left + step;
$('#highlight').css('left',left);
}
});
});
.mini_keyboard{
position: relative;
width: 700px;;
height: 90px;
top: 22.5%;
transform: translate(35%);
border: 0.5rem solid;
box-shadow:
inset 0 0 18rem black,
inset 0 0 4rem black,
0 0 10rem black;
padding: 0.5%;
bottom: 5px;
}
.highlighted{
position: absolute;
background-color: yellow;
width: 198px;;
height: 93px;
left: 57.5%;
top: 0.5%;
opacity: 0.6;
padding: 0.5%;
bottom: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="mini_keyboard">
<div id="highlight" class="highlighted"></div>
</div>
<button id="min_oct">-1 octave</button>
<button id="plus_oct">+1 octave</button>

How to let a div become visible when the bar is full [JS]

my name is Daniel and i'm making a drinking game for school, I want to let a div to become visible when the bar is full (so you know when the bar is full and you win the game), but i have no idea how to do this...
Could you help me out?
HTML:
<div class="col-xs-12" style="display: none;" id="hiddenText">
<div id="bar" class="animated bounceInUp">
</div>
</div>
CCS:
#bar {
background-color: #F8F8F8 ;
width: 340px;
height: 24px;
margin-right: auto;
margin-left: auto;
}
#bar > div {
margin-top: 30px;
max-width: 334px;
width: 100%;
height: 16px;
background: #9d3349;
position: relative;
top: 4px;
left: 3px;
transition: width 500ms;
}
JS:
var jumpsize = 2.77, // %
body = $("body");
(container = $("#bar")), (bar = container.children("div")), (topcnt = function(
px
) {
return 100 * px / container.width();
}), (set = function(pcnt) {
bar.css({ width: pcnt + "%" });
});
body
.on("click", ".card1, .card2, .card3, .card4", function() {
set(topcnt(bar.width()) + jumpsize);
});
set(0);
The reason its not working is because u forgot to put the if statement in the function u run on click. So the if statement only runs once. and on first load it will result in false. To fix your code move the if statement in your Body.onclick.
Next time it would be smart to include the full javascript that is relative to the function.
By looking at the online code i was able to find the issue.
Hope this resolves your issues.
~Yannick
When you hit your target you need to remove the CSS styling of Display = none.
W3 schools page here for some helpful info to help you learn some more.
https://www.w3schools.com/jsref/prop_style_display.asp
The line below inserted when you reach your goal to display should make the bar appear.
document.getElementById("hiddenText").style.display = "block";
I'm not sure you want this, but try this:
var jumpsize = 2.77, // %
width = 0,
body = $("body");
(container = $("#bar")), (bar = container.children("div")), (topcnt = function(
px
) {
return 100 * px / container.width();
}), (set = function(pcnt) {
bar.css({ width: pcnt + "%" });
if(pcnt >= 100) {$('#hiddenText').show();}
});
body
.on("click", ".card1, .card2, .card3, .card4", function() {
width += jumpsize;
set(topcnt(width));
});
set(0);
#bar {
background-color: #F8F8F8 ;
width: 340px;
height: 24px;
margin-right: auto;
margin-left: auto;
}
#bar > div {
margin-top: 30px;
max-width: 334px;
width: 100%;
height: 16px;
background: #9d3349;
position: relative;
top: 4px;
left: 3px;
transition: width 500ms;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="col-xs-12" style="display: none;" id="hiddenText">
<div id="bar" class="animated bounceInUp">
<div></div>
</div>
</div>
<button class="card1">click me</button>
You are using jQuery so quicker will be:
$('#hiddenText').show();
Edit:
sooo
if($('#bar').children('div').width() >= 334){
$('#hiddenText').show();
}
As You can see the div with progress bar can have max od 334 px. Check if it has it and if yes then show the text. Put this in that click event
Seems to me like you're overcomplicating things a little bit with the percentage calculations. I would just add a variable for the width of the bar that starts at 0 and increase this with the jumpsize on every click. Once this new variable goes over or equals 100 you show the hidden div.
HTML
<div class="col-xs-12" id="hiddenText">
<div id="bar" class="animated bounceInUp">
<div></div>
</div>
</div>
<button id="button">Click me</button>
<div id="showOnComplete">Show me when the bar is full!</div>
CSS
#bar {
width: 340px;
height: 24px;
padding: 4px 3px;
margin: 30px auto 0;
background-color: #f8f8f8;
}
#bar > div {
position: relative;
float: left;
height: 100%;
width: 0;
max-width: 100%;
background: #9d3349;
transition: width 500ms;
}
#button {
margin: 20px auto;
display: block;
}
#showOnComplete {
width: 400px;
padding: 20px;
margin: 20px auto;
background: blue;
color: #fff;
text-align: center;
display: none;
}
JS
(function($) {
var jumpSize = 20, //increased this for the fiddle, so we don't have to click as often
barWidth = 0,
$bar,
$showOnComplete;
$(function() {
$bar = $("#bar").children("div");
$showOnComplete = $("#showOnComplete");
$(document).on("click", "#button", function() {
barWidth += jumpSize;
$bar.width(barWidth + "%");
if (barWidth >= 100) $showOnComplete.show(); //optionally add a setTimeout of 500 here to account for the final transition of the bar
});
});
})(jQuery);
I've made a fiddle for it here.

Dynamically recalculate mouse position for a selection box when changing page size

I have a script to draw a selection box over a grid (just a .png image) however I have an error where the selection box is drawn in the wrong place.
I think it's because the script which the mousedown position uses calculates top and left on page load. If the page is resized before creating a selection box, it uses the original calculations of top and left and is therefore not in the correct position.
Is there a way to fix this problem without completely bastardising my script?
Below is the code used along with a .zip and a jsFiddle, thank you for your help!
jsFiddle
.zip
CSS:
body{
background-color: #3AB3F0;
}
#board-background{
width: 1000px;
height: 1000px;
padding: 25px 25px 25px 25px;
margin: 25px auto 25px;
position: relative;
background: url(https://abs.twimg.com/a/1366134123/t1/img/wash-white-30.png);
border: 0px solid #e5e5e5;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,.05);
-moz-box-shadow: 0 1px 2px rgba(0,0,0,.05);
box-shadow: 0 1px 2px rgba(0,0,0,.05);
}
#board {
position: absolute;
background-color: #FFF;
z-index: 1;
width: 1000px;
height: 1000px;
border-bottom: 1px solid black;
border-right: 1px solid black;
}
#board img {
position: absolute;
z-index: 2;
user-drag: none;
-moz-user-select: none;
-webkit-user-drag: none;
}
#selectionBox {
position: absolute;
z-index: 3;
display: none;
background-color: red;
min-width: 0px;
min-height: 0px;
width: 10px;
height: 10px;
opacity: 0.8;
}
HTML:
<html>
<head>
<link href="css/test.css" rel="stylesheet">
<script type="text/javascript" src="http://code.jquery.com/jquery-git.js"></script>
<script type="text/javascript" src="js/board_script.js"></script>
</head>
<body>
</body>
</html>
JS:
// GRID CREATION SCRIPT //
// -------------------- //
function creategrid(){
//Outside background for the board
var BoardBackground = document.createElement('div');
BoardBackground.id = 'board-background';
BoardBackground.class = 'board-background';
document.body.appendChild(BoardBackground);
//Generated image
var Board = document.createElement("div");
Board.id = 'board';
Board.className = 'board';
BoardBackground.appendChild(Board);
//grid image
var grid = document.createElement("img");
grid.id = 'grid';
grid.className = 'grid';
grid.src = "media/grid.png";
Board.appendChild(grid);
}
// Selection Box Script //
// -------------------- //
var isDragging = false,
dragStart,
cellSpacing = 10,
gridOffset,
selectionBox;
function getMousePos (e) {
return {
'left': Math.floor((e.pageX - gridOffset.left) / cellSpacing) * cellSpacing .toFixed( 0 ),
'top': Math.floor((e.pageY - gridOffset.top) / cellSpacing) * cellSpacing .toFixed( 0 )
};
};
$(document).ready(function(){
creategrid(10);
gridOffset = $('#board').offset();
selectionBox = $('<div>').attr({id: 'selectionBox'})
.appendTo($('#board'));
$('#board').on('mousedown', function(e){
isDragging = true;
var pos = getMousePos(e);
dragStart = pos;
selectionBox.css({
left: pos.left,
top: pos.top,
width: 10,
height: 10
}).show();
});
$('#board').on('mousemove', function(e){
if(!isDragging)
return false;
var pos = getMousePos(e);
var diff = {
'left': pos.left - dragStart.left,
'top': pos.top - dragStart.top
};
selectionBox.css({
left: Math.min(pos.left, dragStart.left),
top: Math.min(pos.top, dragStart.top),
width: Math.abs(diff.left),
height: Math.abs(diff.top)
});
});
$('#board').on('mouseup', function(e){
isDragging = false;
});
});
Media:
(I need 10 rep to post a third link, so here's plaintext and 'code')
oi43.tinypic.com/33opjtd.jpg
[grid.png](http://oi43.tinypic.com/33opjtd.jpg "grid lined image with transparent background")
Other things that I need help with:
another minor error is the fact that, when selecting to the left and the top, the box rotates around the top left corner rather than the bottom right (try selecting the entire grid from the bottom right square).
I think that this has something to do with putting an if statement around the math.abs in the css and subtracting 10px from either side... but I can't work it out
Also in the future I want to be able for the user to upload an image and have it displayed over the selection box (dynamically changing in size) it should be possible by changing the css of the selection box... I might open a separate question for that though.
A single line can solve your selection probleme on resize :
$(window).resize(function(){gridOffset = $('#board').offset();})

Categories