Change the colour of a triangle div over time - javascript

EDIT: https://codepen.io/TechTime/pen/NjZOGE This is what I want to achieve, happening every few random amount of seconds with random colors.
EDIT2: How would this be done with multiple triangles? I've tried a few things, but it hasn't worked. Help would be appreciated
I was wandering if it were possible to change the color of a triangle div so that every few seconds it would glow a color then go back to normal. Below is my triangle code:
.triangle-up {
z-index: 1;
float: left;
margin: 0.5%;
width: 5%;
height: 0;
padding-left: 5%;
padding-bottom: 5%;
overflow: hidden;
}
.triangle-up:after {
content: "";
display: block;
width: 0;
height: 0;
margin-left: -500px;
border-left: 500px solid transparent;
border-right: 500px solid transparent;
border-bottom: 500px solid #e6e6e6;
}
I don't mind if it uses css, javascript or jquery. Just that it works! Thanks in advance.

The accepted solution does not meet all the criteria currently requested by the OP, I believe this one does and those being:
Random colors.
Random time intervals.
Return to initial color.
"Glows".
We use JS to change bottom border color and transition duration to random values. We also respond to the transitionend event so we don't have to use setInterval and know that the transition between colors has fully completed. Every other transition returns to the default gray. Glows by fading between colors instead of the color instantly changing to next color.
I've done this through a function that allows you to assign the element that requires the animation/transition and min/max parameters to control the time interval range between color changes. You'll also notice that I removed the pseudo element and nested a regular DIV as changing pseudo element CSS properties can be tricky.
var colorizer = function ( el, min, max ) {
// #link https://stackoverflow.com/questions/5092808/how-do-i-randomly-generate-html-hex-color-codes-using-javascript
function getHexColor() {
return "#000000".replace( /0/g, function () {
return ( ~~( Math.random() * 16 ) ).toString( 16 );
} );
}
// #link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
function getRandomInt( min, max ) {
return Math.floor( Math.random() * ( max - min + 1 ) ) + min;
}
min = undefined == min ? 250 : min;
max = undefined == max ? 1500 : max;
var isDefaultColor = true,
style = el.style,
defaultColor = style.borderBottomColor,
color;
return function ( e ) {
el.offsetWidth; // Reset transition so it can run again.
color = isDefaultColor ? getHexColor() : defaultColor;
isDefaultColor = !isDefaultColor;
style.borderBottomColor = color;
style.transitionDuration = ( getRandomInt( min, max ) ) + 'ms';
};
},
triangle = document.querySelector( '.triangle > div' ),
triangleColorizer = colorizer( triangle, 750, 2000 );
triangle.addEventListener( 'transitionend', triangleColorizer );
// Kick it off!
triangleColorizer();
.triangle {
width: 5%;
height: 0;
padding: 0 0 5% 5%;
overflow: hidden;
}
.triangle > div {
width: 0;
height: 0;
margin-left: -500px;
border-right: 500px solid transparent;
border-left: 500px solid transparent;
border-bottom: 500px solid lightgray;
transition: border-bottom-color 1000ms ease-in-out;
}
<div class="triangle">
<div></div>
</div>

This changes the triangle color into a random color every 2 seconds. On the first function we iterate on a string of letters and return it with as a random hex code. The x function creates a style tag and appends it into the head tag then it toggles the class randColor defined inside the previous statement. Finally the setInterval function is called calling the functions every 2 seconds. The remover function just removes the style tag from the head so we don't keep appending style tags every 2 seconds. It changes color every 2 seconds then goes back to its original color. Hope this helps.
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
function remover(){
$(".style-tag").remove();
}
function x(){
var style = $('<style class="style-tag">.randColor:after { border-bottom: 500px solid ' + getRandomColor() +'; }</style>');
$('html > head').append(style);
$(".triangle-up").toggleClass("randColor");
}
$(document).ready(function(){
setInterval(function(){
remover();
x();
}, 2000);
});
.triangle-up {
z-index: 1;
float: left;
margin: 0.5%;
width: 5%;
height: 0;
padding-left: 5%;
padding-bottom: 5%;
overflow: hidden;
}
.triangle-up:after {
content: "";
display: block;
width: 0;
height: 0;
margin-left: -500px;
border-left: 500px solid transparent;
border-right: 500px solid transparent;
border-bottom: 500px solid #e6e6e6;
transition: all 0.4s ease-in-out;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="triangle-up"></div>

So this is very crude, but the only way I see this possible is using jQuery and having a bunch of css classes. You cannot change the :after css rule via jquery, since it's not part of the dom. But we can do something like this (which I admit is tedious, but I don't quite see another way given your current html).
html
<div class="triangle-up blue">
</div>
jquery
var cachedColorName;
$(document).ready(function() {
setInterval(function(){
var newColor = 'red'; //(here you'd want to randomnly find a color that you have in your css
changeColor(newColor);
}, 3000);});
function changeColor(colorName) {
$('.triangle-up').removeClass(cachedColorName).addClass(colorName);
cachedColorName = colorName;
}
css
.triangle-up {
z-index: 1;
float: left;
margin: 0.5%;
width: 5%;
height: 0;
padding-left: 5%;
padding-bottom: 5%;
overflow: hidden;
}
.triangle-up:after {
content: "";
display: block;
width: 0;
height: 0;
margin-left: -500px;
border-left: 500px solid transparent;
border-right: 500px solid transparent;
}
.triangle-up.blue:after {
border-bottom: 500px solid blue;
}
.triangle-up.red:after{
border-bottom: 500px solid red;
}
So you're just toggling different classes here. But this is the only way to make it random like you want (instead of hardcoded red that I did, you can programmatically pick a random color each time from a collection you have that has all the css classes that accompanies it).
Here's it in action:
https://jsfiddle.net/5b7wLv3r/2/
EDIT: if you need help randomly selecting a color, let me know. I can add that code.
EDIT 2: I made this a bit smarter for you
EDIT 3: finding the random color
css
.triangle-up {
z-index: 1;
float: left;
margin: 0.5%;
width: 5%;
height: 0;
padding-left: 5%;
padding-bottom: 5%;
overflow: hidden;
}
.triangle-up:after {
content: "";
display: block;
width: 0;
height: 0;
margin-left: -500px;
border-left: 500px solid transparent;
border-right: 500px solid transparent;
}
.triangle-up.blue:after {
border-bottom: 500px solid blue;
}
.triangle-up.red:after{
border-bottom: 500px solid red;
}
.triangle-up.purple:after{
border-bottom: 500px solid purple;
}
.triangle-up.yellow:after{
border-bottom: 500px solid yellow;
}
.triangle-up.orange:after{
border-bottom: 500px solid orange;
}
.triangle-up.green:after{
border-bottom: 500px solid green;
}
html
<div class="triangle-up blue">
</div>
js
var cachedColorName;
var colorCollection = ['red', 'blue', 'purple', 'yellow', 'orange', 'green']
$(document).ready(function() {
setInterval(function(){
var newColor = randomItem(colorCollection); //(here you'd want to randomnly find a color that you have in your css
changeColor(newColor);
}, 3000);});
function changeColor(colorName) {
$('.triangle-up').removeClass(cachedColorName);
$('.triangle-up').addClass(colorName);
cachedColorName = colorName;
}
function randomItem(collection) {
return collection[Math.floor(Math.random()*collection.length)];
}
So basically, we have a collection here, which we randomly find a value in it, then pass the color name to our changeColor method. I did see in your question you want to change to random color, then back to default. Let me know if you need me to help you with that as well, basically just a boolean to see if you changed to random before. I would have implemented this in the code, but since you did not try it on your own I want to leave something up to you to figure out if so, just change to default. Otherwise, find the random color.
Working here:
https://jsfiddle.net/5b7wLv3r/3/

Related

Creating health bar that increases in value based on users level

Hello I am trying to create a healthbar that scales in max value based on the users level.
But I am kinda stuck with it because everytime the healthbar ends up in not having the right length based on the users level and it's health. The system works like this: the user starts at level 1 with a health value of 150 and increases + 10 everytime the user levels up, the max level that exists is 32.
Now I know this might be possible to do with a loop but I am not sure on how do this correctly:
This is the code for the health bar. The user_level is the users level and I am trying to change the element style based on his health, but at the same time that it would match with the current level of the user.
for (let i = 0; i < user_level.value; i++) {
playerhealthbar.style.width = user_health // Something here but I dont know how to.
}
This is the CSS code if it helps. What happens is that the greenbar should shrink so that the red bar underneath becomes visible.
#playerhealth {
position: absolute;
bottom: 0;
left: 0;
height: 45px;
width: 325px;
background: lightgreen;
}
#playerhealthbar {
position: absolute;
height: 50px;
width: 330px;
border: rgb(255, 255, 255) 3px solid;
border-radius: 3px;
margin-right: 20px;
display: inline-block;
margin-top: 442px;
margin-left: 70px;
background: rgb(158, 31, 31);
}
#playerhealthvalue{
position: absolute;
margin-top: 500px;
margin-left: 220px;
font-size: 30px;
color: black;
}
The complete outerbar stays the same. But the greenbar thats inside the whole frame shrinks in size when the health goes down.
So the first thing you have to calculate is what the current maximum health value is. This is given by currentMaxHealth = 150 + 10 * (level-1).
The percent of the green bar is playerHealth / currentMaxHealth * 100.
The whole logic can be done with just custom properties calc and var.
So the CSS could look like this:
function setCurrentHealth(val) {
let root = document.documentElement;
root.style.setProperty('--curr-health', val);
}
function setUserLevel(level) {
let root = document.documentElement;
root.style.setProperty('--user-level', level);
}
document.querySelector('#level').addEventListener('input', (evt) => {
setUserLevel(evt.target.value)
})
document.querySelector('#health').addEventListener('input', (evt) => {
setCurrentHealth(evt.target.value)
})
:root {
--user-level: 1;
--curr-health: 10;
--base-health-level: 150;
--additional-health-per-level: 10;
}
.current-health {
width: calc(var(--curr-health) / (var(--base-health-level) + var(--additional-health-per-level) * (var(--user-level) - 1)) * 100%);
height: 100%;
background-color: green;
}
.health-bar {
border: 1px solid black;
width: 300px;
height: 20px;
}
<div class="health-bar">
<div class="current-health">
</div>
</div>
Level: <input value="1" id="level"><br>
Health: <input value="10" id="health">

JavaScript and CSS not working as intended

In the following code, when I put the div with class thumb-bar, the JavaScript I have written works but if place use it after full-img div tag, it doesn't work also the CSS attribute cursor: pointer for the thumb-bar div is not applied.
Edit - I mean the click listeners I apply using JavaScript are not working
CSS:
body {
width: 640px;
margin: 0 auto;
}
.full-img {
position: relative;
display: block;
width: 640px;
height: 480px;
}
button {
border: 0;
background: rgba(150, 150, 150, 0.6);
text-shadow: 1px 1px 1px white;
border: 1px solid #999;
position: absolute;
cursor: pointer;
top: 2px;
left: 2px;
}
.thumb-bar img {
display: block;
width: 20%;
float: left;
cursor: pointer;
}
HTML:
<div class="thumb-bar"></div>
<div class="full-img">
<img class="displayed-img" src="images/pic1.jpg">
<button class="dark">Darken</button>
</div>
JavaScript:
var displayedImage = document.querySelector('.displayed-img');
var thumbBar = document.querySelector('.thumb-bar');
btn = document.querySelector('button');
var overlay = document.querySelector('.overlay');
for (var i = 1; i <= 5; i++) {
var newImage = document.createElement('img');
newImage.setAttribute('src', 'images/pic' + i + '.jpg');
thumbBar.appendChild(newImage);
newImage.addEventListener('click', function(e) {
displayedImage.setAttribute('src', e.target.getAttribute('src'))
});
}
Because you're floating .thumb-bar img, those images are taken out of the page flow which results in the .thumb-bar element to have a height of 0, which in turn causes subsequent content to not be pushed down. That means that the .full-img element is rendered on top of the images and obscures them from the mouse pointer.
You need to clear the floats in order to get the .full-img element to render below them. This can be done by either making sure the .thumb-bar clear it's own content:
.thumb-bar {
overflow: hidden;
}
... or make the .full-img element itself clear them:
.full-img {
clear: both;
}

Animate line wrapping of inline-block elements on content change

I have a container with a fixed width and overflow: auto; set.
It contains multiple items (display: inline-block;), also with fixed dimensions.
So if the container has enough children, the items will wrap around and create a grid-like pattern.
Now I dynamically remove children from the beginning and want to animate the position change of the items that are filling up the freed space and moving up from the start of a line to the end of the line above.
var counter = 1;
document.getElementById("additem").onclick = function() {
var item = document.createElement("div");
item.innerText = counter;
counter++;
document.getElementById('container').appendChild(item);
}
document.getElementById("removeitem").onclick = function() {
document.getElementById('container').removeChild(
document.getElementById('container').children[0]
);
}
#container {
width: 280px;
overflow: auto;
border: 1px solid red;
padding: 5px;
text-align: center;
}
#container > div {
width: 80px;
height: 90px;
border: 1px solid green;
margin: 5px;
display: inline-block;
}
<button id="additem">add item</button>
<button id="removeitem">remove item</button>
<div id="container">
</div>
EDIT: I am also able to use jQuery to accomplish this behaivor.
A reasonably clean solution is to use an inline style that sets the removed element's opacity to 0, accompanied by a transition and a setTimeout timed to run as soon as the transition finishes, effectively fading out the element and then sliding everything else into place. Here's a quick snippet I put together:
var counter = 1;
document.getElementById("additem").onclick = function() {
var item = document.createElement("div");
item.innerText = counter;
counter++;
document.getElementById('container').appendChild(item);
}
document.getElementById("removeitem").onclick = function() {
document.getElementById('container').children[0].setAttribute('style', 'opacity: 0');
window.setTimeout(function() {
document.getElementById('container').removeChild(
document.getElementById('container').children[0]
)
}, 300);
}
#container {
width: 280px;
overflow: auto;
border: 1px solid red;
padding: 5px;
text-align: center;
}
#container>div {
width: 80px;
height: 90px;
border: 1px solid green;
margin: 5px;
display: inline-block;
transition: opacity 0.3s;
}
<button id="additem">add item</button>
<button id="removeitem">remove item</button>
<div id="container">
</div>

Style input range background before thumb

I want to style the bar before the thumb with a different color on a range input. I'v tried looking for a solution but I havent found a proper solution. This is what I need it to look like:
Chrome doesnt seem to support input[type='range']::-webkit-slider-thumb:before anymore and I am at a loss how to style it. Here's what I have so far:
input[type='range'] {
min-width: 100px;
max-width: 200px;
&::-webkit-slider-thumb {
-webkit-appearance: none !important;
background-color: #white;
border: 1px solid #gray-4;
height: 14px;
width: 14px;
&:hover,
&:focus,
&:active {
border-color: #blue;
background-color: #gray-2;
}
}
&::-webkit-slider-runnable-track {
background-color: #gray-2;
border: 1px solid #gray-4;
}
}
document.querySelectorAll(".__range").forEach(function(el) {
el.oninput =function(){
var valPercent = (el.valueAsNumber - parseInt(el.min)) /
(parseInt(el.max) - parseInt(el.min));
var style = 'background-image: -webkit-gradient(linear, 0% 0%, 100% 0%, color-stop('+ valPercent+', #29907f), color-stop('+ valPercent+', #f5f6f8));';
el.style = style;
};
el.oninput();
});
.__range{
margin:30px 0 20px 0;
-webkit-appearance: none;
background-color: #f5f6f8;
height: 3px;
width: 100%;
margin: 10px auto;
}
.__range:focus{
outline:none;
}
.__range::-webkit-slider-thumb{
-webkit-appearance: none;
width: 20px;
height: 20px;
background: #29907f;
border-radius: 50%;
cursor: -moz-grab;
cursor: -webkit-grab;
}
<input class="__range" id="rng" name="rng" value="30" type="range" max="100" min="1" value="100" step="1">
The trick in the post referenced by shambalambala is clever, but I don't think it will work in this case if you want to get something that looks exactly like the image you show. The approach there is to put a shadow on the thumb to create the different coloring to the left of the thumb. Since the shadow extends in the vertical, as well as the horizontal, direction, you also have to add overflow:hidden to the range or the track in order to clip the shadow. Unfortunately, this also clips the thumb. So if you want a thumb that extends beyond the track in the vertical dimension, such as in the image you show where the thumb is a circle with a diameter larger than the track width, this won't work.
I'm not sure there's a pure CSS solution to this problem. With JavaScript, one way around this is to make two range elements that overlap exactly. For one range element, you will see only the thumb and for one you will see only the track. You can use the shadow approach on the track element to get the different color before the thumb. You can style the thumb on the thumb range however you want, and since overflow is not set to hidden for this range element, it can extend beyond the width of the track. You can then use JavaScript to yoke the two range elements together, so that when you move the thumb on the thumb-visible element, the value of the track-visible element also changes.
For example (works in webkit browsers--will need some additional styling for other browsers):
<html>
<head>
<style>
.styled_range {
position: relative;
padding: 10px;
}
input[type=range] {
-webkit-appearance: none;
width: 600px;
background: transparent;
position: absolute;
top: 0;
left: 0;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
}
input[type=range]:focus {
outline: none;
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 12px;
}
.track_range {
pointer-events: none;
}
.track_range::-webkit-slider-runnable-track {
background: #D0D0D0;
border-radius: 6px;
overflow: hidden;
}
.track_range::-webkit-slider-thumb {
-webkit-appearance: none;
background: transparent;
height: 1px;
width: 1px;
box-shadow: -600px 0 0 600px #666666;
}
.thumb_range::-webkit-slider-runnable-track {
background: transparent;
cursor: pointer;
}
.thumb_range::-webkit-slider-thumb {
-webkit-appearance: none;
border: 3px solid #ffffff;
border-radius: 20px;
height: 40px;
width: 40px;
background: #1180AD;
cursor: pointer;
margin: -12px 0px 0px 0px;
}
</style>
</head>
<body>
<form>
<div class="styled_range">
<input type="range" class="track_range"/>
<input type="range" class="thumb_range"/>
</div>
<br/>
<div class="styled_range">
<input type="range" class="track_range"/>
<input type="range" class="thumb_range"/>
</div>
</form>
</body>
<script>
window.onload = function() {
var styledRanges = document.getElementsByClassName('styled_range');
for (var i=0; i<styledRanges.length; i++) {
var thumbRange = null, trackRange = null;
for (var j=0; j<styledRanges[i].children.length; j++) {
var child = styledRanges[i].children[j];
if (child.className === 'thumb_range')
var thumbRange = child;
else if (child.className === 'track_range')
var trackRange = child;
}
thumbRange.oninput = function(thumbRange, trackRange) {
return function(e) {
trackRange.value = thumbRange.value;
};
}(thumbRange, trackRange);
}
}
</script>
</html>

html multiple columns unordered list with header

I have a unordered list that based on my Style Sheet will either have 1, 2 or 3 columns.
I want to create a heading for the list and it should also respond to the screen size, so if I have 2 column list I should see 2 headings align with the list, or 3 if I have 3 columns.
The list if items will be dynamic so there can be any amount of items listed.
Example
http://jsfiddle.net/francoist/AtX4K/1/
NOTE: the Log No Dimension (heading) in picture below is what I'm trying to add.
Result
CSS
body{
font-family: "Tahoma";
}
ul {
border-bottom: 1.5px solid #ccc;
border-top: 1.5px solid #ccc;
columns: 1;
-webkit-columns: 1;
-moz-columns: 1;
margin: 0;
padding: 0;
list-style: none;
}
li{
position: relative;
border-bottom: 1px dotted #ccc;
list-style: none;
list-style-type: none;
width: 100%;
padding: 0;
}
ul li a {
float: right; /* width of icon + whitespace */
padding: 5px;
font-size: 14px;
}
labeltotal{
float: right;
font-size: 24px;
}
labeldetail{
font-size: 24px;
}
labeldetailsmall{
font-size: 14px;
}
#media (min-width: 480px) {
ul {
border-bottom: 1.5px solid #ccc;
border-top: 1.5px solid #ccc;
columns: 1;
-webkit-columns: 1;
-moz-columns: 1;
margin: 0;
padding: 0;
list-style: none;
}
}
#media (min-width: 568px) {
ul {
border-bottom: 1.5px solid #ccc;
border-top: 1.5px solid #ccc;
columns: 2;
-webkit-columns: 2;
-moz-columns: 2;
margin: 0;
padding: 0;
list-style: none;
}
}
#media (min-width: 768px) {
ul {
border-bottom: 1.5px solid #ccc;
border-top: 1.5px solid #ccc;
columns: 3;
-webkit-columns: 3;
-moz-columns: 3;
margin: 0;
padding: 0;
list-style: none;
}
}
HTML
<ul>
<li>
<labeldetailsmall>LOG000001 </labeldetailsmall><labeldetail>2,1 x2,3</labeldetail>
edit
delete
</li>
<li>
<labeldetailsmall>LOG000002 </labeldetailsmall><labeldetail>2,1 x 2,3</labeldetail>
edit
delete
</li>
<li>
</ul>
I do not recommend you to use this function, as it is rife with improper programming practices and may not be that efficient.
It works fine on the first page load, but on window resize, it becomes a 'little' hectic.
However, I wanted to challenge myself today and I took it on.
What this function basically does is that it gets the coordinates of all occurrences of a specified HTML tag (labeldetailsmall in this case), picks the elements closest to the top and appends a heading to each while removing the previously inserted heading elements.
The CSS is fuzzy and needs improving (for there is some overlapping of elements).
Once again, use this at your own risk... I just wanted to play with code, and ended up with this.
I just hope that you would get an idea of one way you could use to achieve what you want.
[UPDATED]
The jQuery:
function addThoseHeadings(elementTagInput, yourHEADING){
var elementTag = $( elementTagInput );
var allElementsObject = {positions : {}};
$(elementTag).each(function( index ) {
var theOffset = $(this).offset();
allElementsObject.positions[index] = {
left: theOffset.left,
top: theOffset.top
};
});
var arr = Object.keys( allElementsObject ).map(function ( key, subkey ) { return allElementsObject[key][subkey]['top']; });
var minimumOffset = Math.min.apply( null, arr );
$.each(allElementsObject.positions, function( indexUnwanted, valueOffsets ) {
if( valueOffsets.top == minimumOffset ){
var elementToAppendTo = document.elementFromPoint( valueOffsets.left, valueOffsets.top );
$( elementToAppendTo ).before( '<span class="replaceThese" style="left:'+(valueOffsets.left)+'px;top:'+(valueOffsets.top-35)+'px;">'+yourHEADING+'</span>' );
}
});
}
var yourHEADING = "Log No";
addThoseHeadings( "labeldetailsmall", yourHEADING );
$(window).resize(function() {
$( ".replaceThese" ).remove();
addThoseHeadings( "labeldetailsmall", yourHEADING );
});
The CSS (needs working on):
span {
display: inline-block;
position: fixed;
}
I hope that this would be of some use to someone!
Try this:
Instead of using px(pixels) for size, try using %.
eg: font-size: 300%;
Note: % value can be increased or decreased as you need.

Categories

Resources