in mc/Scripts/nv.d3.js [11162:12027]
color: color(d, i)
});
});
}
}
needsUpdate = true;
var groups = wrap.select('.nv-groups').selectAll('.nv-group')
.data(function(d) { return d }, function(d) { return d.key });
groups.enter().append('g')
.style('stroke-opacity', 1e-6)
.style('fill-opacity', 1e-6);
groups.exit()
.remove();
groups
.attr('class', function(d,i) { return 'nv-group nv-series-' + i })
.classed('hover', function(d) { return d.hover });
groups.watchTransition(renderWatch, 'scatter: groups')
.style('fill', function(d,i) { return color(d, i) })
.style('stroke', function(d,i) { return color(d, i) })
.style('stroke-opacity', 1)
.style('fill-opacity', .5);
// create the points, maintaining their IDs from the original data set
var points = groups.selectAll('path.nv-point')
.data(function(d) {
return d.values.map(
function (point, pointIndex) {
return [point, pointIndex]
}).filter(
function(pointArray, pointIndex) {
return pointActive(pointArray[0], pointIndex)
})
});
points.enter().append('path')
.style('fill', function (d) { return d.color })
.style('stroke', function (d) { return d.color })
.attr('transform', function(d) {
return 'translate(' + x0(getX(d[0],d[1])) + ',' + y0(getY(d[0],d[1])) + ')'
})
.attr('d',
nv.utils.symbol()
.type(function(d) { return getShape(d[0]); })
.size(function(d) { return z(getSize(d[0],d[1])) })
);
points.exit().remove();
groups.exit().selectAll('path.nv-point')
.watchTransition(renderWatch, 'scatter exit')
.attr('transform', function(d) {
return 'translate(' + x(getX(d[0],d[1])) + ',' + y(getY(d[0],d[1])) + ')'
})
.remove();
points.each(function(d) {
d3.select(this)
.classed('nv-point', true)
.classed('nv-point-' + d[1], true)
.classed('nv-noninteractive', !interactive)
.classed('hover',false)
;
});
points
.watchTransition(renderWatch, 'scatter points')
.attr('transform', function(d) {
//nv.log(d, getX(d[0],d[1]), x(getX(d[0],d[1])));
return 'translate(' + x(getX(d[0],d[1])) + ',' + y(getY(d[0],d[1])) + ')'
})
.attr('d',
nv.utils.symbol()
.type(function(d) { return getShape(d[0]); })
.size(function(d) { return z(getSize(d[0],d[1])) })
);
// Delay updating the invisible interactive layer for smoother animation
clearTimeout(timeoutID); // stop repeat calls to updateInteractiveLayer
timeoutID = setTimeout(updateInteractiveLayer, 300);
//updateInteractiveLayer();
//store old scales for use in transitions on update
x0 = x.copy();
y0 = y.copy();
z0 = z.copy();
});
renderWatch.renderEnd('scatter immediate');
return chart;
}
//============================================================
// Expose Public Variables
//------------------------------------------------------------
chart.dispatch = dispatch;
chart.options = nv.utils.optionsFunc.bind(chart);
// utility function calls provided by this chart
chart._calls = new function() {
this.clearHighlights = function () {
nv.dom.write(function() {
container.selectAll(".nv-point.hover").classed("hover", false);
});
return null;
};
this.highlightPoint = function (seriesIndex, pointIndex, isHoverOver) {
nv.dom.write(function() {
container.select(" .nv-series-" + seriesIndex + " .nv-point-" + pointIndex)
.classed("hover", isHoverOver);
});
};
};
// trigger calls from events too
dispatch.on('elementMouseover.point', function(d) {
if (interactive) chart._calls.highlightPoint(d.seriesIndex,d.pointIndex,true);
});
dispatch.on('elementMouseout.point', function(d) {
if (interactive) chart._calls.highlightPoint(d.seriesIndex,d.pointIndex,false);
});
chart._options = Object.create({}, {
// simple options, just get/set the necessary values
width: {get: function(){return width;}, set: function(_){width=_;}},
height: {get: function(){return height;}, set: function(_){height=_;}},
xScale: {get: function(){return x;}, set: function(_){x=_;}},
yScale: {get: function(){return y;}, set: function(_){y=_;}},
pointScale: {get: function(){return z;}, set: function(_){z=_;}},
xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
pointDomain: {get: function(){return sizeDomain;}, set: function(_){sizeDomain=_;}},
xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}},
yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}},
pointRange: {get: function(){return sizeRange;}, set: function(_){sizeRange=_;}},
forceX: {get: function(){return forceX;}, set: function(_){forceX=_;}},
forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}},
forcePoint: {get: function(){return forceSize;}, set: function(_){forceSize=_;}},
interactive: {get: function(){return interactive;}, set: function(_){interactive=_;}},
pointActive: {get: function(){return pointActive;}, set: function(_){pointActive=_;}},
padDataOuter: {get: function(){return padDataOuter;}, set: function(_){padDataOuter=_;}},
padData: {get: function(){return padData;}, set: function(_){padData=_;}},
clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}},
clipVoronoi: {get: function(){return clipVoronoi;}, set: function(_){clipVoronoi=_;}},
clipRadius: {get: function(){return clipRadius;}, set: function(_){clipRadius=_;}},
showVoronoi: {get: function(){return showVoronoi;}, set: function(_){showVoronoi=_;}},
id: {get: function(){return id;}, set: function(_){id=_;}},
// simple functor options
x: {get: function(){return getX;}, set: function(_){getX = d3.functor(_);}},
y: {get: function(){return getY;}, set: function(_){getY = d3.functor(_);}},
pointSize: {get: function(){return getSize;}, set: function(_){getSize = d3.functor(_);}},
pointShape: {get: function(){return getShape;}, set: function(_){getShape = d3.functor(_);}},
// options that require extra logic in the setter
margin: {get: function(){return margin;}, set: function(_){
margin.top = _.top !== undefined ? _.top : margin.top;
margin.right = _.right !== undefined ? _.right : margin.right;
margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
margin.left = _.left !== undefined ? _.left : margin.left;
}},
duration: {get: function(){return duration;}, set: function(_){
duration = _;
renderWatch.reset(duration);
}},
color: {get: function(){return color;}, set: function(_){
color = nv.utils.getColor(_);
}},
useVoronoi: {get: function(){return useVoronoi;}, set: function(_){
useVoronoi = _;
if (useVoronoi === false) {
clipVoronoi = false;
}
}}
});
nv.utils.initOptions(chart);
return chart;
};
nv.models.scatterChart = function() {
"use strict";
//============================================================
// Public Variables with Default Settings
//------------------------------------------------------------
var scatter = nv.models.scatter()
, xAxis = nv.models.axis()
, yAxis = nv.models.axis()
, legend = nv.models.legend()
, distX = nv.models.distribution()
, distY = nv.models.distribution()
, tooltip = nv.models.tooltip()
;
var margin = {top: 30, right: 20, bottom: 50, left: 75}
, width = null
, height = null
, container = null
, color = nv.utils.defaultColor()
, x = scatter.xScale()
, y = scatter.yScale()
, showDistX = false
, showDistY = false
, showLegend = true
, showXAxis = true
, showYAxis = true
, rightAlignYAxis = false
, state = nv.utils.state()
, defaultState = null
, dispatch = d3.dispatch('stateChange', 'changeState', 'renderEnd')
, noData = null
, duration = 250
;
scatter.xScale(x).yScale(y);
xAxis.orient('bottom').tickPadding(10);
yAxis
.orient((rightAlignYAxis) ? 'right' : 'left')
.tickPadding(10)
;
distX.axis('x');
distY.axis('y');
tooltip
.headerFormatter(function(d, i) {
return xAxis.tickFormat()(d, i);
})
.valueFormatter(function(d, i) {
return yAxis.tickFormat()(d, i);
});
//============================================================
// Private Variables
//------------------------------------------------------------
var x0, y0
, renderWatch = nv.utils.renderWatch(dispatch, duration);
var stateGetter = function(data) {
return function(){
return {
active: data.map(function(d) { return !d.disabled })
};
}
};
var stateSetter = function(data) {
return function(state) {
if (state.active !== undefined)
data.forEach(function(series,i) {
series.disabled = !state.active[i];
});
}
};
function chart(selection) {
renderWatch.reset();
renderWatch.models(scatter);
if (showXAxis) renderWatch.models(xAxis);
if (showYAxis) renderWatch.models(yAxis);
if (showDistX) renderWatch.models(distX);
if (showDistY) renderWatch.models(distY);
selection.each(function(data) {
var that = this;
container = d3.select(this);
nv.utils.initSVG(container);
var availableWidth = nv.utils.availableWidth(width, container, margin),
availableHeight = nv.utils.availableHeight(height, container, margin);
chart.update = function() {
if (duration === 0)
container.call(chart);
else
container.transition().duration(duration).call(chart);
};
chart.container = this;
state
.setter(stateSetter(data), chart.update)
.getter(stateGetter(data))
.update();
// DEPRECATED set state.disableddisabled
state.disabled = data.map(function(d) { return !!d.disabled });
if (!defaultState) {
var key;
defaultState = {};
for (key in state) {
if (state[key] instanceof Array)
defaultState[key] = state[key].slice(0);
else
defaultState[key] = state[key];
}
}
// Display noData message if there's nothing to show.
if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) {
nv.utils.noData(chart, container);
renderWatch.renderEnd('scatter immediate');
return chart;
} else {
container.selectAll('.nv-noData').remove();
}
// Setup Scales
x = scatter.xScale();
y = scatter.yScale();
// Setup containers and skeleton of chart
var wrap = container.selectAll('g.nv-wrap.nv-scatterChart').data([data]);
var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-scatterChart nv-chart-' + scatter.id());
var gEnter = wrapEnter.append('g');
var g = wrap.select('g');
// background for pointer events
gEnter.append('rect').attr('class', 'nvd3 nv-background').style("pointer-events","none");
gEnter.append('g').attr('class', 'nv-x nv-axis');
gEnter.append('g').attr('class', 'nv-y nv-axis');
gEnter.append('g').attr('class', 'nv-scatterWrap');
gEnter.append('g').attr('class', 'nv-regressionLinesWrap');
gEnter.append('g').attr('class', 'nv-distWrap');
gEnter.append('g').attr('class', 'nv-legendWrap');
if (rightAlignYAxis) {
g.select(".nv-y.nv-axis")
.attr("transform", "translate(" + availableWidth + ",0)");
}
// Legend
if (showLegend) {
var legendWidth = availableWidth;
legend.width(legendWidth);
wrap.select('.nv-legendWrap')
.datum(data)
.call(legend);
if ( margin.top != legend.height()) {
margin.top = legend.height();
availableHeight = nv.utils.availableHeight(height, container, margin);
}
wrap.select('.nv-legendWrap')
.attr('transform', 'translate(0' + ',' + (-margin.top) +')');
}
wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
// Main Chart Component(s)
scatter
.width(availableWidth)
.height(availableHeight)
.color(data.map(function(d,i) {
d.color = d.color || color(d, i);
return d.color;
}).filter(function(d,i) { return !data[i].disabled }));
wrap.select('.nv-scatterWrap')
.datum(data.filter(function(d) { return !d.disabled }))
.call(scatter);
wrap.select('.nv-regressionLinesWrap')
.attr('clip-path', 'url(#nv-edge-clip-' + scatter.id() + ')');
var regWrap = wrap.select('.nv-regressionLinesWrap').selectAll('.nv-regLines')
.data(function (d) {
return d;
});
regWrap.enter().append('g').attr('class', 'nv-regLines');
var regLine = regWrap.selectAll('.nv-regLine')
.data(function (d) {
return [d]
});
regLine.enter()
.append('line').attr('class', 'nv-regLine')
.style('stroke-opacity', 0);
// don't add lines unless we have slope and intercept to use
regLine.filter(function(d) {
return d.intercept && d.slope;
})
.watchTransition(renderWatch, 'scatterPlusLineChart: regline')
.attr('x1', x.range()[0])
.attr('x2', x.range()[1])
.attr('y1', function (d, i) {
return y(x.domain()[0] * d.slope + d.intercept)
})
.attr('y2', function (d, i) {
return y(x.domain()[1] * d.slope + d.intercept)
})
.style('stroke', function (d, i, j) {
return color(d, j)
})
.style('stroke-opacity', function (d, i) {
return (d.disabled || typeof d.slope === 'undefined' || typeof d.intercept === 'undefined') ? 0 : 1
});
// Setup Axes
if (showXAxis) {
xAxis
.scale(x)
._ticks( nv.utils.calcTicksX(availableWidth/100, data) )
.tickSize( -availableHeight , 0);
g.select('.nv-x.nv-axis')
.attr('transform', 'translate(0,' + y.range()[0] + ')')
.call(xAxis);
}
if (showYAxis) {
yAxis
.scale(y)
._ticks( nv.utils.calcTicksY(availableHeight/36, data) )
.tickSize( -availableWidth, 0);
g.select('.nv-y.nv-axis')
.call(yAxis);
}
if (showDistX) {
distX
.getData(scatter.x())
.scale(x)
.width(availableWidth)
.color(data.map(function(d,i) {
return d.color || color(d, i);
}).filter(function(d,i) { return !data[i].disabled }));
gEnter.select('.nv-distWrap').append('g')
.attr('class', 'nv-distributionX');
g.select('.nv-distributionX')
.attr('transform', 'translate(0,' + y.range()[0] + ')')
.datum(data.filter(function(d) { return !d.disabled }))
.call(distX);
}
if (showDistY) {
distY
.getData(scatter.y())
.scale(y)
.width(availableHeight)
.color(data.map(function(d,i) {
return d.color || color(d, i);
}).filter(function(d,i) { return !data[i].disabled }));
gEnter.select('.nv-distWrap').append('g')
.attr('class', 'nv-distributionY');
g.select('.nv-distributionY')
.attr('transform', 'translate(' + (rightAlignYAxis ? availableWidth : -distY.size() ) + ',0)')
.datum(data.filter(function(d) { return !d.disabled }))
.call(distY);
}
//============================================================
// Event Handling/Dispatching (in chart's scope)
//------------------------------------------------------------
legend.dispatch.on('stateChange', function(newState) {
for (var key in newState)
state[key] = newState[key];
dispatch.stateChange(state);
chart.update();
});
// Update chart from a state object passed to event handler
dispatch.on('changeState', function(e) {
if (typeof e.disabled !== 'undefined') {
data.forEach(function(series,i) {
series.disabled = e.disabled[i];
});
state.disabled = e.disabled;
}
chart.update();
});
// mouseover needs availableHeight so we just keep scatter mouse events inside the chart block
scatter.dispatch.on('elementMouseout.tooltip', function(evt) {
tooltip.hidden(true);
container.select('.nv-chart-' + scatter.id() + ' .nv-series-' + evt.seriesIndex + ' .nv-distx-' + evt.pointIndex)
.attr('y1', 0);
container.select('.nv-chart-' + scatter.id() + ' .nv-series-' + evt.seriesIndex + ' .nv-disty-' + evt.pointIndex)
.attr('x2', distY.size());
});
scatter.dispatch.on('elementMouseover.tooltip', function(evt) {
container.select('.nv-series-' + evt.seriesIndex + ' .nv-distx-' + evt.pointIndex)
.attr('y1', evt.pos.top - availableHeight - margin.top);
container.select('.nv-series-' + evt.seriesIndex + ' .nv-disty-' + evt.pointIndex)
.attr('x2', evt.pos.left + distX.size() - margin.left);
tooltip.position(evt.pos).data(evt).hidden(false);
});
//store old scales for use in transitions on update
x0 = x.copy();
y0 = y.copy();
});
renderWatch.renderEnd('scatter with line immediate');
return chart;
}
//============================================================
// Expose Public Variables
//------------------------------------------------------------
// expose chart's sub-components
chart.dispatch = dispatch;
chart.scatter = scatter;
chart.legend = legend;
chart.xAxis = xAxis;
chart.yAxis = yAxis;
chart.distX = distX;
chart.distY = distY;
chart.tooltip = tooltip;
chart.options = nv.utils.optionsFunc.bind(chart);
chart._options = Object.create({}, {
// simple options, just get/set the necessary values
width: {get: function(){return width;}, set: function(_){width=_;}},
height: {get: function(){return height;}, set: function(_){height=_;}},
container: {get: function(){return container;}, set: function(_){container=_;}},
showDistX: {get: function(){return showDistX;}, set: function(_){showDistX=_;}},
showDistY: {get: function(){return showDistY;}, set: function(_){showDistY=_;}},
showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}},
showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}},
showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}},
defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}},
noData: {get: function(){return noData;}, set: function(_){noData=_;}},
duration: {get: function(){return duration;}, set: function(_){duration=_;}},
// deprecated options
tooltips: {get: function(){return tooltip.enabled();}, set: function(_){
// deprecated after 1.7.1
nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead');
tooltip.enabled(!!_);
}},
tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){
// deprecated after 1.7.1
nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead');
tooltip.contentGenerator(_);
}},
tooltipXContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){
// deprecated after 1.7.1
nv.deprecated('tooltipContent', 'This option is removed, put values into main tooltip.');
}},
tooltipYContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){
// deprecated after 1.7.1
nv.deprecated('tooltipContent', 'This option is removed, put values into main tooltip.');
}},
// options that require extra logic in the setter
margin: {get: function(){return margin;}, set: function(_){
margin.top = _.top !== undefined ? _.top : margin.top;
margin.right = _.right !== undefined ? _.right : margin.right;
margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
margin.left = _.left !== undefined ? _.left : margin.left;
}},
rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){
rightAlignYAxis = _;
yAxis.orient( (_) ? 'right' : 'left');
}},
color: {get: function(){return color;}, set: function(_){
color = nv.utils.getColor(_);
legend.color(color);
distX.color(color);
distY.color(color);
}}
});
nv.utils.inheritOptions(chart, scatter);
nv.utils.initOptions(chart);
return chart;
};
nv.models.sparkline = function() {
"use strict";
//============================================================
// Public Variables with Default Settings
//------------------------------------------------------------
var margin = {top: 2, right: 0, bottom: 2, left: 0}
, width = 400
, height = 32
, container = null
, animate = true
, x = d3.scale.linear()
, y = d3.scale.linear()
, getX = function(d) { return d.x }
, getY = function(d) { return d.y }
, color = nv.utils.getColor(['#000'])
, xDomain
, yDomain
, xRange
, yRange
;
function chart(selection) {
selection.each(function(data) {
var availableWidth = width - margin.left - margin.right,
availableHeight = height - margin.top - margin.bottom;
container = d3.select(this);
nv.utils.initSVG(container);
// Setup Scales
x .domain(xDomain || d3.extent(data, getX ))
.range(xRange || [0, availableWidth]);
y .domain(yDomain || d3.extent(data, getY ))
.range(yRange || [availableHeight, 0]);
// Setup containers and skeleton of chart
var wrap = container.selectAll('g.nv-wrap.nv-sparkline').data([data]);
var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-sparkline');
var gEnter = wrapEnter.append('g');
var g = wrap.select('g');
wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
var paths = wrap.selectAll('path')
.data(function(d) { return [d] });
paths.enter().append('path');
paths.exit().remove();
paths
.style('stroke', function(d,i) { return d.color || color(d, i) })
.attr('d', d3.svg.line()
.x(function(d,i) { return x(getX(d,i)) })
.y(function(d,i) { return y(getY(d,i)) })
);
// TODO: Add CURRENT data point (Need Min, Mac, Current / Most recent)
var points = wrap.selectAll('circle.nv-point')
.data(function(data) {
var yValues = data.map(function(d, i) { return getY(d,i); });
function pointIndex(index) {
if (index != -1) {
var result = data[index];
result.pointIndex = index;
return result;
} else {
return null;
}
}
var maxPoint = pointIndex(yValues.lastIndexOf(y.domain()[1])),
minPoint = pointIndex(yValues.indexOf(y.domain()[0])),
currentPoint = pointIndex(yValues.length - 1);
return [minPoint, maxPoint, currentPoint].filter(function (d) {return d != null;});
});
points.enter().append('circle');
points.exit().remove();
points
.attr('cx', function(d,i) { return x(getX(d,d.pointIndex)) })
.attr('cy', function(d,i) { return y(getY(d,d.pointIndex)) })
.attr('r', 2)
.attr('class', function(d,i) {
return getX(d, d.pointIndex) == x.domain()[1] ? 'nv-point nv-currentValue' :
getY(d, d.pointIndex) == y.domain()[0] ? 'nv-point nv-minValue' : 'nv-point nv-maxValue'
});
});
return chart;
}
//============================================================
// Expose Public Variables
//------------------------------------------------------------
chart.options = nv.utils.optionsFunc.bind(chart);
chart._options = Object.create({}, {
// simple options, just get/set the necessary values
width: {get: function(){return width;}, set: function(_){width=_;}},
height: {get: function(){return height;}, set: function(_){height=_;}},
xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}},
yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}},
xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}},
yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}},
xScale: {get: function(){return x;}, set: function(_){x=_;}},
yScale: {get: function(){return y;}, set: function(_){y=_;}},
animate: {get: function(){return animate;}, set: function(_){animate=_;}},
//functor options
x: {get: function(){return getX;}, set: function(_){getX=d3.functor(_);}},
y: {get: function(){return getY;}, set: function(_){getY=d3.functor(_);}},
// options that require extra logic in the setter
margin: {get: function(){return margin;}, set: function(_){
margin.top = _.top !== undefined ? _.top : margin.top;
margin.right = _.right !== undefined ? _.right : margin.right;
margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom;
margin.left = _.left !== undefined ? _.left : margin.left;
}},
color: {get: function(){return color;}, set: function(_){
color = nv.utils.getColor(_);
}}
});
nv.utils.initOptions(chart);
return chart;
};
nv.models.sparklinePlus = function() {
"use strict";
//============================================================
// Public Variables with Default Settings
//------------------------------------------------------------
var sparkline = nv.models.sparkline();
var margin = {top: 15, right: 100, bottom: 10, left: 50}
, width = null
, height = null
, x
, y
, index = []
, paused = false
, xTickFormat = d3.format(',r')
, yTickFormat = d3.format(',.2f')
, showLastValue = true
, alignValue = true
, rightAlignValue = false
, noData = null
;
function chart(selection) {
selection.each(function(data) {
var container = d3.select(this);
nv.utils.initSVG(container);
var availableWidth = nv.utils.availableWidth(width, container, margin),
availableHeight = nv.utils.availableHeight(height, container, margin);
chart.update = function() { container.call(chart); };
chart.container = this;
// Display No Data message if there's nothing to show.
if (!data || !data.length) {
nv.utils.noData(chart, container)
return chart;
} else {
container.selectAll('.nv-noData').remove();
}
var currentValue = sparkline.y()(data[data.length-1], data.length-1);
// Setup Scales
x = sparkline.xScale();
y = sparkline.yScale();
// Setup containers and skeleton of chart
var wrap = container.selectAll('g.nv-wrap.nv-sparklineplus').data([data]);
var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-sparklineplus');
var gEnter = wrapEnter.append('g');
var g = wrap.select('g');
gEnter.append('g').attr('class', 'nv-sparklineWrap');
gEnter.append('g').attr('class', 'nv-valueWrap');
gEnter.append('g').attr('class', 'nv-hoverArea');
wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
// Main Chart Component(s)
var sparklineWrap = g.select('.nv-sparklineWrap');
sparkline.width(availableWidth).height(availableHeight);
sparklineWrap.call(sparkline);
if (showLastValue) {
var valueWrap = g.select('.nv-valueWrap');
var value = valueWrap.selectAll('.nv-currentValue')
.data([currentValue]);
value.enter().append('text').attr('class', 'nv-currentValue')
.attr('dx', rightAlignValue ? -8 : 8)
.attr('dy', '.9em')
.style('text-anchor', rightAlignValue ? 'end' : 'start');
value
.attr('x', availableWidth + (rightAlignValue ? margin.right : 0))
.attr('y', alignValue ? function (d) {
return y(d)
} : 0)
.style('fill', sparkline.color()(data[data.length - 1], data.length - 1))
.text(yTickFormat(currentValue));
}
gEnter.select('.nv-hoverArea').append('rect')
.on('mousemove', sparklineHover)
.on('click', function() { paused = !paused })
.on('mouseout', function() { index = []; updateValueLine(); });
g.select('.nv-hoverArea rect')
.attr('transform', function(d) { return 'translate(' + -margin.left + ',' + -margin.top + ')' })
.attr('width', availableWidth + margin.left + margin.right)
.attr('height', availableHeight + margin.top);
//index is currently global (within the chart), may or may not keep it that way
function updateValueLine() {
if (paused) return;
var hoverValue = g.selectAll('.nv-hoverValue').data(index);
var hoverEnter = hoverValue.enter()
.append('g').attr('class', 'nv-hoverValue')
.style('stroke-opacity', 0)
.style('fill-opacity', 0);
hoverValue.exit()
.transition().duration(250)
.style('stroke-opacity', 0)
.style('fill-opacity', 0)
.remove();
hoverValue
.attr('transform', function(d) { return 'translate(' + x(sparkline.x()(data[d],d)) + ',0)' })
.transition().duration(250)
.style('stroke-opacity', 1)
.style('fill-opacity', 1);
if (!index.length) return;
hoverEnter.append('line')
.attr('x1', 0)
.attr('y1', -margin.top)
.attr('x2', 0)
.attr('y2', availableHeight);
hoverEnter.append('text').attr('class', 'nv-xValue')
.attr('x', -6)
.attr('y', -margin.top)
.attr('text-anchor', 'end')
.attr('dy', '.9em');
g.select('.nv-hoverValue .nv-xValue')
.text(xTickFormat(sparkline.x()(data[index[0]], index[0])));
hoverEnter.append('text').attr('class', 'nv-yValue')
.attr('x', 6)
.attr('y', -margin.top)
.attr('text-anchor', 'start')
.attr('dy', '.9em');
g.select('.nv-hoverValue .nv-yValue')
.text(yTickFormat(sparkline.y()(data[index[0]], index[0])));
}
function sparklineHover() {
if (paused) return;
var pos = d3.mouse(this)[0] - margin.left;
function getClosestIndex(data, x) {
var distance = Math.abs(sparkline.x()(data[0], 0) - x);
var closestIndex = 0;
for (var i = 0; i < data.length; i++){
if (Math.abs(sparkline.x()(data[i], i) - x) < distance) {