Gerardo Furtado has pointed out in a comment that the question does not really involve traversing the DOM upwards, but rather focuses on iterating through td
elements. This task can be easily accomplished by using d3.selectAll("td")
, which will provide a flat selection of all td
elements present on the page. Depending on the layout, you may need to refine the selection further to target a specific table, such as "table.myTable td"
or "#tableId td"
.
Once you have this selection, you can add a class, like range
, using selection.classed(names[, value])
. The second argument value
can be a function, allowing for dynamic assignment of classes based on certain criteria.
If the value is a function, the function evaluates each selected element one by one, receiving the current data (d), index (i), and group (nodes) along with the current DOM element via this. The return value of the function decides whether to apply or remove classes on each element.
The final step involves creating a filter function to determine if an element falls within a desired range and consequently assign the range
class accordingly.
The code snippet below demonstrates how to combine all these steps using a custom filter function named rangeFilter()
within .classed()
:
// The day parameter sets the stopping point
function rangeFilter(day) {
// This property is captured by the following function to track the
// range status. When true, the current element and subsequent elements are part
// of the range until encountering the button's td.
var inRange = false;
// Filter function returns true if the element belongs to the range.
return function(d) {
element = d3.select(this); // Current td element during iteration.
// Determine if the element is still in the range, or if the range hasn't started yet,
// check if we've reached the td.is-startrange.
inRange = (inRange && element.attr("day") != day)
|| element.classed("is-startrange");
// XOR operation to exclude the .is-startrange element.
return inRange != element.classed("is-startrange");
}
}
d3.selectAll("button")
.on("click", function() {
// Check all tds for range inclusion and set class based on filter function result
passing in the clicked button's value.
d3.selectAll("td")
.classed("range", rangeFilter(d3.select(this).text()));
});
.is-startrange {
background-color: limegreen;
}
.range {
background-color: red;
}
<script src="https://d3js.org/d3.v4.js"></script>
<h1>Hit the button</h1>
<table>
<thead>...</thead>
<tbody>
<tr>...</tr>
<tr>
<td day="4">...4...</td>
<td day="5">...5...</td>
<td day="6" class="is-startrange">...6...</td>
<td day="7">...7...</td>
<td day="8">...8...</td>
</tr>
<tr>
<td day="9">...9...</td>
<td day="10">...10...</td>
<td day="11">...11...</td>
<td day="12">
<button class="day" type="button">12</button>
</td>
<td day="13">...13...</td>
</tr>
</tbody>
</table>