Reputation: 2617
I am trying to make an interactive calendar object that displays the past 5 days. It is comprised of html <li>
and <span>
elements. I realize that jquery might be the conventional way to solve dom manipulation, but I have motivation to use a d3 approach. The code is pretty clear itself, but I will also include a brief synopsis of what I'm trying to do afterwards.
d3.selectAll('li').on('click', function(d) {
var array = d3.select(this)[0];
var tab = array[0];
var tabClass = tab.className.split(" ")[1];
var priorTab = d3.selectAll('.tab0');
var tabIndex = [].indexOf.call(tab.parentNode.children, tab);
priorTab.classed('tab0', false);
d3.select(tab).classed(tabClass, false);
d3.select(tab).classed('tab0', true);
d3.selectAll('li:not(.tab0)').each(function() {
var tempArray = d3.select(this)[0];
var tempTab = tempArray[0];
var tempTabClass = tempTab.className.split(" ")[1];
var tempIndex = [].indexOf.call(tempTab.parentNode.children, tempTab);
var tempIndexDifference = Math.abs(tabIndex-tempIndex);
d3.select(tempTab).classed(('tab'+tempIndexDifference), true);
});
});
.tab0 {
color:#77b4c9;
box-shadow: none;
transition: all .2s linear;
}
.tab0 span:first-of-type {
background-color: #fff;
box-shadow: none;
font-size: 50px;
margin-top: 15px;
display:block;
}
.tab1 {
background-color: #cbdeea;
color: #fff;
}
.tab2 {
background-color: #a6cdd9;
color: #fff;
}
.tab3 {
background-color: #77b4c9;
color: #fff;
}
.tab4 {
background-color: #519ab6;
color: #fff;
}
.contentTitleSize {
font-size: 50px;
}
.contentTitle {
color: #000;
height: 73px;
margin-top: 27px;
font-family: Play;
}
.contentTitle, .contentArea {
display:inline-block;
}
.contentArea {
height:320px;
width:312px;
margin-left: 25px;
overflow: hidden;
}
.subheading {
font-size: 18px;
height: 20px;
font-family: Play;
color: #77b4c9;
margin-top: 14px;
margin-bottom: 24px;
}
.outerContainer {
width:566px;
display:inline-block;
vertical-align: top;
margin-right: 27px;
}
section {
display:block;
}
*, :after, :before {
-webkit-box-sizing: inherit;
box-sizing: inherit;
}
*, :after, :before {
-webkit-box-sizing: inherit;
box-sizing: inherit;
}
::selection {
background: #b3d4fc;
text-shadow: none;
}
.tabPanel {
display:inline-block;
vertical-align: top;
width:160px;
margin:0;
padding:0;
}
ul {
list-style-type: disc;
-webkit-margin-before: 1em;
-webkit-margin-after: 1em;
-webkit-margin-start: 0px;
-webkit-margin-end: 0px;
-webkit-padding-start: 40px;
}
li {
display:list-item;
}
.listTabs {
display:block;
list-style: none;
font-size: 22px;
font-family: Play;
text-align: center;
padding-top: 12px;
padding-bottom: 13px;
cursor: pointer;
-webkit-box-shadow: inset 0 1px 2.5px 0 rgba(0,0,0,.11);
box-shadow: inset 0 1px 2.5px 0 rgba(0,0,0,.11);
}
.container {
height:320px;
width: 100%;
margin-bottom:24px;
border-radius: 2px;
background-color: #fff;
font-family: Roboto-Regular,serif;
line-height: 1;
box-shadow: 0 2px 5px 0 rgba(0,0,0,.1)
}
.bottomButton {
height: 61px;
background-color: #327ca3;
border-radius: 3px;
font-size: 20px;
font-family: Play;
letter-spacing: .4px;
color: #fff;
text-align: center;
line-height: 61px;
cursor: pointer;
}
<script src="https://d3js.org/d3.v3.min.js">
<div class="outerContainer">
<section class="container">
<ul class="tabPanel">
<li class="listTabs tab0" role="button">
<span>02</span>
<span>OCT</span>
</li>
<li class="listTabs tab1" role="button">
<span>01</span>
<span>OCT</span>
</li>
<li class="listTabs tab2" role="button">
<span>30</span>
<span>SEP</span>
</li>
<li class="listTabs tab3" role="button">
<span>29</span>
<span>SEP</span>
</li>
<li class="listTabs tab4" role="button">
<span>28</span>
<span>SEP</span>
</li>
</ul>
<div class="contentArea">
<a class="contentTitle contentTitleSize">Content Area</a>
<div class="subheading">
<span>
<strong>First</strong>
"Second and Third"::after
</span>
<span>more info</span>
</div>
<div class="details">
<p>lots of details</p>
</div>
</section>
<div>
<div class="bottomButton">
Click Me</div>
</div>
</div>
The user clicks a tab which then gets assigned a class to show that it is the active tab (.tab0
in my code)
I have 4 other classes ranging from .tab1
all the way to .tab4
. These classes have a different background-color
. The naming scheme is based on how far the tabs are from the active tab. .tab1
being adjacent (top or bottom) .tab4
being far away.
I then select all other tabs and use .each()
to apply a separate background-color
for the tab based on its relational position to the active tab. This is achieved by giving it a new .tabx
class. So for example, if you clicked on the third tab in the middle (which has a [].indexOf.call(tab.parentNode.children, tab)
equal to 2, then the tab above it and below it would have the class tab1
-- because the absolute value of 0-1 is 1.
Despite my careful attempts to revise it, I can't get it working. None of the tabs are updated with new colors and I can't understand why. Dev tools shows that the index is being correctly calculated each time.
Question: How do I get this dynamic color update to work? In other words, whichever tab the user clicks on will be white, and all the other tabs will update the background-color
based on their relational position to the active tab.
Clarification
To clarify, it's not the same as swapping the styles from the old active tab to the new, what I mean is updating all background-color
s of the tabs to a new value based on how far away they are from the new active tab. For example, the tabs directly on the top and bottom of the new active tab would be the closest, and thus they should get the class: .tab1
. The tabs that are two tabs away would get .tab2
and so on. Note the initial state has the first tab being the active tab, and as such there will only be 1 tab with class .tab1
because there can't be any tabs above it.
Upvotes: 1
Views: 104
Reputation: 32327
Restructure your click logic like this.
//select all lis
d3.selectAll('li').on('click', function(d, i) {
//select the dom with .tab0
var old = d3.select(".tab0");
//swap the class with the selected li
var oldClass = d3.select(old).node().node().className;
var newClass = d3.select(this).node().className;
d3.select(this).node().className = oldClass;
d3.select(old).node().node().className = newClass;
//make all tabs in ascending order excluding the li with tab0.
var index = 1;
d3.selectAll(".listTabs").each(function(d, i){
if (!d3.select(this).classed("tab0")){
d3.select(this).node().className = "listTabs";
d3.select(this).classed("tab" + index, true);
index++;
}
})
});
working code below:
//select all lis
d3.selectAll('li').on('click', function(d, i) {
//select the dom with .tab0
var old = d3.select(".tab0");
//swap the class with the selected li
var oldClass = d3.select(old).node().node().className;
var newClass = d3.select(this).node().className;
d3.select(this).node().className = oldClass;
d3.select(old).node().node().className = newClass;
//make all tabs in ascending order excluding the li with tab0.
var index = 1;
d3.selectAll(".listTabs").each(function(d, i){
if (!d3.select(this).classed("tab0")){
d3.select(this).node().className = "listTabs";
d3.select(this).classed("tab" + index, true);
index++;
}
})
});
.tab0 {
color:#77b4c9;
box-shadow: none;
transition: all .2s linear;
}
.tab0 span:first-of-type {
background-color: #fff;
box-shadow: none;
font-size: 50px;
margin-top: 15px;
display:block;
}
.tab1 {
background-color: #cbdeea;
color: #fff;
}
.tab2 {
background-color: #a6cdd9;
color: #fff;
}
.tab3 {
background-color: #77b4c9;
color: #fff;
}
.tab4 {
background-color: #519ab6;
color: #fff;
}
.contentTitleSize {
font-size: 50px;
}
.contentTitle {
color: #000;
height: 73px;
margin-top: 27px;
font-family: Play;
}
.contentTitle, .contentArea {
display:inline-block;
}
.contentArea {
height:320px;
width:312px;
margin-left: 25px;
overflow: hidden;
}
.subheading {
font-size: 18px;
height: 20px;
font-family: Play;
color: #77b4c9;
margin-top: 14px;
margin-bottom: 24px;
}
.outerContainer {
width:566px;
display:inline-block;
vertical-align: top;
margin-right: 27px;
}
section {
display:block;
}
*, :after, :before {
-webkit-box-sizing: inherit;
box-sizing: inherit;
}
*, :after, :before {
-webkit-box-sizing: inherit;
box-sizing: inherit;
}
::selection {
background: #b3d4fc;
text-shadow: none;
}
.tabPanel {
display:inline-block;
vertical-align: top;
width:160px;
margin:0;
padding:0;
}
ul {
list-style-type: disc;
-webkit-margin-before: 1em;
-webkit-margin-after: 1em;
-webkit-margin-start: 0px;
-webkit-margin-end: 0px;
-webkit-padding-start: 40px;
}
li {
display:list-item;
}
.listTabs {
display:block;
list-style: none;
font-size: 22px;
font-family: Play;
text-align: center;
padding-top: 12px;
padding-bottom: 13px;
cursor: pointer;
-webkit-box-shadow: inset 0 1px 2.5px 0 rgba(0,0,0,.11);
box-shadow: inset 0 1px 2.5px 0 rgba(0,0,0,.11);
}
.container {
height:320px;
width: 100%;
margin-bottom:24px;
border-radius: 2px;
background-color: #fff;
font-family: Roboto-Regular,serif;
line-height: 1;
box-shadow: 0 2px 5px 0 rgba(0,0,0,.1)
}
.bottomButton {
height: 61px;
background-color: #327ca3;
border-radius: 3px;
font-size: 20px;
font-family: Play;
letter-spacing: .4px;
color: #fff;
text-align: center;
line-height: 61px;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<body>
<div class="outerContainer">
<section class="container">
<ul class="tabPanel">
<li class="listTabs tab0" role="button">
<span>02</span>
<span>OCT</span>
</li>
<li class="listTabs tab1" role="button">
<span>01</span>
<span>OCT</span>
</li>
<li class="listTabs tab2" role="button">
<span>30</span>
<span>SEP</span>
</li>
<li class="listTabs tab3" role="button">
<span>29</span>
<span>SEP</span>
</li>
<li class="listTabs tab4" role="button">
<span>28</span>
<span>SEP</span>
</li>
</ul>
<div class="contentArea">
<a class="contentTitle contentTitleSize">Content Area</a>
<div class="subheading">
<span>
<strong>First</strong>
"Second and Third"::after
</span>
<span>more info</span>
</div>
<div class="details">
<p>lots of details</p>
</div>
</div>
</section>
<div class="bottomButton">
Click Me</div>
</div>
</body>
Upvotes: 1