Why last function is applying to other elements also on 2nd change - javascript

I have created a color changer for different properties like border & background for elements.
Color changing 1 at a time but issue occurs when I click on next element , now the color of both elements changes (on next click) . Is there a way to change only 1 at a time .
The method to solve this can be creating a color-picker with each click and remove when work is done but if possible can the solution be regarding the input color-picker in html
To see the issue :
1)Click on any circle & change its color (works fine)
2)Now click on any other circle and try to change its color
Issue seen : Now on 2nd step both circles color changes at same time
var restyleBG = document.getElementsByClassName("restyleBackground")
for (let i = 0; i < restyleBG.length; i++) {
restyleBG[i].addEventListener('click', changeBGcolor)
function changeBGcolor() {
event.stopPropagation()
var colorPicker = document.getElementById("colorClock");
colorPicker.click();
colorPicker.addEventListener('input', function() {
var colorPickerVal = colorPicker.value;
restyleBG[i].style.backgroundColor = colorPickerVal;
})
}
}
#clockStyleCircle {
position: absolute;
width: 16vw;
height: 16vw;
text-align: center;
padding: 0%;
top: 28.5%;
left: 28.5%;
border-radius: 50%;
border: 3px solid black;
background-color: rgb(255, 233, 35);
z-index: 1;
}
#clockOuterCircle {
display: flex;
justify-content: center;
align-items: center;
width: 42vw;
height: 42vw;
margin: auto;
border-radius: 50%;
border: 4px solid rgb(255, 62, 62);
background-color: rgb(253, 133, 133);
user-select: none;
}
#another-circle {
width: 50px;
height: 50px;
border-radius: 50%;
border: 4px green solid;
background-color: blue;
position: absolute;
top: 20px;
left: 20px;
}
.colour-picker {
display: none;
}
<body>
<input type="color" name="colorClock" id="colorClock">
<div id="clockOuterCircle" class="restyleBackground">
<div id="clockStyleCircle" class="restyleBackground"></div>
</div>
<!-- another circle -->
<div id="another-circle" class="restyleBackground"></div>
<!-- ... -->
</body>
Thanks for help in advance

What is going on ?
Your problem here is that for every time you click on a circle you add an EventListener to your colorPicker which then changes the color of the circle. So every time you change the value of the colorPicker, the circles that got clicked on change their color.
How to achieve what you want
You could try to remove the EventListener after the change happened, but this isn't good practice. What you should do is create a global variable that holds the index to the current circle of the circles array that got clicked on and add an EventListener to the input element, that changes the color of the circle with the index of that reference variable. Below you can see the code.
var restyleBG = document.getElementsByClassName("restyleBackground")
let current = 0;
var colorPicker = document.getElementById("colorClock");
colorPicker.addEventListener('input', function() {
restyleBG[current].style.backgroundColor = colorPicker.value;
})
for (let i = 0; i < restyleBG.length; i++) {
restyleBG[i].addEventListener('click', changeBGcolor)
function changeBGcolor() {
event.stopPropagation()
colorPicker.click();
current = i;
}
}
#clockStyleCircle {
position: absolute;
width: 16vw;
height: 16vw;
text-align: center;
padding: 0%;
top: 28.5%;
left: 28.5%;
border-radius: 50%;
border: 3px solid black;
background-color: rgb(255, 233, 35);
z-index: 1;
}
#clockOuterCircle {
display: flex;
justify-content: center;
align-items: center;
width: 42vw;
height: 42vw;
margin: auto;
border-radius: 50%;
border: 4px solid rgb(255, 62, 62);
background-color: rgb(253, 133, 133);
user-select: none;
}
#another-circle {
width: 50px;
height: 50px;
border-radius: 50%;
border: 4px green solid;
background-color: blue;
position: absolute;
top: 20px;
left: 20px;
}
.colour-picker {
display: none;
}
<body>
<input type="color" name="colorClock" id="colorClock">
<div id="clockOuterCircle" class="restyleBackground">
<div id="clockStyleCircle" class="restyleBackground"></div>
</div>
<!-- another circle -->
<div id="another-circle" class="restyleBackground"></div>
<!-- ... -->
</body>

As I said in comments on every click you were adding new event listeners so after the second click there you have more than one event registered. so from the second click, your input Listener will call all previous color changes, that's why it is changing the color of all 3 circles.
I have removed the listener after every color change so this code works fine
Check the console once to get the listener calls, also check by removing the "removeEventListener" and check how many "input event called" will appear after changing color if all three circles (this will help to understand the problem in your code )
Also, you may not be needed to add an input evenlistener inside the loop, I have approached same to understand the problem in your code
You can add eventListner outside the loop
So that you may not need to remove it
var restyleBG = document.getElementsByClassName("restyleBackground")
var colorPicker = document.getElementById("colorClock");
var element;
for (let i = 0; i < restyleBG.length; i++) {
restyleBG[i].addEventListener('click', ()=> changeBGcolor(restyleBG[i]))
}
function changeBGcolor(restyle) {
event.stopPropagation()
colorPicker.click();
element = restyle
colorPicker.addEventListener('input', respond)
}
function respond() {
var colorPickerVal = colorPicker.value;
console.log('input event called')
element.style.backgroundColor = colorPickerVal;
}
colorPicker.addEventListener('change',function (){
console.log('input event removed')
colorPicker.removeEventListener('input', respond)
})
#clockStyleCircle {
position: absolute;
width: 16vw;
height: 16vw;
text-align: center;
padding: 0%;
top: 28.5%;
left: 28.5%;
border-radius: 50%;
border: 3px solid black;
background-color: rgb(255, 233, 35);
z-index: 1;
}
#clockOuterCircle {
display: flex;
justify-content: center;
align-items: center;
width: 42vw;
height: 42vw;
margin: auto;
border-radius: 50%;
border: 4px solid rgb(255, 62, 62);
background-color: rgb(253, 133, 133);
user-select: none;
}
#another-circle {
width: 50px;
height: 50px;
border-radius: 50%;
border: 4px green solid;
background-color: blue;
position: absolute;
top: 20px;
left: 20px;
}
.colour-picker {
display: none;
}
<body>
<input type="color" name="colorClock" id="colorClock">
<div id="clockOuterCircle" class="restyleBackground" >
<div id="clockStyleCircle" class="restyleBackground" ></div>
</div>
<!-- another circle -->
<div id="another-circle" class="restyleBackground" ></div>
<!-- ... -->
</body>

Related

How to change the border color of a div when clicking a radio button inside the same div?

So I'm currently working on a personal project. And came across with a problem.
I want my border color of this div to green when the user clicks the radio button inside that div. Like this:
Here
But my current version looks like this:
Here
Here is my CSS and HTML
.backProjectCard2 {
padding-right: 10px;
}
.backProjectCard {
border: 2px solid #ececec;
border-radius: 10px;
margin: 0 0 20px;
padding-top: 24px;
position: relative;
right: 5px;
width: 580px;
}
/*For Input and .checkmark*/
.backProjectCard input {
position: relative;
height: 20px;
width: 20px;
left: 20px;
}
.input {
position: absolute;
opacity: 0;
cursor: pointer;
}
.backProject input:checked~.checkmark {
background-color: #fff;
}
.checkmark {
position: absolute;
top: 27px;
left: 20px;
height: 18px;
width: 18px;
background-color: #fff;
border-radius: 50%;
border: solid #e0e0e0 1.7px;
z-index: -1;
}
.backProject input:checked~.checkmark:after {
display: block;
}
.backProject .checkmark:after {
top: 2px;
left: 3px;
width: 10px;
height: 10px;
border-radius: 50%;
background: hsl(176, 50%, 47%);
}
.checkmark:after {
z-index: 1;
content: "";
position: absolute;
display: none;
}
<div class="backProjectCard backProjectCard2">
<input onclick="radioCheck();" type="radio" class="input">
<span class="checkmark"></span>
<h4 id="card-h">Bamboo Stand</h4>
<h3>Pledge $25 or more</h3>
<p id="left">left</p>
<h2 id="card2-num">101</h2>
<p>You get an ergonomic stand made of natural baamboo. You've helped us launch our promotional campaign, and you'll be added to a special Backer member list.</p>
<hr>
<div class="pledgeSection">
<p>Enter your pledge</p>
<button class="btn-1 card2Btn">Continue</button>
<button class="btn-2">
<p>$</p>
<input value="25" class="input-price input-price2" type="number">
</button>
</div>
JS (Only for clicking the radio button twice):
function radioCheck() {
timesClicked++
if (timesClicked > 1) {
$("input").prop("checked", false)
timesClicked = 0;
}
}
function colorchange() {
var x = document.getElementById('checker');
var y = document.getElementById('radiobox');
if (x.checked === true) {
y.style.borderColor = "green";
} else {
y.style.borderColor = "silver";
}
}
#radiobox {
width: 300px;
height: 200px;
border: 5px solid;
border-color: silver;
}
<div id="radiobox">
<input type="radio" onclick="colorchange();" id="checker"></input>
</div>
To keep it simple, I'll just use a short example and you can just apply it to your own example.
This is how you can do that
function radioCheck(){
// Get the checkbox
var checkBox = document.getElementById("myInputCheck");
// Get the div with border
var divBorder = document.getElementsByClassName("backProjectCard")[0]
// If the checkbox is checked, display the border
if (checkBox.checked == true){
divBorder.classList.remove("backProjectCard"); //remove "backProjectCard"
divBorder.classList.add("newBorder"); //add the new border with new color
} else {
divBorder.classList.remove("newBorder");
divBorder.classList.add("backProjectCard");
}
}
.backProjectCard2 {
padding-right: 10px;
}
.backProjectCard {
border: 2px solid #ececec;
border-radius: 10px;
margin: 0 0 20px;
padding-top: 24px;
position: relative;
right: 5px;
width: 580px;
}
/*For Input and .checkmark*/
.backProjectCard input {
position: relative;
height: 20px;
width: 20px;
left: 20px;
}
.input {
position: absolute;
opacity: 1;
cursor: pointer;
}
.checkmark {
position: absolute;
top: 27px;
left: 20px;
height: 18px;
width: 18px;
background-color: #fff;
border-radius: 50%;
border: solid #e0e0e0 1.7px;
z-index: -1;
}
.newBorder{
border: 2px solid #177972 !important;
border-radius: 10px;
margin: 0 0 20px;
padding-top: 24px;
position: relative;
right: 5px;
width: 580px;
}
<div class="backProjectCard backProjectCard2">
<input onclick="radioCheck();" type="radio" id="myInputCheck">
<h4 >Bamboo Stand</h4>
<h3>Pledge $25 or more</h3>
<p >left</p>
<h2 >101</h2>
<p>You get an ergonomic stand made of natural baamboo. You've helped us launch our promotional campaign, and you'll be added to a special Backer member list.</p>

Add rendered images to array onclick for submission using JS

I currently have a functionality where the user can upload and display multiple images at once as a preview on top of a modal. Ideally, I would like to allow the user to click on one of the displayed images and add it to an array on a click event so that they can then hit a button to submit the images for processing somewhere. I've tried for a few hours trying to code this out but have hit a brick wall and wouldn't mind some guidance on the matter! I'd love to be able to implement only HTML, CSS and vanilla JS... any suggestions or offerings of help would be appreciated! I searched online a fair bit but couldn't really grasp many of the concepts offered...
<!--Modal code: -->
<div id="simpleModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<span class="closeBtn">×</span>
<h2>Image search and processing: </h2>
</div>
<div class="modal-body">
<form id="modal-form" class="form">
<label for="files">Select multiple files: </label>
<input id="files" target="_blank" type="file" onchange="previewFiles()" multiple/>
<output id="result">
<button type="submit" class="floating-btn" value ="submit">+</button>
<button type="reset" class="floating-btn2" value ="reset" onclick="return hideImage()">x</button>
</form>
</div>
<div id="preview"></div>
</div>
</div>
<script>
//code to render image files to modal
function previewFiles() {
var preview = document.querySelector('#preview');
var files = document.querySelector('input[type=file]').files;
function readAndPreview(file) {
// Make sure `file.name` matches our extensions criteria
if ( /\.(jpe?g|png|gif)$/i.test(file.name) ) {
var reader = new FileReader();
reader.addEventListener("load", function () {
var image = new Image();
//styling in JS //
image.height = 160;
image.width = 160;
image.style.flexDirection = "row";
image.title = file.name;
image.src = this.result;
preview.appendChild( image );
}, false);
reader.readAsDataURL(file);
}
}
if (files) {
[].forEach.call(files, readAndPreview);
}
}
//delete form
function hideImage() {
document.getElementById("modal-form").reset(); //reset form
var preview = document.querySelector("#preview");
preview.innerHTML = '' //set preview to null
</script>
}
/* floating buttons: */
.floating-btn{
width: 80px;
height: 80px;
background: #0B406D;
display: flex;
border-radius: 50%;
color: white;
font-size: 40px;
align-items: center;
justify-content: center;
text-decoration: none;
box-shadow: 2px 2px 5px rgba(0,0,0,0.25);
position: fixed;
right: 120px;
bottom: 20px;
outline: blue;
border: none;
cursor: pointer;
}
.floating-btn:hover {
background: #4D89C8;
}
.floating-btn2{
width: 80px;
height: 80px;
background: #0B406D;
display: flex;
border-radius: 50%;
color: white;
font-size: 40px;
align-items: center;
justify-content: center;
text-decoration: none;
box-shadow: 2px 2px 5px rgba(0,0,0,0.25);
position: fixed;
right: 20px;
bottom: 20px;
outline: blue;
border: none;
cursor: pointer;
}
.floating-btn2:hover {
background: #4D89C8;
}
/*Modal styling: */
.modal{
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
position: fixed;
top: 0;
z-index: 1;
display: none;
justify-content: center;
align-items: center;
}
.modal-content{
width: 80%;
height: 80%;
background-color: rgba(255, 255, 255, 0.9);
border-radius: 4px;
padding: 15px;
margin: 20% auto;
box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2), 0 7px 20px rgba(0, 0, 0, 0.17);
animation-name: modalopen;
animation-duration: 1s;
flex-direction: column;
justify-content: space-around;
}
.modal-header{
font-size:12pt;
color: black;
}
.modal-header h2{
margin: 0;
}
.modal-body{
width: 33.33%;
padding: 5px;
}
.closeBtn{
color: #ccc;
float: right;
font-size: 50px;
}
.closeBtn:hover,.closeBtn:focus{
color: red;
text-decoration: none;
cursor: pointer;
}
#keyframes modalopen{
from{opacity: 0}
to {opacity: 1}
}
/*Image displaying style: */
form{
margin-top:10px;
padding: 5px;
border-radius: 4px;
margin: 0 auto;
}
a img{
float: left;
width: 150px;
height: 150px;
padding-right: 15px;
box-sizing: border-box;
}
img:hover {
transform: scale(1.5);
cursor: pointer;
}
While there can be complicated ways like using FormData and ajax to submit the form it's better to always go with simpler ones. One of such is below
Add a hidden field in your form
<input type="hidden" name="list" id="list">
</form>
Create a variable that will hold an array var sList = []
Now just take this function it appends to that array and serializes that data into the hidden field
function addToArr(item){
var index = sList.indexOf(item);
if (index == -1) { //if not already added
sList.push(item) // add
}
document.getElementById('list').value = JSON.stringify(sList);
}
That's it now in your reader load event listener add this one line
reader.addEventListener("load", function () {
var image = new Image();
//other code
//..
image.src = this.result;
image.onclick = function(){ addToArr(file.name); } // <-- this line
preview.appendChild( image );
}, false);
Now whenever user clicks any image, its name will get into the list array and therefore in hidden field (You may verify using inspect element in devtools). So when you submit the form, on you server side just decode/parse the json and you know which images user wants (the names) by that you can filter on the actual file objects. You haven't told what language you are using at the server so for now this should suffice

Render JSX-elements as multi-level pyramid

I need to create a pyramid figure with 4 levels division something like this:
Although I have achieved the same with the following code set:
const PyramidChart = () => {
return (
<div className="d-flex flex-column align-items-center pyramid_wrap">
<div className="category_one">
<h6>2</h6>
</div>
<div className="category_two">
<h6>8</h6>
</div>
<div className="category_three">
<h6>11</h6>
</div>
<div className="category_four">
<h6>16</h6>
</div>
</div>
);
};
ReactDOM.render(
<PyramidChart />,
document.getElementById('root')
);
.pyramid_wrap {
height: 100%;
text-align: center;
}
.category_one {
width: 70px;
height: 30px;
border-left: 35px solid transparent;
border-right: 35px solid transparent;
border-bottom: 50px solid tomato;
}
.category_two {
width: 116px;
height: 30px;
border-left: 22px solid transparent;
border-right: 22px solid transparent;
border-bottom: 28px solid orange;
}
.category_three {
width: 162px;
height: 30px;
border-left: 22px solid transparent;
border-right: 22px solid transparent;
border-bottom: 28px solid cyan;
}
.category_four {
width: 208px;
height: 30px;
border-left: 22px solid transparent;
border-right: 22px solid transparent;
border-bottom: 28px solid teal;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
And got something like this:
But the issue I am unable to resolve is to align the text in top-level pyramid area to center. It is somehow always out of sync with the it is aligned in.
Any help to rectify this issue is appreciated :)
Let's try moving from CSS Triangle to :before and :after with skew transform property.
I haven't changed your HTML, just add a .value class to your <h6> to style them.
Basically all you have to do is to set to every <div> a :before with a negative degree angle and a :after with a positive degree angle and give them the same background color, in order to match.
Only for the top-level <div> I used a CSS Triangle, so you already know how it works.
In order to make the values horizontally and vertically aligned I used flexbox on the parent, combined with justify-content: center; (horizontal align) and align-items: center; (vertical align). Don't forget to always add a line-height:1em; and remove margin to the element you want to be vertical aligned. If the line-height is not equal to its actual height it will always be some pixels up or down the middle axe.
.pyramid_wrap {
margin-top: 200px;
height: 100%;
text-align: center;
}
.category_one,
.category_two,
.category_three,
.category_four {
position: relative;
margin: 6px auto;
display: flex;
justify-content: center;
align-items: center;
}
.category_one:before,
.category_one:after,
.category_two:before,
.category_two:after,
.category_three:before,
.category_three:after,
.category_four:before,
.category_four:after {
position: absolute;
top: 0;
display: block;
width: 30px;
height: 100%;
content: "";
}
.category_one:before,
.category_two:before,
.category_three:before,
.category_four:before {
left: -15px;
transform: skew(-25deg);
}
.category_one:after,
.category_two:after,
.category_three:after,
.category_four:after {
right: -15px;
transform: skew(25deg);
}
.category_one {
width: 20px;
height: 40px;
background: tomato;
}
.category_one:before,
.category_one:after {
width: 30px;
height: 40px;
background: tomato;
}
.category_one:before {
left: -16px;
top: 0;
}
.category_one:after {
right: -16px;
top: 0;
}
.category_one .value:after {
position: absolute;
z-index: -1;
top: -55px;
left: 50%;
transform: translateX(-50%);
content: "";
display: block;
width: 0;
height: 0;
border-style: solid;
border-width: 0 28px 70px 28px;
border-color: transparent transparent tomato transparent;
}
.category_two {
width: 70px;
height: 40px;
background: orange;
}
.category_two:before,
.category_two:after {
width: 40px;
background: orange;
}
.category_two:before {
left: -12px;
}
.category_two:after {
right: -12px;
}
.category_three {
width: 120px;
height: 40px;
background: cyan;
}
.category_three:before,
.category_three:after {
background: cyan;
}
.category_three:before {
left: -9px;
}
.category_three:after {
right: -9px;
}
.category_four {
width: 150px;
height: 40px;
background: teal;
}
.category_four:before,
.category_four:after {
background: teal;
}
.value {
margin: 0;
position: relative;
z-index: 3;
color: #fff;
font-size: 16px;
font-family: Arial, sans-serif;
font-weight: normal;
line-height: 1em;
}
<div class="d-flex flex-column align-items-center pyramid_wrap">
<div class="category_one">
<h6 class="value">2</h6>
</div>
<div class="category_two">
<h6 class="value">8</h6>
</div>
<div class="category_three">
<h6 class="value">11</h6>
</div>
<div class="category_four">
<h6 class="value">16</h6>
</div>
</div>
One of the possible solutions is to use CSS mask over the entire pyramid's wrapper. It may be not well supported as of now, yet provides genuine way of shaping your pyramid with SVG path (triangle):
In order not to let the mask shrink (hiding upper and lower layers), you may need to preserve the min-width of a wrapper (equal to number of layers multiplied by layer height - 3em).
To avoid layer labels falling outside of the mask, you may need to center the mask according to labels position (mask-position: center)
Live-demo, implementing that concept, might look as follows:
const { render } = ReactDOM,
rootNode = document.getElementById('root')
const pyramidItems = [{label:'2', color: '#f47660'}, {label:'8', color:'#fcae60'}, {label:'11', color:'#a7e6db'}, {label:'16',color:'#79d4c5'}]
const Pyramid = ({items}) => (
<div
className="wrapper"
style={{minWidth:`${items.length}*3em`}}
>
{
items.map(({label,color},key) => (
<div
key={key}
className="layer"
style={{backgroundColor:color}}
>
{label}
</div>
))
}
</div>
)
render (
<Pyramid items={pyramidItems} />,
rootNode
)
.wrapper {
--triangle-shape: url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNTAsMCBMMTAwLDEwMCBMMCwxMDAgeiIvPjwvc3ZnPg==");
-webkit-mask-image: var(--triangle-shape);
-webkit-mask-repeat: no-repeat;
-webkit-mask-position: center;
mask-image: var(--triangle-shape);
mask-repeat: no-repeat;
mask-position: center;
display: flex;
flex-direction: column;
}
.layer {
height: 3em;
color: #fff;
font-size: 15px;
display: flex;
justify-content: center;
align-items: center;
border: .2em solid #fff;
margin: -.2em 0px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>

Why is my color not changing when clicking?

So I have a very simple code that gives no error when I run it but the problem is, it's not doing what it's supposed to do...
When I click on the div in the middle, it should change colors...
What am I missing? Can't seem to find any typo...
var panel = document.getElementById('color_panel');
document.getElementById('color_panel').addEventListener("click", function() {
var mySwitch = document.getElementById('color_panel').style.background;
if (mySwitch == "#76FF03") {
document.getElementById('color_panel').style.background = "#039BE5";
} else {
document.getElementById('color_panel').style.background = "#76FF03";
}
});
<body style="background: #37474F; margin: 0;">
<div id="color_panel" style="background: #76FF03; margin:
auto; font-family: Century Gothic; font-size: 40px; color: #37474F;
width: 200px; height: 200px; padding: 20px; margin-top: 50%;
transform: translateY(-50%); text-align: center;">
Click me!<br>or Double Click?</div>
<button style="font-size: 10px;
width: 100px; height: 20px; margin-left: 50%;
transform: translateX(-50%); border: solid 2px;
border-color: #FBC02D; border-radius: 5px;
background: #E3F2FD;" id="button" onclick="transition()">
add transition!</button>
You need to do some basic debugging. Add a console.log statement to examine the value you are putting into your if statement and see what it actually is.
The browser is normalising it, so mySwitch == "#76FF03" is never true.
var panel = document.getElementById('color_panel');
document.getElementById('color_panel').addEventListener("click", function() {
var mySwitch = document.getElementById('color_panel').style.background;
console.log(mySwitch);
if (mySwitch == "#76FF03") {
document.getElementById('color_panel').style.background = "#039BE5";
} else {
document.getElementById('color_panel').style.background = "#76FF03";
}
});
<body style="background: #37474F; margin: 0;">
<div id="color_panel" style="background: #76FF03; margin:
auto; font-family: Century Gothic; font-size: 40px; color: #37474F;
width: 200px; height: 200px; padding: 20px; margin-top: 50%;
transform: translateY(-50%); text-align: center;">
Click me!<br>or Double Click?</div>
<button style="font-size: 10px;
width: 100px; height: 20px; margin-left: 50%;
transform: translateX(-50%); border: solid 2px;
border-color: #FBC02D; border-radius: 5px;
background: #E3F2FD;" id="button" onclick="transition()">
add transition!</button>
This type of problem is generally better handled by putting all your styles in a separate stylesheet and then adjusting the classes that an element is a member of.
var panel = document.getElementById('color_panel');
panel.addEventListener("click", function() {
panel.classList.toggle("other");
});
body {
background: #37474F;
margin: 0;
}
#color_panel {
background: #76FF03;
margin: auto;
font-family: Century Gothic;
font-size: 40px;
color: #37474F;
width: 200px;
height: 200px;
padding: 20px;
margin-top: 50%;
transform: translateY(-50%);
text-align: center;
}
#color_panel.other {
background: #039BE5;
}
#button {
font-size: 10px;
width: 100px;
height: 20px;
margin-left: 50%;
transform: translateX(-50%);
border: solid 2px;
border-color: #FBC02D;
border-radius: 5px;
background: #E3F2FD;
}
<div id="color_panel">
Click me!<br>or Double Click?
</div>
<button style="" id="button" onclick="transition()">
add transition!
</button>
Your code seems to correct, you are getting rgb(118, 255, 3) in the variable mySwitch so its not going in the if the condition
Your code should be
<script type="text/javascript">
var panel = document.getElementById('color_panel');
document.getElementById('color_panel').addEventListener("click", function() {
var mySwitch = document.getElementById('color_panel').style.background;alert(mySwitch);
if (mySwitch == "rgb(118, 255, 3)") {
document.getElementById('color_panel').style.background = "#039BE5";
} else {
document.getElementById('color_panel').style.background = "#76FF03";
}
});
</script>
mySwitch will give the color in rgb, which you cannot compare with the stirng. remove the inline style and add instead use class. Then use toggle to toggle the class on every click
var panel = document.getElementById('color_panel');
document.getElementById('color_panel').addEventListener("click", function() {
panel.classList.toggle('changeColor')
});
.divStyle {
background: #76FF03;
margin: auto;
font-family: Century Gothic;
font-size: 40px;
color: #37474F;
width: 200px;
height: 200px;
padding: 20px;
margin-top: 50%;
transform: translateY(-50%);
text-align: center;
}
.changeColor {
background: #039BE5
}
<body style="background: #37474F; margin: 0;">
<div id="color_panel" class='divStyle'>
Click me!<br>or Double Click?</div>
<button style="font-size: 10px;
width: 100px; height: 20px; margin-left: 50%;
transform: translateX(-50%); border: solid 2px;
border-color: #FBC02D; border-radius: 5px;
background: #E3F2FD;" id="button" onclick="transition()">
add transition!</button>
</body>
The only issue with your code is you defined the color in HEX format in HTML #76FF03 and JavaScript returns the color in RGB format by which your if condition doesn't work and in your else condition you are again applying the same background color so you thought that your code doesn't work.
You just need to match the color with the RGB format in JavaScript. rgb(118, 255, 3) is the same color as #76FF03 but in different format.
You may try this:
var panel = document.getElementById('color_panel');
panel.addEventListener("click", function(e) {
var mySwitch = e.target.style.background;
if (mySwitch == "rgb(118, 255, 3)") {
e.target.style.background = "#039BE5";
} else {
e.target.style.background = "#76FF03";
}
});
<body style="background: #37474F; margin: 0;">
<div id="color_panel" style="background: #76FF03; margin:
auto; font-family: Century Gothic; font-size: 40px; color: #37474F;
width: 200px; height: 200px; padding: 20px; margin-top: 50%;
transform: translateY(-50%); text-align: center;">
Click me!<br>or Double Click?</div>
<button style="font-size: 10px;
width: 100px; height: 20px; margin-left: 50%;
transform: translateX(-50%); border: solid 2px;
border-color: #FBC02D; border-radius: 5px;
background: #E3F2FD;" id="button" onclick="transition()">
add transition!</button>
</body>
To avoid format issue you can define the color with color Name then HTML and JavaScript both return you the same result.
By the way, you just don't need to use document.getElementById('color_panel') again and again. As you are already assigning element in var so just use that variable for addEventListener and in the addEventListener function you may use the event variable e or event whatever name you like to use for that.
That's the optional thing if you like to do.
The correct answer to your question is...
Your code is working when you click in the box. You're code isn't incorrect and you don't have any typos.
The background color is changing when the box is clicked. It's just changing the background color to the same color that it already is:
In your html file, in the first div:
style="background: #76FF03;
in your script, in the else statement:
document.getElementById('color_panel').style.background = "#76FF03";

How do I make a button like the JoinVideoCallButton in Discord?

JoinVideoCallButton
Hi!
I simply wonder if anyone here have any idea how to make such a hover effect that could be used for such double option buttons or navbars etc.
I have the css and html code for it but I have no idea how to make the effect work. Also, I wonder if it is possible without the use of Jquery?
body {
background-size: 100%;
margin: 0px;
background-color: gray;
}
.joinVideoCallButton-2Pohj0 {
-ms-flex-align: center;
-ms-flex-pack: center;
-webkit-box-align: center;
-webkit-box-pack: center;
-webkit-box-sizing: border-box;
align-items: center;
background-color: #43b581;
border-radius: 3px;
box-sizing: border-box;
cursor: pointer;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
height: 36px;
justify-content: center;
overflow: hidden;
padding: 0 14px;
position: relative;
}
.joinVideoCallButton-2Pohj0 .underlay-1LCk7B {
-webkit-transition: opacity .1s ease;
background-color: #69c49a;
border-radius: 3px;
bottom: 0;
left: 0;
margin: 2px;
position: absolute;
top: 0;
transition: opacity .1s ease;
width: 50%;
flex: 1 1 auto;
}
.joinVideoCallButton-2Pohj0 .inner-1e8n63 {
cursor: pointer;
z-index: 1;
flex: 1 1 auto;
}
.flex-lFgbSz:first-child, .horizontal-2BEEBe>.flexChild-1KGW5q:first-child {
margin-left: 0;
}
.flex-lFgbSz, .horizontal-2BEEBe>.flexChild-1KGW5q {
margin-left: 10px;
margin-right: 10px;
}
.joinVideoCallButton-2Pohj0 .callDivider-_hMb9n {
background-color: #69c49a;
height: 20px;
margin: 0 2px;
opacity: .6;
width: 2px;
}
.joinVideoCallButton-2Pohj0 .icon-3tOP24 {
height: 16px;
width: 16px;
}
.joinVideoCallButton-2Pohj0 .buttonText-1b8lyZ {
color: #f6f6f7;
font-size: 14px;
margin-left: 8px;
margin-right: 8px;
text-transform: uppercase;
}
.wrapper-1XTKlU{
background-size:cover;
min-height:100vh;
overflow:hidden
}
.flexWrapper-1ztpWj{
height:100vh
}
.flex-3B1Tl4{
display:-webkit-box;
display:-ms-flexbox;
display:flex
}
.alignStart-pnSyE6{
-ms-flex-align:start;
-webkit-box-align:start;
align-items:flex-start
}
.alignEnd-3PVyen{
-ms-flex-align:end;
-webkit-box-align:end;
align-items:flex-end
}
.alignCenter-3VxkQP{
-ms-flex-align:center;
-webkit-box-align:center;
align-items:center
}
.alignStretch-1hwxMa{
-ms-flex-align:stretch;
-webkit-box-align:stretch;
align-items:stretch
}
.alignBaseline-4enZzv{
-ms-flex-align:baseline;
-webkit-box-align:baseline;
align-items:baseline
}
.justifyStart-2yIZo0{
-ms-flex-pack:start;
-webkit-box-pack:start;
justify-content:flex-start
}
.justifyEnd-1ceqOU{
-ms-flex-pack:end;
-webkit-box-pack:end;
justify-content:flex-end
}
.justifyCenter-29N31w{
-ms-flex-pack:center;
-webkit-box-pack:center;
justify-content:center
}
.justifyBetween-1d1Hto{
-ms-flex-pack:justify;
-webkit-box-pack:justify;
justify-content:space-between
}
.horizontal-2VE-Fw>.spacer-2Aeq3k,.horizontalReverse-k5PqxT>.spacer-2Aeq3k,.vertical-3X17r5>.spacer-2Aeq3k{
min-height:1px
}
.horizontal-2BEEBe>.flex-lFgbSz,.horizontal-2BEEBe>.flexChild-1KGW5q{
margin-left:10px;
margin-right:10px
}
.horizontal-2BEEBe>.flex-lFgbSz:first-child,.horizontal-2BEEBe>.flexChild-1KGW5q:first-child{
margin-left:0
}
.horizontal-2BEEBe>.flex-lFgbSz:last-child,.horizontal-2BEEBe>.flexChild-1KGW5q:last-child{
margin-right:0
}
<div class="flex-lFgbSz flex-3B1Tl4 horizontal-2BEEBe horizontal-2VE-Fw flex-3B1Tl4 directionRow-yNbSvJ justifyCenter-29N31w alignStretch-1hwxMa noWrap-v6g9vO private-channel-call-actions" style="">
<div class="joinVideoCallButton-2Pohj0">
<div class="underlay-1LCk7B" style="opacity: 1; transform: translateX(31.5781px);"></div>
<div class="flex-lFgbSz flex-3B1Tl4 horizontal-2BEEBe horizontal-2VE-Fw flex-3B1Tl4 directionRow-yNbSvJ justifyCenter-29N31w alignCenter-3VxkQP noWrap-v6g9vO inner-1e8n63" style="flex: 1 1 auto;">
<div class="flex-lFgbSz flex-3B1Tl4 horizontal-2BEEBe horizontal-2VE-Fw flex-3B1Tl4 directionRow-yNbSvJ justifyCenter-29N31w alignCenter-3VxkQP noWrap-v6g9vO callButton-205P-D" style="flex: 1 1 auto;"><img class="icon-3tOP24" src="http://discordapp.com/assets/0682cf612d4fed39efb57e0a1bcc8544.svg">
<div class="buttonText-1b8lyZ">Video</div>
</div>
<div class="callDivider-_hMb9n"></div>
<div class="flex-lFgbSz flex-3B1Tl4 horizontal-2BEEBe horizontal-2VE-Fw flex-3B1Tl4 directionRow-yNbSvJ justifyCenter-29N31w alignCenter-3VxkQP noWrap-v6g9vO callButton-205P-D" style="flex: 1 1 auto;">
<div class="buttonText-1b8lyZ">Voice</div><img class="icon-3tOP24" src="http://discordapp.com/assets/8b47456a037cc496c55ae8f871274018.svg"></div>
</div>
</div>
</div>
Part 1
The idea is fairly simple: you need to add an extra "hover box" element inside the button row, absolute position it, and finally just change the left value of the object according to the position of the cursor:
function relocateHoverBox(e) {
// Get all the needed values
// (idealy don't use as many variables)
let hoverBoxEl = e.target.closest(".btn-row").querySelector(".btn-row--hover-box");
let hoverBoxHalfWidth = hoverBoxEl.clientWidth / 2;
let containerX = e.target.closest(".btn-row").getBoundingClientRect().left;
let maxLeft = e.target.closest(".btn-row").clientWidth - hoverBoxEl.clientWidth;
let newLeftValue = e.pageX - containerX - hoverBoxHalfWidth;
// Apply new left value accordingly
if (newLeftValue >= 0) {
if (newLeftValue > maxLeft) {
hoverBoxEl.style.left = maxLeft + "px";
}
else {
hoverBoxEl.style.left = e.pageX - containerX - hoverBoxHalfWidth + "px";
}
}
else {
hoverBoxEl.style.left = 0 + "px";
}
}
// Set the hover box in the right position as soon as the mouse enters
const mouseoverHandler = function(e) {
relocateHoverBox(e);
}
// Update the hover box position
const mousemoveHandler = function(e) {
relocateHoverBox(e);
}
// Reset the hover box position
const mouseleaveHandler = function(e) {
e.target.closest(".btn-row").querySelector(".btn-row--hover-box").style.left = "";
}
document.getElementsByClassName("btn-row")[0].addEventListener('mousemove', mousemoveHandler);
document.getElementsByClassName("btn-row")[0].addEventListener('mouseenter', mouseoverHandler);
document.getElementsByClassName("btn-row")[0].addEventListener('mouseleave', mouseleaveHandler);
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #202225;
}
.btn-row {
display: flex;
justify-content: center;
align-items: center;
border-radius: 4px;
height: 48px;
background: #43b581;
position: relative;
}
.btn-row--hover-box {
width: 50%;
height: 44px;
border-radius: 2px;
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
}
.btn-row--hover-box:hover {
background: rgba(255, 255, 255, 0.25);
}
.btn {
background: transparent;
letter-spacing: .1rem;
padding: 0 1rem;
border: 0;
color: #fff;
height: 28px;
display: block;
font-weight: bold;
text-transform: uppercase;
}
<div class="btn-row">
<div class="btn-row--hover-box"></div>
<button class="btn">Option 1</button>
<button class="btn">Option 2</button>
</div>
Part 2
Also, I wonder if it is possible without the use of Jquery?
If by "Jquery" you actually mean the jQuery library, then just remember that it is a library, which means that it is only a collection of useful scripts written in a programming language, then since you can write your own scripts using that language, it is possible to do it without jQuery
If by "Jquery" you mean Javascript (the language in which jQuery is written), then it's not possible to do it without it, since you need it to follow the x-coordinate of the cursor.

Categories

Resources