Add missing tests to local.html, organize.
<![endif]-->
<script type="text/javascript" src="../../dygraph-dev.js"></script>
- <!-- Scripts for automated tests -->
+ <!-- Scripts for library support -->
<script type="text/javascript" src="../lib/jquery-1.4.2.js"></script>
<script type="text/javascript" src="../lib/Asserts.js"></script>
<script type="text/javascript" src="fake-jstestdriver.js"></script>
<script type="text/javascript" src="../tests/CanvasAssertions.js"></script>
<script type="text/javascript" src="../tests/DygraphOps.js"></script>
<script type="text/javascript" src="../tests/PixelSampler.js"></script>
+
+ <!-- Scripts for automated tests -->
<script type="text/javascript" src="../tests/annotations.js"></script>
<script type="text/javascript" src="../tests/axis_labels.js"></script>
<script type="text/javascript" src="../tests/callback.js"></script>
<script type="text/javascript" src="../tests/formats.js"></script>
<script type="text/javascript" src="../tests/interaction_model.js"></script>
<script type="text/javascript" src="../tests/missing_points.js"></script>
- <script type="text/javascript" src="../tests/multiple_axes.js"></script>
<script type="text/javascript" src="../tests/multi_csv.js"></script>
+ <script type="text/javascript" src="../tests/multiple_axes.js"></script>
<script type="text/javascript" src="../tests/no_hours.js"></script>
+ <script type="text/javascript" src="../tests/parser.js"></script>
<script type="text/javascript" src="../tests/pathological_cases.js"></script>
-
+ <script type="text/javascript" src="../tests/per-series.js"></script>
+ <script type="text/javascript" src="../tests/range_selector.js"></script>
<script type="text/javascript" src="../tests/range_tests.js"></script>
<script type="text/javascript" src="../tests/rolling_average.js"></script>
<script type="text/javascript" src="../tests/sanity.js"></script>
- <script type="text/javascript" src="../tests/selection.js"></script>
<script type="text/javascript" src="../tests/scientific_notation.js"></script>
<script type="text/javascript" src="../tests/scrolling_div.js"></script>
+ <script type="text/javascript" src="../tests/selection.js"></script>
<script type="text/javascript" src="../tests/simple_drawing.js"></script>
+ <script type="text/javascript" src="../tests/stacked.js"></script>
<!--
<script type="text/javascript" src="../tests/tickers.js"></script>
-->
<script type="text/javascript" src="../tests/to_dom_coords.js"></script>
- <script type="text/javascript" src="../tests/update_while_panning.js"></script>
- <script type="text/javascript" src="../tests/stacked.js"></script>
- <script type="text/javascript" src="../tests/per_series.js"></script>
- <script type="text/javascript" src="../tests/parser.js"></script>
<script type="text/javascript" src="../tests/update_options.js"></script>
+ <script type="text/javascript" src="../tests/update_while_panning.js"></script>
<script type="text/javascript" src="../tests/utils_test.js"></script>
<style type="text/css">
);
assertEquals(["40", "45", "50", "55", "60", "65", "70", "75"], getYLabelsForAxis("1"));
assertEquals(["1M", "1.02M", "1.05M", "1.08M", "1.1M", "1.13M", "1.15M", "1.18M"], getYLabelsForAxis("2"));
-};
\ No newline at end of file
+};
+
+MultipleAxesTestCase.prototype.testDrawPointCallback = function() {
+ var data = MultipleAxesTestCase.getData();
+
+ var results = { y : {}, y2 : {}};
+ var firstCallback = function(g, seriesName, ctx, canvasx, canvasy, color, radius) {
+ results.y[seriesName] = 1;
+ Dygraph.Circles.DEFAULT(g, seriesName, ctx, canvasx, canvasy, color, radius);
+
+ };
+ var secondCallback = function(g, seriesName, ctx, canvasx, canvasy, color, radius) {
+ results.y2[seriesName] = 1;
+ Dygraph.Circles.TRIANGLE(g, seriesName, ctx, canvasx, canvasy, color, radius);
+ };
+
+ g = new Dygraph(
+ document.getElementById("graph"),
+ data,
+ {
+ labels: [ 'Date', 'Y1', 'Y2', 'Y3', 'Y4' ],
+ drawPoints : true,
+ pointSize : 3,
+ 'Y3': {
+ axis: {
+ }
+ },
+ 'Y4': {
+ axis: 'Y3' // use the same y-axis as series Y3
+ },
+ axes: {
+ y2: {
+ drawPointCallback: secondCallback
+ }
+ },
+ drawPointCallback: firstCallback
+ }
+ );
+
+ assertEquals(1, results.y["Y1"]);
+ assertEquals(1, results.y["Y2"]);
+ assertEquals(1, results.y2["Y3"]);
+ assertEquals(1, results.y2["Y4"]);
+};
"rgbcolor/rgbcolor.js",
"stacktrace.js",
"dashed-canvas.js",
+ "dygraph-options.js",
"dygraph-layout.js",
"dygraph-canvas.js",
"dygraph.js",
--- /dev/null
+/**
+ * @fileoverview DygraphOptions is responsible for parsing and returning information about options.
+ *
+ * Still tightly coupled to Dygraphs, we could remove some of that, you know.
+ */
+
+"use strict";
+
+/*
+ * Interesting member variables:
+ * dygraph_ - the graph.
+ * global - global attributes (common among all graphs, AIUI)
+ * user - attributes set by the user
+ * axes
+ * series - { seriesName -> { idx, yAxis, options }
+ * labels - used as mapping from index to series name.
+ */
+
+/**
+ * @constructor
+ *
+ * This parses attributes into an object that can be easily queried.
+ *
+ * @param {Dyraph} dygraph The chart to which these options belong.
+ */
+var DygraphOptions = function(dygraph) {
+ this.dygraph_ = dygraph;
+ this.axes_ = [];
+ this.series_ = {};
+
+ // Once these two objects are initialized, you can call find();
+ this.global_ = this.dygraph_.attrs_;
+ this.user_ = this.dygraph_.user_attrs_ || {};
+
+ this.highlightSeries_ = this.find("highlightSeriesOpts") || {};
+ // Get a list of series names.
+
+ var labels = this.find("labels");
+ if (!labels) {
+ return; // -- can't do more for now, will parse after getting the labels.
+ };
+
+ this.reparseSeries();
+}
+
+DygraphOptions.prototype.reparseSeries = function() {
+ this.labels = this.find("labels").slice(1);
+
+ this.axes_ = [ {} ]; // Always one axis at least.
+ this.series_ = {};
+
+ var axisId = 0; // 0-offset; there's always one.
+ // Go through once, add all the series, and for those with {} axis options, add a new axis.
+ for (var idx = 0; idx < this.labels.length; idx++) {
+ var seriesName = this.labels[idx];
+
+ var optionsForSeries = this.user_[seriesName] || {};
+ var yAxis = 0;
+
+ var axis = optionsForSeries["axis"];
+ if (typeof(axis) == 'object') {
+ yAxis = ++axisId;
+ this.axes_[yAxis] = axis;
+ }
+ this.series_[seriesName] = { idx: idx, yAxis: yAxis, options : optionsForSeries };
+ }
+
+ // Go through one more time and assign series to an axis defined by another
+ // series, e.g. { 'Y1: { axis: {} }, 'Y2': { axis: 'Y1' } }
+ for (var idx = 0; idx < this.labels.length; idx++) {
+ var seriesName = this.labels[idx];
+ var optionsForSeries = this.series_[seriesName]["options"];
+ var axis = optionsForSeries["axis"];
+
+ if (typeof(axis) == 'string') {
+ if (!this.series_.hasOwnProperty(axis)) {
+ this.dygraph_.error("Series " + seriesName + " wants to share a y-axis with " +
+ "series " + axis + ", which does not define its own axis.");
+ return null;
+ }
+ this.series_[seriesName].yAxis = this.series_[axis].yAxis;
+ }
+ }
+
+ // This doesn't support reading from the 'x' axis, only 'y' and 'y2.
+ // Read from the global "axes" option.
+ if (this.user_.hasOwnProperty("axes")) {
+ var axis_opts = this.user_.axes;
+
+ if (axis_opts.hasOwnProperty("y")) {
+ Dygraph.update(this.axes_[0], axis_opts.y);
+ }
+
+ if (axis_opts.hasOwnProperty("y2")) {
+ this.axes_[1] = this.axes_[1] || {};
+ Dygraph.update(this.axes_[1], axis_opts.y2);
+ }
+ }
+};
+
+DygraphOptions.prototype.find = function(name) {
+ if (this.user_.hasOwnProperty(name)) {
+ return this.user_[name];
+ }
+ if (this.global_.hasOwnProperty(name)) {
+ return this.global_[name];
+ }
+ return null;
+}
+
+DygraphOptions.prototype.findForAxis = function(name, axis) {
+ var axisIdx = (axis == "y2" || axis == "y2" || axis == 1) ? 1 : 0;
+
+ var axisOptions = this.axes_[axisIdx];
+ if (axisOptions.hasOwnProperty(name)) {
+ return axisOptions[name];
+ }
+ return this.find(name);
+}
+
+DygraphOptions.prototype.findForSeries = function(name, series) {
+ // Honors indexes as series.
+ var seriesName = (typeof(series) == "number") ? this.labels[series] : series;
+
+ if (seriesName === this.dygraph_.highlightSet_) {
+ if (this.highlightSeries_.hasOwnProperty(name)) {
+ return this.highlightSeries_[name];
+ }
+ }
+
+ if (!this.series_.hasOwnProperty(seriesName)) {
+ throw "Unknown series: " + series;
+ }
+
+ var seriesObj = this.series_[seriesName];
+ var seriesOptions = seriesObj["options"];
+ if (seriesOptions.hasOwnProperty(name)) {
+ return seriesOptions[name];
+ }
+
+ return this.findForAxis(name, seriesObj["yAxis"]);
+}
+
this.registeredEvents_ = [];
this.eventListeners_ = {};
+ this.attributes_ = new DygraphOptions(this);
+
// Create the containing DIV and other interactive elements
this.createInterface_();
}
// </REMOVE_FOR_COMBINED>
+ // Building an array which we peruse in backwards order to find the correct value.
+ // Options are checked in this order:
+ // series, axis, user attrs, global attrs.
+ // TODO(konigsberg): Can this be made faster by starting with the series and working outward,
+ // rather than building an array?
+
var sources = [];
sources.push(this.attrs_);
if (this.user_attrs_) {
if (this.user_attrs_.hasOwnProperty(seriesName)) {
sources.push(this.user_attrs_[seriesName]);
}
+
+ // TODO(konigsberg): This special case ought to be documented.
if (seriesName === this.highlightSet_ &&
this.user_attrs_.hasOwnProperty('highlightSeriesOpts')) {
sources.push(this.user_attrs_.highlightSeriesOpts);
break;
}
}
- return ret;
+
+ var computedValue = seriesName ? this.attributes_.findForSeries(name, seriesName) : this.attributes_.find(name);
+ if (ret !== computedValue) {
+ console.log("Mismatch", name, seriesName, ret, computedValue);
+ }
+
+ var USE_NEW_VALUE = true;
+ return USE_NEW_VALUE ? computedValue : ret;
};
/**
// rolling averages.
this.rolledSeries_ = [null]; // x-axis is the first series and it's special
for (var i = 1; i < this.numColumns(); i++) {
- var logScale = this.attr_('logscale', i); // TODO(klausw): this looks wrong
+ // var logScale = this.attr_('logscale', i); // TODO(klausw): this looks wrong // konigsberg thinks so too.
+ var logScale = this.attr_('logscale');
var series = this.extractSeries_(this.rawData_, i, logScale);
series = this.rollingAverage(series, this.rollPeriod_);
this.rolledSeries_.push(series);
// User hasn't explicitly set labels, so they're (presumably) in the CSV.
start = 1;
this.attrs_.labels = lines[0].split(delim); // NOTE: _not_ user_attrs_.
+ this.attributes_.reparseSeries();
}
var line_no = 0;
"in the options parameter");
this.attrs_.labels = [ "X" ];
for (i = 1; i < data[0].length; i++) {
- this.attrs_.labels.push("Y" + i);
+ this.attrs_.labels.push("Y" + i); // Not user_attrs_.
}
+ this.attributes_.reparseSeries();
} else {
var num_labels = this.attr_("labels");
if (num_labels.length != data[0].length) {