<script type="text/javascript" src="../tests/custom_bars.js"></script>
<script type="text/javascript" src="../tests/css.js"></script>
<script type="text/javascript" src="../tests/selection.js"></script>
+ <script type="text/javascript" src="../tests/update_options.js"></script>
<script type="text/javascript">
--- /dev/null
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+/**
+ * @fileoverview Tests for the updateOptions function.
+ * @author antrob@google.com (Anthony Robledo)
+ */
+var UpdateOptionsTestCase = TestCase("update-options");
+
+UpdateOptionsTestCase.prototype.opts = {
+ width: 480,
+ height: 320,
+};
+
+UpdateOptionsTestCase.prototype.data = "X,Y1,Y2\n" +
+ "2011-01-01,2,3\n" +
+ "2011-02-02,5,3\n" +
+ "2011-03-03,6,1\n" +
+ "2011-04-04,9,5\n" +
+ "2011-05-05,8,3\n";
+
+UpdateOptionsTestCase.prototype.setUp = function() {
+ document.body.innerHTML = "<div id='graph'></div>";
+};
+
+UpdateOptionsTestCase.prototype.tearDown = function() {
+};
+
+UpdateOptionsTestCase.prototype.wrap = function(g) {
+ g._testDrawCalled = false;
+ var oldDrawGraph = Dygraph.prototype.drawGraph_;
+ Dygraph.prototype.drawGraph_ = function() {
+ g._testDrawCalled = true;
+ oldDrawGraph.call(g);
+ }
+
+ return oldDrawGraph;
+}
+
+UpdateOptionsTestCase.prototype.unWrap = function(oldDrawGraph) {
+ Dygraph.prototype.drawGraph_ = oldDrawGraph;
+}
+
+UpdateOptionsTestCase.prototype.testStrokeAll = function() {
+ var graphDiv = document.getElementById("graph");
+ var graph = new Dygraph(graphDiv, this.data, this.opts);
+ var updatedOptions = { };
+
+ updatedOptions['strokeWidth'] = 3;
+
+ // These options will allow us to jump to renderGraph_()
+ // drawGraph_() will be skipped.
+ var oldDrawGraph = this.wrap(graph);
+ graph.updateOptions(updatedOptions);
+ this.unWrap(oldDrawGraph);
+ assertFalse(graph._testDrawCalled);
+};
+
+UpdateOptionsTestCase.prototype.testStrokeSingleSeries = function() {
+ var graphDiv = document.getElementById("graph");
+ var graph = new Dygraph(graphDiv, this.data, this.opts);
+ var updatedOptions = { };
+ var optionsForY1 = { };
+
+ optionsForY1['strokeWidth'] = 3;
+ updatedOptions['Y1'] = optionsForY1;
+
+ // These options will allow us to jump to renderGraph_()
+ // drawGraph_() will be skipped.
+ var oldDrawGraph = this.wrap(graph);
+ graph.updateOptions(updatedOptions);
+ this.unWrap(oldDrawGraph);
+ assertFalse(graph._testDrawCalled);
+};
+
+UpdateOptionsTestCase.prototype.testSingleSeriesRequiresNewPoints = function() {
+ var graphDiv = document.getElementById("graph");
+ var graph = new Dygraph(graphDiv, this.data, this.opts);
+ var updatedOptions = { };
+ var optionsForY1 = { };
+ var optionsForY2 = { };
+
+ // This will not require new points.
+ optionsForY1['strokeWidth'] = 2;
+ updatedOptions['Y1'] = optionsForY1;
+
+ // This will require new points.
+ optionsForY2['stepPlot'] = true;
+ updatedOptions['Y2'] = optionsForY2;
+
+ // These options will not allow us to jump to renderGraph_()
+ // drawGraph_() must be called
+ var oldDrawGraph = this.wrap(graph);
+ graph.updateOptions(updatedOptions);
+ this.unWrap(oldDrawGraph);
+ assertTrue(graph._testDrawCalled);
+};
+
+UpdateOptionsTestCase.prototype.testWidthChangeNeedsNewPoints = function() {
+ var graphDiv = document.getElementById("graph");
+ var graph = new Dygraph(graphDiv, this.data, this.opts);
+ var updatedOptions = { };
+
+ // This will require new points.
+ updatedOptions['width'] = 600;
+
+ // These options will not allow us to jump to renderGraph_()
+ // drawGraph_() must be called
+ var oldDrawGraph = this.wrap(graph);
+ graph.updateOptions(updatedOptions);
+ this.unWrap(oldDrawGraph);
+ assertTrue(graph._testDrawCalled);
+};
return canvas;
};
+
+/**
+ * @private
+ * This function will scan the option list and determine if they
+ * require us to recalculate the pixel positions of each point.
+ * @param { List } a list of options to check.
+ * @return { Boolean } true if the graph needs new points else false.
+ */
+Dygraph.isPixelChangingOptionList = function(labels, attrs) {
+ // A whitelist of options that do not change pixel positions.
+ var pixelSafeOptions = {
+ 'annotationClickHandler': true,
+ 'annotationDblClickHandler': true,
+ 'annotationMouseOutHandler': true,
+ 'annotationMouseOverHandler': true,
+ 'axisLabelColor': true,
+ 'axisLineColor': true,
+ 'axisLineWidth': true,
+ 'clickCallback': true,
+ 'colorSaturation': true,
+ 'colorValue': true,
+ 'colors': true,
+ 'connectSeparatedPoints': true,
+ 'digitsAfterDecimal': true,
+ 'drawCallback': true,
+ 'drawPoints': true,
+ 'drawXGrid': true,
+ 'drawYGrid': true,
+ 'fillAlpha': true,
+ 'gridLineColor': true,
+ 'gridLineWidth': true,
+ 'hideOverlayOnMouseOut': true,
+ 'highlightCallback': true,
+ 'highlightCircleSize': true,
+ 'interactionModel': true,
+ 'isZoomedIgnoreProgrammaticZoom': true,
+ 'labelsDiv': true,
+ 'labelsDivStyles': true,
+ 'labelsDivWidth': true,
+ 'labelsKMB': true,
+ 'labelsKMG2': true,
+ 'labelsSeparateLines': true,
+ 'labelsShowZeroValues': true,
+ 'legend': true,
+ 'maxNumberWidth': true,
+ 'panEdgeFraction': true,
+ 'pixelsPerYLabel': true,
+ 'pointClickCallback': true,
+ 'pointSize': true,
+ 'showLabelsOnHighlight': true,
+ 'showRoller': true,
+ 'sigFigs': true,
+ 'strokeWidth': true,
+ 'underlayCallback': true,
+ 'unhighlightCallback': true,
+ 'xAxisLabelFormatter': true,
+ 'xTicker': true,
+ 'xValueFormatter': true,
+ 'yAxisLabelFormatter': true,
+ 'yValueFormatter': true,
+ 'zoomCallback': true
+ };
+
+ // Assume that we do not require new points.
+ // This will change to true if we actually do need new points.
+ var requiresNewPoints = false;
+
+ // Create a dictionary of series names for faster lookup.
+ // If there are no labels, then the dictionary stays empty.
+ var seriesNamesDictionary = { };
+ if (labels) {
+ for (var i = 1; i < labels.length; i++) {
+ seriesNamesDictionary[labels[i]] = true;
+ }
+ }
+
+ // Iterate through the list of updated options.
+ for (property in attrs) {
+ // Break early if we already know we need new points from a previous option.
+ if (requiresNewPoints) {
+ break;
+ }
+ if (attrs.hasOwnProperty(property)) {
+ // Find out of this field is actually a series specific options list.
+ if (seriesNamesDictionary[property]) {
+ // This property value is a list of options for this series.
+ // If any of these sub properties are not pixel safe, set the flag.
+ for (subProperty in attrs[property]) {
+ // Break early if we already know we need new points from a previous option.
+ if (requiresNewPoints) {
+ break;
+ }
+ if (attrs[property].hasOwnProperty(subProperty) && !pixelSafeOptions[subProperty]) {
+ requiresNewPoints = true;
+ }
+ }
+ // If this was not a series specific option list, check if its a pixel changing property.
+ } else if (!pixelSafeOptions[property]) {
+ requiresNewPoints = true;
+ }
+ }
+ }
+
+ return requiresNewPoints;
+};
this.layout_.setDateWindow(this.dateWindow_);
this.zoomed_x_ = tmp_zoomed_x;
this.layout_.evaluateWithError();
+ this.renderGraph_(is_initial_draw, false);
+
+ if (this.attr_("timingName")) {
+ var end = new Date();
+ if (console) {
+ console.log(this.attr_("timingName") + " - drawGraph: " + (end - start) + "ms")
+ }
+ }
+};
+
+Dygraph.prototype.renderGraph_ = function(is_initial_draw, clearSelection) {
this.plotter_.clear();
this.plotter_.render();
this.canvas_.getContext('2d').clearRect(0, 0, this.canvas_.width,
if (this.attr_("drawCallback") !== null) {
this.attr_("drawCallback")(this, is_initial_draw);
}
-
- if (this.attr_("timingName")) {
- var end = new Date();
- if (console) {
- console.log(this.attr_("timingName") + " - drawGraph: " + (end - start) + "ms")
- }
- }
};
/**
// drawPoints
// highlightCircleSize
+ // Check if this set options will require new points.
+ var requiresNewPoints = Dygraph.isPixelChangingOptionList(this.attr_("labels"), attrs);
+
Dygraph.update(this.user_attrs_, attrs);
if (attrs['file']) {
this.file_ = attrs['file'];
if (!block_redraw) this.start_();
} else {
- if (!block_redraw) this.predraw_();
+ if (!block_redraw) {
+ if (requiresNewPoints) {
+ this.predraw_();
+ } else {
+ this.renderGraph_(false, false);
+ }
+ }
}
};