My question is: I have a list of colors that jquery uses to select a random color for the box divs in my HTML. If you click on the "Random me" button, everything works and random colors are picked for each square. However, I want to make sure that adjacent squares don't get the same color (i.e. Square 1 color = black, Square 2 color = red,
Square 3 color = yellow, Square 4 color = purple). I want each Square to have its own unique color that is selected from a pool of say, 20 colors. So I don't want red, red, yellow, purple or red, yellow, red, purple, etc.
Below is all my code (HTML with CSS added as a style element in the head) and (jQuery added at the bottom of the page just before the closing body tag).
You guys are awesome. Thanks in advance for all your help. Jason
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Square Test</title>
<!-- CSS styles -->
<style>
.nw{background: #f09; top: 0; left: 0; right: 50%; bottom: 50%}
.ne{background: #f90; top: 0; left: 50%; right: 0; bottom: 50%}
.sw{background: #009; top: 50%; left: 0; right: 50%; bottom: 0}
.se{background: #090; top: 50%; left: 50%; right: 0; bottom: 0}
html, body{width: 100%; height: 100%; padding: 0; margin: 0}
div{position: absolute; padding: 1em; border: 1px solid #000}
div {
-webkit-box-sixing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
#question {
position: absolute;
top: 44%;
left: 37%;
bottom: 50%;
color: red;
width: 30%;
height: 5%;
background-color: #fff;
border: 3px solid black;
text-align: center;
font-size: 24px;
border-radius: 30px;
}
#square1 {
position: absolute;
top: 20%;
left: 20%;
color: #fff;
font-weight: bold;
font-size: 24px;
}
#square2 {
position: absolute;
top: 20%;
left: 70%;
color: #fff;
font-weight: bold;
font-size: 24px;
}
#square3 {
position: absolute;
top: 70%;
left: 20%;
color: #fff;
font-weight: bold;
font-size: 24px;
}
#square4 {
position: absolute;
top: 70%;
left: 70%;
color: #fff;
font-weight: bold;
font-size: 24px;
}
</style>
</head>
<body>
<!-- the divs that the jQuery acts on -->
<div onclick="change_color(1)" id="div_color_1" class="nw change_color" style="background-color: rgb(224, 216, 200);">
</div>
<div onclick="change_color(2)" id="div_color_2" class="ne change_color" style="background-color: rgb(94, 198, 49);">
</div>
<div onclick="change_color(3)" id="div_color_3" class="sw change_color" style="background-color: rgb(84, 51, 38);">
</div>
<div onclick="change_color(4)" id="div_color_4" class="se change_color" style="background-color: rgb(169, 215, 220);">
</div>
<!-- Random me button that selects a random color for each square -->
<input id="question" type="button" onclick="colorfy_me()" value="Random me">
<!-- the squares -->
<p id="square1">Square 1</p>
<p id="square2">>Square 2</p>
<p id="square3">>Square 3</p>
<p id="square4">>Square 4</p>
<!-- jQuery scripts -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript">
var myColors = [
'#7F8C8D', '#95A5A6', '#BDC3C7', '#003946', '#BDC3C7',
'#ECF0F1', '#BDC3C7', '#ECF0F1', '#C0392B', '#E74C3C',
'#D35400', '#E67E22', '#F39C12', '#F1C40F', '#22313f',
'#2C3E50', '#34495E', '#8E44AD', '#9B59B6', '#2980B9',
'#3498DB', '#27AE60', '#2ECC71', '#16A085'
];
$(function(){
$.each(myColors, function(i, v){
$('#div_color' + (+i + 1)).css('background-color', v);
})
})
function colorfy_me() {
var colors = {};
$.each(myColors, function(i, v){
colors[i] = 0;
})
$('div.change_color').each(function() {
var color = Math.floor(Math.random() * myColors.length);
$(this).css('background-color', myColors[color]);
colors[color] = colors[color] + 1;
});
$.each(colors, function(i, v){
$('#div_color' + (+i + 1)).html(colors[i])
});
}
</script>
</body>
</html>
This version of color_me implements the algorithm alexmac is trying to describe. It removes each color from the copy as it goes so that the shrinking color array contains only unused colors.
colorfy_me = function() {
var colors = myColors.slice(0)
$('div.change_color').each(function() {
// find a random color that's not already used.
var color = Math.floor(Math.random() * colors.length);
$(this).css('background-color', colors[color]);
$(this).html( colors[color] )
colors = colors.slice(0,color-1).concat(
colors.slice(color+1,colors.length-1) )
});
$.each(colors, function(i, v){
$('#div_color_' + (+i + 1)).html(colors[i])
});
}
there were a few other issues with your code, so I did have to make a few changes. See working example on http://jsfiddle.net/cQB38/1/
Defining only colors that are unique, that's trickier. One option is to break your colors into 4 sets of similar colors, and then pull one random color from each of the 4 sets. I think it's probably possible to determine how dissimilar two colors are, based on comparing the differences between and sums of their individual red, green, and blue components, but that sounds complicated.
assign myColors to a temp array and get color for background-color from temp array then remove the color from temp array using splice method
change your colorfy_me() like following and try
function colorfy_me() {
var colors = {};
$.each(myColors, function(i, v){
colors[i] = 0;
})
testColor=myColors;
$('div.change_color').each(function() {
var color = Math.floor(Math.random() * myColors.length);
$(this).css('background-color', testColor[color]);
testColor.splice(color,1);
colors[color] = colors[color] + 1;
});
$.each(colors, function(i, v){
$('#div_color' + (+i + 1)).html(colors[i])
});
}
Related
I'm working on a progress bar (in Javascript) that cycles through every second and then starts again.
I tried to change value with setInteval() but nothing helped me.
I hope for help, thanks
here's my code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.progress {
position: relative;
width: 510px;
height: 60px;
background: #9cbab4;
overflow: hidden;
}
.progress__fill {
width: 0%;
height: 100%;
background: #009579;
transition: all 0.1s;
}
.progress__text{
position: absolute;
top: 50%;
right: 5px;
transform: translateY(-50%);
font: bold 20px 'Quicksand', sans-serif;
color: #ffffff;
}
</style>
</head>
<body>
<div class="progress">
<div class="progress__fill"></div>
<span class="progress__text">0%</span>
</div>
<script>
setInterval(function(){
value++;
}, 1000);
function updateProgressBar(ProgressBar, value){
ProgressBar.querySelector(".progress__fill").style.width = '${value}%'
ProgressBar.querySelector(".progress__text").textContent = '${value}%'
}
</script>
</body>
</html> ```
I tried reproducing your code by changing the progress, progress__fill, and progress__text into id's and changed the <div class="__" /> into <div id="__" />:
<style>
#progress {
position: relative;
width: 510px;
height: 60px;
background: #9cbab4;
overflow: hidden;
}
#progress_fill {
width: 0%;
height: 100%;
background: #009579;
transition: all 0.1s;
}
#progress_text{
position: absolute;
top: 50%;
right: 5px;
transform: translateY(-50%);
font: bold 20px 'Quicksand', sans-serif;
color: #ffffff;
}
</style>
here's the <div /> in my repro code:
<div id="progress">
<div id="progress_fill"></div>
<span id="progress_text">0%</span>
</div>
then on the <script>, You did not have a variable for value so I made one and set the value to zero: let value = 0; then concatenated it with '%'.
I used window.setInterval then changed the querySelector to document.getElementById because of the changes above.
here's what it looks like on the script tag:
<script>
let value = 0;
window.setInterval(function() {
if (value != 100) {
value++;
document.getElementById("progress_fill").style.width = value + '%';
document.getElementById("progress_text").textContent = value + '%';
}
}, 1000);
</script>
I included an if (value != 100) to stop the cycle when it reaches 100.
Hope this helps! here's my code snippet if you want some reference:
https://jsbin.com/xiwiyew/5/edit?html
I have taken you example and played around a bit.
I have changed it up for I think suits better.
Problem one was you did not call the updateProgressBar() in your interval. So it did not work.. I think the code speaks for itself. If you have a question let me know
My code. Note: you could chose to put the two lines in the update function and move them directly in the interval function. Also the function does not have a cap now. and will go above 100% if left running long enough.
Hope this helps
value = 0;
setInterval(function() {
value++;
updateProgressBar(value);
}, 1000);
function updateProgressBar(value) {
document.querySelector(".progress__fill").style.width = value + "%"
document.querySelector(".progress__text").innerHTML = value + "%"
}
Looking at your code I am geussing you are new. Try writing out/ describing what you want in your head and try have your code replicate that. Example: I want a progressbar with a value, that increments every second. (interval function tells that now). Than the logic that looks clunky/reads less easy can be put behind a function
First of all you have to understand that variables have a scope limitations, so what you can do is get value from your innerHTML and update it in each function call. this way you can get realtime value, without storing it somewhere globally.
Here is the working code for the same.
setInterval(function () {
const progress__text = document.querySelector(".progress__text");
const progress__fill = document.querySelector(".progress__fill");
if (progress__text && progress__fill) {
let value = parseInt(progress__text.innerHTML.split("%")[0]);
if (value === 100) {
progress__fill.style.width = "0%";
progress__text.innerHTML = "0%";
} else {
progress__fill.style.width = ++value + "%";
progress__text.innerHTML = ++value + "%";
}
}
}, 100);
.progress {
position: relative;
width: 510px;
height: 60px;
background: #9cbab4;
overflow: hidden;
}
.progress__fill {
width: 0%;
height: 100%;
background: #009579;
transition: all 0.1s;
}
.progress__text {
position: absolute;
top: 50%;
right: 5px;
transform: translateY(-50%);
font: bold 20px "Quicksand", sans-serif;
color: #ffffff;
}
<body>
<div class="progress">
<div class="progress__fill"></div>
<span value="0" class="progress__text">0%</span>
</div>
</body>
This isn't an accurate way of timing a animation, but pretty simple to implement
const animation = {
duration: 2, // animation length in seconds
steps: 60,
counter: 0,
incrementCounter() {
this.counter += ((1 / this.duration) * (this.steps / 1000) * 100);
this.counter = Math.min(this.counter, 100)
}
}
const draw = setInterval(updateAnimation, animation.steps);
function updateAnimation() {
animation.incrementCounter();
document.querySelector(".progress__fill").style.width = animation.counter + '%'
document.querySelector(".progress__text").textContent = animation.counter + '%'
if (animation.counter === 100) {
animation.counter = 0;
clearInterval(draw)
};
}
.progress {
position: relative;
width: 510px;
height: 60px;
background: #9cbab4;
overflow: hidden;
}
.progress__fill {
width: 0%;
height: 100%;
background: #009579;
transition: all 0.1s;
}
.progress__text {
position: absolute;
top: 50%;
right: 5px;
transform: translateY(-50%);
font: bold 20px 'Quicksand', sans-serif;
color: #ffffff;
}
<div class="progress">
<div class="progress__fill"></div>
<span class="progress__text">0%</span>
</div>
I am in a class that is writing an online UNO game (this is not a graded assignment, just a class project). I am currently trying to develop the functionality to play a card. Basically, the player needs to be able to click on a card in their hand and have it appear in the discard pile. I thought about animating this, but we have 1 week left and a lot to get done, so my idea is to just have the player double-click on the card and it will appear in the discard pile.
Each of the cards in all the players' hands are separate divs created in javascript via information from the back end. I do not, however, have the code connected to the back end yet because I need to be able to test my functions and script now. Thus I have currently hard-coded the cards.
The discard pile has one card on it. I have determined that we don't actually need every single card to be placed on the discard pile. Rather, it should be enough to change the color and the rank of the card on the discard pile to reflect the card discarded and just eliminate that div from the player's hand. If you think I am wrong about this, please tell me.
That is where my problem is. I have a bit of script here that is supposed to erase the color of the discard pile card and replace it with the color of the div card that was clicked on in the player's hand. Here is the code (full code posted later in the post):
/*
The double-click on the card in the player's hand does erase the color from the discard pile card, but it doesn't add the color of the card from the hand to the discard pile card. I have tried different variations of the code, but none seem to work. Can anyone help me? Or am I thinking about this the wrong way?
*/
$(document).ready(function() {
function playCardThisPlayer(game) {
currCardColor = $(this).color;
$(".card").dblclick(function() {
$(".discardPile").removeClass(game.discardPile.color);
$(".discardPile").addClass.$(currCardColor);
});
}
playCardThisPlayer(gameTurn);
var gameTurn = {
deckCount: 40,
discardPile: {
color: "yellow",
rank: "2"
},
players: [{
name: "David", //players[0].name
hand: [{
color: "yellow",
rank: "3"
},
{
color: "blue",
rank: "3"
},
{
color: "red",
rank: "4"
},
{
color: "black",
rank: "w"
},
{
color: "blue",
rank: "7"
},
{
color: "blue",
rank: "8"
},
{
color: "green",
rank: "S"
}
]
},
{
name: "Dan", //players[1].name
hand: 4 //players[1].hand
},
{
name: "John", //players[2].name
hand: 5 //players[2].hand
},
{
name: "Kent", //players[3].name
hand: 10 //players[3].hand
},
{
name: "Amy",
hand: 15
}
]
};
function makePlayerList(game) {
for (i = 0; i < game.players.length; i++) {
$(".list").append("<p>" + (i + 1) + ". " + game.players[i].name + "</p>");
}
}
makePlayerList(gameTurn);
function createCards(game) {
var currPlayer = game.players[0];
var hand = $("<div class='hand'></div>");
for (var i = 0; i < currPlayer.hand.length; i++) {
var card = $("<div class='card'></div>" /*<div class='playerLabel'></div>"*/ );
card.addClass(".oval-shape");
var corner1 = $("<div></div>");
var middle = $("<div></div>");
var corner2 = $("<div></div>");
var oval = $("<div></div>")
corner1.append(currPlayer.hand[i].rank);
corner1.addClass("corner1");
middle.append(currPlayer.hand[i].rank);
middle.addClass("middle");
oval.addClass("oval-shape");
card.append(oval);
corner2.append(currPlayer.hand[i].rank);
corner2.addClass("corner2");
card.append(corner1);
card.append(middle);
card.append(corner2);
card.addClass(currPlayer.hand[i].color);
hand.append(card);
}
$("#table").append(hand);
}
function createCardBacks(game) {
for (var i = 1; i < game.players.length; i++) {
var hand = $("<div class='hand'></div>");
for (var j = 0; j < game.players[i].hand; j++) {
var cardBack = $("<div class='cardBack black'></div>");
var oval = $("<div></div>")
oval.addClass("oval-shape");
cardBack.append(oval);
hand.append(cardBack);
}
$("#table").append(hand);
}
}
function createDiscardPile(game) {
var topOfDiscardPile = $(".discardPile");
topOfDiscardPile.addClass(".oval-shape");
var corner1 = $("<div></div>");
var middle = $("<div></div>");
var corner2 = $("<div></div>");
var oval = $("<div></div>")
corner1.append(game.discardPile.rank);
corner1.addClass("corner1");
middle.append(game.discardPile.rank);
middle.addClass("middle");
oval.addClass("oval-shape");
topOfDiscardPile.append(oval);
corner2.append(game.discardPile.rank);
corner2.addClass("corner2");
topOfDiscardPile.append(corner1);
topOfDiscardPile.append(middle);
topOfDiscardPile.append(corner2);
topOfDiscardPile.addClass(game.discardPile.color);
}
createCards(gameTurn);
createCardBacks(gameTurn);
createDiscardPile(gameTurn);
function playCardThisPlayer(game) {
currCardColor = $(this).color;
$(".card").dblclick(function() {
$(".discardPile").removeClass(game.discardPile.color);
$(".discardPile").addClass.$(currCardColor);
});
}
playCardThisPlayer(gameTurn);
function fan(container, angle) {
var num = $(container).children().length;
var rotate = -angle * Math.floor(num / 2);
$(container).children().each(function() {
$(this).data("rotate", rotate);
$(this).css("transform", "translate(-50%,0) rotate(" + rotate + "deg)");
$(this).css("transform-origin", "0 100%");
rotate += angle;
});
$(container).children().mouseenter(function() {
var rotate = parseInt($(this).data("rotate")) * Math.PI / 180;
$(this).css("top", (-3 * Math.cos(rotate)) + "vmin");
$(this).css("left", (3 * Math.sin(rotate)) + "vmin");
});
$(container).children().mouseleave(function() {
$(this).css("top", 0);
$(this).css("left", 0);
});
}
var rotate = 0;
var num = $("#table").children().length;
var angleInc = 360 / num;
$("#table").children().each(function(idx) {
$(this).css("transform", "rotate(" + rotate + "deg)");
$(this).append("<div class='playerLabel'><span>" + (idx + 1) + "</span></div>")
$(this).css("transform-origin", "50% -18vmin");
fan(this, (idx == 0) ? 7 : 2.5);
rotate += angleInc;
});
});
* {
margin: 0;
padding: 0;
}
body {
background: #00a651;
}
#table {
width: 100vmin;
height: 100vmin;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background-color: #00FF00;
border-radius: 50%;
}
.card {
position: absolute;
top: 0;
left: 0;
display: inline-block;
}
.discardPile {
position: absolute;
bottom: 0;
left: 0;
display: inline-block;
}
.card,
.discardPile {
width: 15vmin;
height: 22vmin;
border-radius: 1vmin;
background: #fff;
-webkit-box-shadow: 3px 3px 7px rgba(0, 0, 0, 0.3);
box-shadow: 3px 3px 7px rgba(0, 0, 0, 0.3);
text-shadow: 2px 2px 0px #808080;
border: .3em solid white;
transition: all 0.125s;
}
.hand {
position: absolute;
left: 50%;
bottom: 10vmin;
width: 0;
height: 22vmin;
}
span {
position: absolute;
z-index: 100;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.playerLabel {
margin-top: -10vh;
background-color: red;
width: 3vmin;
height: 3vmin;
border: 1px solid black;
border-radius: 50%;
}
.list {
color: yellow;
font-family: 'Gloria Hallelujah', cursive;
font-size: 3vmin;
}
.yellow {
background-color: yellow;
}
.blue {
background-color: blue;
}
.red {
background-color: red;
}
.green {
background-color: green;
}
.black {
background-color: black;
}
.corner1 {
position: absolute;
font-size: 3.5vmin;
left: .5vmin;
top: .5vmin;
color: white;
}
.corner2 {
position: absolute;
font-size: 3.5vmin;
right: .5vmin;
bottom: .5vmin;
color: white;
}
.middle {
position: absolute;
font-size: 10vmin;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.oval-shape {
width: 10vmin;
height: 22vmin;
background: white;
border-radius: 7vmin / 15vmin;
transform: translate(-50%, -50%) rotate(25deg);
margin: 0 auto;
position: absolute;
left: 50%;
top: 50%;
}
.slide-out {
top: -3vmin;
}
.cardBack {
position: absolute;
top: 0;
display: inline-block;
width: 15vmin;
height: 22vmin;
border-radius: 1vmin;
-webkit-box-shadow: .3vmin .3vmin .7vmin rgba(0, 0, 0, 0.3);
box-shadow: .3vmin .3vmin .7vmin rgba(0, 0, 0, 0.3);
text-shadow: .2vmin .2vmin 0 #808080;
border: .3em solid white;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>UNO Cards</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://fonts.googleapis.com/css?family=Gloria+Hallelujah" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="style.css">
<script src="https://code.jquery.com/jquery-3.2.1.js" integrity="sha256-DZAnKJ/6XZ9si04Hgrsxu/8s717jcIzLy3oi35EouyE=" crossorigin="anonymous"></script>
</head>
<body>
<div class="list"></div>
<div class="discardPile"></div>
<div id="table"></div>
<script src="script.js"></script>
</body>
</html>
Thanks!
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>
I have set the background color of the inner div to white and the opacity of its parent div to 0.6. It seems that the background color of the inner div is not exactly white. If I change the opacity of the parent div to 1.0, the problem disapears, why?
http://jsbin.com/zekacunefi/edit?html,output
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="js/jquery.js"></script>
<style>
#msg_container {
position: fixed;
z-index: 3800;
background-color: #000000;
opacity: 0.6;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
#modalDialog {
display: inline-block;
z-index: 3801;
background-color: white;
position: absolute;
border: 1px solid rgb(103, 103, 103);
box-shadow: 0 4px 17px 0px rgba(0,0,0,0.4);
top: 50%;
left: 50%;
}
body {
background-color: blue;
}
</style>
</head>
<body>
<script>
MessageBox("abc\ndef\ng\nhdasfasdfsdsdfsd");
function MessageBox(str) {
var boxHtml = "<div id='msg_container'><div id='modalDialog'></div></div>";
$("body").append(boxHtml);
var md = $("#modalDialog");
var contentArray = str.split("\n");
var newArray = contentArray.map(function(ele, idx) {
return ele + "<br>";
});
md.html("<p>" + newArray.join("") + "</p>");
var w = md.width(),
h = md.height();
md.css({
marginTop: -1 * h / 2 + "px",
marginLeft: -1 * w / 2 + "px"
});
$("#msg_container").appendTo($("body"));
}
</script>
</body>
</html>
When you use "opacity", you're not only setting the opacity of the div background, but also the opacity of the whole content. (see this W3C Wiki as example : http://www.w3.org/wiki/CSS/Properties/opacity)
IMHO, you should remove the opacity setting from both #msg_container and #modalDialog and then using instead rgba() to define background color of #msg_container.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<style>
#msg_container {
position: fixed;
z-index: 3800;
background-color: rgba(0,0,0,0.6);
left: 0;
top: 0;
right: 0;
bottom: 0;
}
#modalDialog {
display: inline-block;
z-index: 3801;
background-color: white;
position: absolute;
border: 1px solid rgb(103, 103, 103);
box-shadow: 0 4px 17px 0px rgba(0,0,0,0.4);
top: 50%;
left: 50%;
}
body {
background-color: blue;
}
</style>
</head>
<body>
<script>
MessageBox("abc\ndef\ng\nhdasfasdfsdsdfsd");
function MessageBox(str) {
var boxHtml = "<div id='msg_container'><div id='modalDialog'></div></div>";
$("body").append(boxHtml);
var md = $("#modalDialog");
var contentArray = str.split("\n");
var newArray = contentArray.map(function(ele, idx) {
return ele + "<br>";
});
md.html("<p>" + newArray.join("") + "</p>");
var w = md.width(),
h = md.height();
md.css({
marginTop: -1 * h / 2 + "px",
marginLeft: -1 * w / 2 + "px"
});
$("#msg_container").appendTo($("body"));
}
</script>
</body>
</html>
Its because opacity on parent is affecting inner div too and blue color is body background. Instead what you can do is set rgba() for parent div
Try this
#msg_container {
position: fixed;
background-color: rgba(0, 0, 0, 0.6);
left: 0;
top: 0;
right: 0;
bottom: 0;
}
You change the opacity of the parent and all it's children. This means that you will see the blue background through both the parent div and the child.
I'm trying to create an animated menu that slides up and down. Unfortunately it's not working. I've checked the error console and there are no syntax errors. Here's my Javascript:
function showLayer() {
var hiddenLayer = document.getElementById("mainmenu");
var layerPosition = parseInt(hiddenLayer.style.bottom);
if (layerPosition > 700) {
hiddenLayer.style.bottom = (layerPosition + 5) + "px";
setTimeout("showLayer()", 20);
}
}
function hideLayer() {
var hiddenLayer = document.getElementByID("mainmenu");
hiddenLayer.style.bottom = "700px";
}
Here's the whole context:
<script type="text/javascript">
function showLayer() {
var hiddenLayer = document.getElementById("mainmenu");
var layerPosition = parseInt(hiddenLayer.style.bottom);
if (layerPosition > 700) {
hiddenLayer.style.bottom = (layerPosition + 5) + "px";
setTimeout("showLayer()", 20);
}
}
function hideLayer() {
var hiddenLayer = document.getElementByID("mainmenu");
hiddenLayer.style.bottom = "700px";
}
</script>
<style type="text/css">
div#mainmenu { position: absolute; bottom: 700px; left: 9px; width: 600px;
height: 350px; border-style: solid; background-color: rgb(0, 0, 0) ; border-
width: 3px; border-top-right-radius: 7px; border-top-left-radius: 7px; }
div#mainbutton { position: absolute; top: 674px; left: 12px; width: 28px;
height: 28px; border-style: solid; border-color: rgb(255, 255, 255); border-width:
1px; border-radius: 4px; }
div#mainbuttontext { position: absolute; top: 679px; left: 22px; color: rgb(255, 255,
255); font-style: normal; font-size: 18px; font-family:"Arial"; }
</style>
<div id="mainbutton"></div>
<div id="mainmenu" onClick="showLayer('mainmenu')"> </div>
<div id="mainbuttontext">F</div>
</body>
I think I found your problem! It's something very strange and I can't explain it, but to get style in javascript, the css must be inline (to set a style it's not necessary).
So I modified your code by placing the css inline.
HTML :
<div id="mainmenu" style="position:absolute;bottom:100px;" onclick="showLayer('mainmenu');">Click me!</div>
<!--I wrote 100px just for the test, you can change it and modify the js-->
JS :
function showLayer()
{
var hiddenLayer=document.getElementById("mainmenu");
var layerPosition=parseInt(hiddenLayer.style.bottom);
if(layerPosition>50)
{
hiddenLayer.style.bottom=(layerPosition+5)+"px";
setTimeout("showLayer()",20);
}
}
function hideLayer()
{
var hiddenLayer=document.getElementById("mainmenu");
hiddenLayer.style.bottom="700px";
}
Fiddle : http://jsfiddle.net/8MWfV/
And here is a fiddle that shows that a not inline css doesn't works : http://jsfiddle.net/kfUrP/