I'm new to web development and have run into a wall with a d3 visualization I am making. I need a range slider that will loop through a two dimensional array (representing different time-points) to change the color of several SVG elements.
What I have so far seems perfectly functional, as far as I can tell. I cannot figure out how to add play/pause functionality to the HTML range slider to save my life, however. A previous post for almost this exact question received only the advice to use a d3 brush element as a slider. This makes sense, however it seems more complicated and I still cannot figure out how the play/pause function would be accomplished with a brush.
Please see the full code of my toy example embedded below, or in this fiddle, if you prefer. I'm guessing there is a way to do this with jQuery -- but there is a desire to reduce dependencies as much as possible, so I need a vanilla javascript or d3 based solution. Thank you!
var dataSet = [
[1, 2],
[2, 3],
[3, 4],
[4, 5],
[5, 4]
];
var colorScale = d3.scale.linear()
.domain([0, 2.5, 5])
.range(["red", "white", "blue"]);
//Draw the SVG element, then the circles
var svg = d3.select('#circles')
.append("svg")
.attr("width", 200)
.attr("height", 900)
.append('g')
.attr('id', 'foo');
svg.append('circle')
.attr({
"cx": 45,
'cy': 45,
'r': 15,
'id': 'circle1'
});
svg.append('circle')
.attr({
"cx": 90,
'cy': 45,
'r': 15,
'id': 'circle2'
});
//Initialize the color fill in each circle
d3.select('#circle1')
.style('fill', function(d) {
return colorScale(dataSet[0][0]);
})
.transition();
d3.select('#circle2')
.style('fill', function(d) {
return colorScale(dataSet[0][1]);
})
.transition();
//The function which updates the fill of the circles to match a new time point
function update(timePoint) {
d3.select('#circle1')
.transition().duration(500)
.style('fill', function(d) {
return colorScale(dataSet[timePoint][0]);
});
d3.select('#circle2')
.transition().duration(500)
.style('fill', function(d) {
return colorScale(dataSet[timePoint][1]);
});
};
//Run the update function when the slider is changed
d3.select('#rangeSlider').on('input', function() {
update(this.value);
});
html {
background-color: lightgray;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<body>
<div id="slider">
<input type='range' min='0' max='4' step='1' value='0' id='rangeSlider' />
<button type="button" id="start">start</button>
<button type="button" id="stop">stop</button>
</div>
<div id="circles">
</div>
</body>
Adjusted fiddle: https://jsfiddle.net/bfbun6cc/4/
var myTimer;
d3.select("#start").on("click", function() {
clearInterval (myTimer);
myTimer = setInterval (function() {
var b= d3.select("#rangeSlider");
var t = (+b.property("value") + 1) % (+b.property("max") + 1);
if (t == 0) { t = +b.property("min"); }
b.property("value", t);
update (t);
}, 1000);
});
d3.select("#stop").on("click", function() {
clearInterval (myTimer);
});
You can use d3's property operator to access the min, max, value settings of rangeslider
Note that setting the value on the rangeslider like this doesn't fire the input event. There's ways of doing that, but just calling the update function with the current value works as well.