/** * Bandline renderer */ function defined(x) { return !isNaN(x) && isFinite(x) && x !== null } function rectanglePath(xr, yr) { return d3.svg.line()([[xr[0], yr[0]], [xr[1], yr[0]], [xr[1], yr[1]], [xr[0], yr[1]]]) + 'Z' } function bandLinePath(valueAccessor, xScale, yScaler, d) { var drawer = d3.svg.line().defined(compose(defined, property(1))) return drawer(valueAccessor(d).map(function(s, i) {return [xScale(i), yScaler(d)(s)]})) } function bandData(bands, yScaler, d) { var yScale = yScaler(d) return bands.map(function(band, i) { return {key: i, value: band, yScale: yScale} }) } function renderBands(root, bands, yScaler, xRanger, yRanger) { bind(bind(root, 'bands'), 'band', 'path', bandData.bind(0, bands, yScaler)) .transition() .attr('class', function(d, i) {return 'band s' + i}) .attr('d', function(d) {return rectanglePath(xRanger(d), yRanger(d))}) } function pointData(valueAccessor, d) { return valueAccessor(d) .map(function(value, i) {return {key: i, value: value, o: d}}) .filter(compose(defined, value)) } function renderPoints(root, valueAccessor, pointStyleAccessor, rScale, xSpec, ySpec) { bind(root, 'valuePoints', 'g', pointData.bind(0, valueAccessor)) .entered .attr('transform', translate(xSpec, ySpec)) root['valuePoints'] .transition() .attr('transform', translate(xSpec, ySpec)) bind(root['valuePoints'], 'point', 'circle') .attr('class', function(d) {return 'point ' + pointStyleAccessor(d.value)}) .attr('r', function(d) {return rScale(pointStyleAccessor(d.value))}) root['valuePoints'].exit().remove() } function valuesExtent(valueAccessor, d) { return d3.extent(valueAccessor(d).filter(defined)) } function sparkStripBoxPath(valueAccessor, xScale, yRange, d) { var midY = d3.mean(yRange) var halfHeight = (yRange[1] - yRange[0]) / 2 return rectanglePath( valuesExtent(valueAccessor, d).map(xScale), [midY - halfHeight / 2, midY + halfHeight / 2] ) } function renderExtent(root, valueAccessor, xScale, yRange) { bind(root, 'valueBox', 'path') .transition() .attr('d', sparkStripBoxPath.bind(0, valueAccessor, xScale, yRange)) } function renderValueLine(root, valueAccessor, xScale, yScaler) { bind(root, 'valueLine', 'path') .transition() .attr('d', bandLinePath.bind(0, valueAccessor, xScale, yScaler)) } function bandLine() { function renderBandLine(root) { var bandLine = bind(root, 'bandLine') renderBands(bandLine, _bands, _yScalerOfBandLine, constant(_xScaleOfBandLine.range()), function(d) {return d.value.map(d.yScale)}) renderValueLine(bandLine, _valueAccessor, _xScaleOfBandLine, _yScalerOfBandLine) renderPoints(bandLine, _valueAccessor, _pointStyleAccessor, _rScaleOfBandLine, compose(_xScaleOfBandLine, key), function(d) {return _yScalerOfBandLine(d.o)(d.value)}) } function renderSparkStrip(root) { var sparkStrip = bind(root, 'sparkStrip') renderBands(sparkStrip, _bands, _yScalerOfSparkStrip, function(d) { return d.value.map(_xScaleOfSparkStrip) }, constant(_yRange)) renderExtent(sparkStrip, _valueAccessor, _xScaleOfSparkStrip, _yRange) renderPoints(sparkStrip, _valueAccessor, _pointStyleAccessor, _rScaleOfSparkStrip, compose(_xScaleOfSparkStrip, value), _yScalerOfSparkStrip()) } function yScalerOfBandLineCalc() { return function(d) { return d3.scale.linear() .domain(valuesExtent(_valueAccessor, d)) .range(_yRange) .clamp(true) } } var _bands = [[0, 0.25], [0.25, 0.5], [0.5, 0.75], [0.75, 1]] var bands = function(spec) { if(spec !== void(0)) { _bands = spec return functionalObject } else { return bands } } var _valueAccessor = value var valueAccessor = function(spec) { if(spec !== void(0)) { _valueAccessor = spec _yScalerOfBandLine = yScalerOfBandLineCalc() return functionalObject } else { return _valueAccessor } } var _xScaleOfBandLine = d3.scale.linear() var xScaleOfBandLine = function(spec) { if(spec !== void(0)) { _xScaleOfBandLine = spec return functionalObject } else { return _xScaleOfBandLine } } var _xScaleOfSparkStrip = d3.scale.linear() var xScaleOfSparkStrip = function(spec) { if(spec !== void(0)) { _xScaleOfSparkStrip = spec return functionalObject } else { return _xScaleOfSparkStrip } } var _rScaleOfBandLine = constant(2) var rScaleOfBandLine = function(spec) { if(spec !== void(0)) { _rScaleOfBandLine = spec return functionalObject } else { return _rScaleOfBandLine } } var _rScaleOfSparkStrip = constant(2) var rScaleOfSparkStrip = function(spec) { if(spec !== void(0)) { _rScaleOfSparkStrip = spec return functionalObject } else { return _rScaleOfSparkStrip } } var _yRange = [0, 1] var _yScalerOfSparkStrip var _yScalerOfBandLine var yRange = function(spec) { if(spec !== void(0)) { _yRange = spec _yScalerOfSparkStrip = constant(d3.mean(_yRange)) _yScalerOfBandLine = yScalerOfBandLineCalc() return functionalObject } else { return _yRange } } var _pointStyleAccessor = constant('normal') var pointStyleAccessor = function(spec) { if(spec !== void(0)) { _pointStyleAccessor = spec return functionalObject } else { return _pointStyleAccessor } } var functionalObject = { // For reference: http://bost.ocks.org/mike/chart/ renderBandLine: renderBandLine, renderSparkStrip: renderSparkStrip, bands: bands, valueAccessor: valueAccessor, xScaleOfBandLine: xScaleOfBandLine, xScaleOfSparkStrip: xScaleOfSparkStrip, rScaleOfBandLine: rScaleOfBandLine, rScaleOfSparkStrip: rScaleOfSparkStrip, yRange: yRange, pointStyleAccessor: pointStyleAccessor } return functionalObject }