d3.slider = function module() { "use strict"; var div, min = 0, max = 52, svg, svgGroup, value, classPrefix, axis, height = 10, rect, rectHeight = 5, tickSize = 9, margin = { top: 6, right: 10, bottom: 4, left: 10 }, ticks = 0, tickValues, scale, tickFormat, dragger, width, range = false, callbackFn, stepValues, focus; function slider(selection) { selection.each(function() { div = d3.select(this).classed('d3slider', true); width = parseInt(div.style("width"), 11) - (margin.left + margin.right); value = value || min; scale = d3.scale.linear().domain([min, max]).range([0, width]).clamp(true); svg = div.append("svg").attr("class", "d3slider-axis").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom).append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); svg.append("rect").attr("class", "d3slider-rect-range").attr("width", width).attr("height", rectHeight); if (range) { svg.append("rect").attr("class", "d3slider-rect-value").attr("width", scale(value)).attr("height", rectHeight); } var axis = d3.svg.axis().scale(scale).orient("bottom"); if (ticks != 0) { axis.ticks(ticks); axis.tickSize(tickSize); } else if (tickValues) { axis.tickValues(tickValues); axis.tickSize(tickSize); } else { axis.ticks(0); axis.tickSize(0); } if (tickFormat) { axis.tickFormat(tickFormat); } svg.append("g").attr("transform", "translate(0," + rectHeight + ")").call(axis) var values = [value]; dragger = svg.selectAll(".dragger").data(values).enter().append("g").attr("class", "dragger").attr("transform", function(d) { return "translate(" + scale(d) + ")"; }) var displayValue = null; if (tickFormat) { displayValue = tickFormat(value); } else { displayValue = d3.format(",.0f")(value); } dragger.append("text").attr("x", 0).attr("y", -15).attr("text-anchor", "middle").attr("class", "draggertext").text(displayValue); dragger.append("circle").attr("class", "dragger-outer").attr("r", 7).attr("transform", function(d) { return "translate(0,2)"; }); dragger.append("circle").attr("class", "dragger-inner").attr("r", 5).attr("transform", function(d) { return "translate(0,2)"; }); var dragBehaviour = d3.behavior.drag(); dragBehaviour.on("drag", slider.drag); dragger.call(dragBehaviour); svg.on("click", slider.click); }); } slider.draggerTranslateFn = function() { return function(d) { return "translate(" + scale(d) + ")"; } } slider.click = function() { var pos = d3.event.offsetX || d3.event.layerX; slider.move(pos); } slider.drag = function() { var pos = d3.event.x; slider.move(pos + margin.left); } slider.move = function(pos) { var l, u; var newValue = scale.invert(pos - margin.left); if (stepValues != undefined) { l = stepValues.reduce(function(p, c, i, arr) { if (c < newValue) { return c; } else { return p; } }); if (stepValues.indexOf(l) < stepValues.length - 1) { u = stepValues[stepValues.indexOf(l) + 1]; } else { u = l; } var oldValue = value; value = ((newValue - l) <= (u - newValue)) ? l : u; } else { var oldValue = value; value = newValue; } var values = [value]; svg.selectAll(".dragger").data(values).attr("transform", function(d) { return "translate(" + scale(d) + ")"; }); var displayValue = null; if (tickFormat) { displayValue = tickFormat(value); } else { displayValue = d3.format(",.0f")(value); } svg.selectAll(".dragger").select("text").text(displayValue); if (range) { svg.selectAll(".d3slider-rect-value").attr("width", scale(value)); } if (callbackFn) { callbackFn(slider); } } slider.min = function(_) { if (!arguments.length) return min; min = _; return slider; }; slider.max = function(_) { if (!arguments.length) return max; max = _; return slider; }; slider.classPrefix = function(_) { if (!arguments.length) return classPrefix; classPrefix = _; return slider; } slider.tickValues = function(_) { if (!arguments.length) return tickValues; tickValues = _; return slider; } slider.ticks = function(_) { if (!arguments.length) return ticks; ticks = _; return slider; } slider.stepValues = function(_) { if (!arguments.length) return stepValues; stepValues = _; return slider; } slider.tickFormat = function(_) { if (!arguments.length) return tickFormat; tickFormat = _; return slider; } slider.value = function(_) { if (!arguments.length) return value; value = _; return slider; } slider.showRange = function(_) { if (!arguments.length) return range; range = _; return slider; } slider.callback = function(_) { if (!arguments.length) return callbackFn; callbackFn = _; return slider; } slider.setValue = function(newValue) { var pos = scale(newValue) + margin.left; slider.move(pos); } slider.mousemove = function() { var pos = d3.mouse(this)[0]; var val = slider.getNearest(scale.invert(pos), stepValues); focus.attr("transform", "translate(" + scale(val) + ",0)"); focus.selectAll("text").text(val); } slider.getNearest = function(val, arr) { var l = arr.reduce(function(p, c, i, a) { if (c < val) { return c; } else { return p; } }); var u = arr[arr.indexOf(l) + 1]; var nearest = ((value - l) <= (u - value)) ? l : u; return nearest; } slider.destroy = function() { div.selectAll('svg').remove(); return slider; } return slider; };