// 2. e.relatedTarget is outside the chart
var target = e.target || e.fromElement;
var relatedTarget = e.relatedTarget || e.toElement;
- if (Dygraph.isElementContainedBy(target, dygraph.graphDiv) &&
- !Dygraph.isElementContainedBy(relatedTarget, dygraph.graphDiv)) {
+ if (Dygraph.isNodeContainedBy(target, dygraph.graphDiv) &&
+ !Dygraph.isNodeContainedBy(relatedTarget, dygraph.graphDiv)) {
dygraph.mouseOut_(e);
}
};
var datasets = [];
var extremes = {}; // series name -> [low, high]
var i, j, k;
+ var errorBars = this.attr_("errorBars");
+ var customBars = this.attr_("customBars");
+ var bars = errorBars || customBars;
+ var isValueNull = function(sample) {
+ if (!bars) {
+ return sample[1] === null;
+ } else {
+ return customBars ? sample[1][1] === null :
+ errorBars ? sample[1][0] === null : false;
+ }
+ };
// Loop over the fields (series). Go from the last to the first,
// because if they're stacked that's how we accumulate the values.
// Prune down to the desired range, if necessary (for zooming)
// Because there can be lines going to points outside of the visible area,
// we actually prune to visible points, plus one on either side.
- var bars = this.attr_("errorBars") || this.attr_("customBars");
if (dateWindow) {
var low = dateWindow[0];
var high = dateWindow[1];
var pruned = [];
+
// TODO(danvk): do binary search instead of linear search.
// TODO(danvk): pass firstIdx and lastIdx directly to the renderer.
var firstIdx = null, lastIdx = null;
lastIdx = k;
}
}
+
if (firstIdx === null) firstIdx = 0;
- if (firstIdx > 0) firstIdx--;
+ var correctedFirstIdx = firstIdx;
+ var isInvalidValue = true;
+ while (isInvalidValue && correctedFirstIdx > 0) {
+ correctedFirstIdx--;
+ isInvalidValue = isValueNull(series[correctedFirstIdx]);
+ }
+
if (lastIdx === null) lastIdx = series.length - 1;
- if (lastIdx < series.length - 1) lastIdx++;
- boundaryIds[i-1] = [firstIdx, lastIdx];
+ var correctedLastIdx = lastIdx;
+ isInvalidValue = true;
+ while (isInvalidValue && correctedLastIdx < series.length - 1) {
+ correctedLastIdx++;
+ isInvalidValue = isValueNull(series[correctedLastIdx]);
+ }
+
+ boundaryIds[i-1] = [(firstIdx > 0) ? firstIdx - 1 : firstIdx,
+ (lastIdx < series.length - 1) ? lastIdx + 1 : lastIdx];
+
+ if (correctedFirstIdx!==firstIdx) {
+ pruned.push(series[correctedFirstIdx]);
+ }
for (k = firstIdx; k <= lastIdx; k++) {
pruned.push(series[k]);
}
+ if (correctedLastIdx !== lastIdx) {
+ pruned.push(series[correctedLastIdx]);
+ }
+
series = pruned;
} else {
boundaryIds[i-1] = [0, series.length-1];
// Save the X axis zoomed status as the updateOptions call will tend to set it erroneously
var tmp_zoomed_x = this.zoomed_x_;
// Tell PlotKit to use this new data and render itself
- this.layout_.setDateWindow(this.dateWindow_);
this.zoomed_x_ = tmp_zoomed_x;
this.layout_.evaluateWithError();
this.renderGraph_(is_initial_draw);
opts,
this);
// Define the first independent axis as primary axis.
- if(!p_axis)
- p_axis = axis;
+ if (!p_axis) p_axis = axis;
}
}
- if(p_axis === undefined)
+ if (p_axis === undefined) {
throw ("Configuration Error: At least one axis has to have the \"independentTicks\" option activated.");
+ }
// Add ticks. By default, all axes inherit the tick positions of the
// primary axis. However, if an axis is specifically marked as having
// independent ticks, then that is permissible as well.
Dygraph.prototype.extractSeries_ = function(rawData, i, logScale) {
// TODO(danvk): pre-allocate series here.
var series = [];
+ var errorBars = this.attr_("errorBars");
+ var customBars = this.attr_("customBars");
for (var j = 0; j < rawData.length; j++) {
var x = rawData[j][0];
var point = rawData[j][i];
point = null;
}
}
- series.push([x, point]);
+ // Fix null points to fit the display type standard.
+ if(point !== null) {
+ series.push([x, point]);
+ } else {
+ series.push([x, errorBars ? [null, null] : customBars ? [null, null, null] : point]);
+ }
}
return series;
};