};
/**
- * Assert that all the elements in 'parent' with class 'className' is
- * the expected font size.
+ * Assert that all elements have a certain style property.
*/
-Util.assertFontSizes = function(parent, className, expectedSize) {
- var expectedSizePx = expectedSize + "px";
- var labels = parent.getElementsByClassName(className);
- assertTrue(labels.length > 0);
-
- // window.getComputedStyle is apparently compatible with all browsers
- // (IE first became compatible with IE9.)
- // If this test fails on earlier browsers, then enable something like this,
- // because the font size is set by the parent div.
- // if (!window.getComputedStyle) {
- // fontSize = label.parentElement.style.fontSize;
- // }
- for (var idx = 0; idx < labels.length; idx++) {
- var label = labels[idx];
- var fontSize = window.getComputedStyle(label).fontSize;
- assertEquals(expectedSizePx, fontSize);
- }
+Util.assertStyleOfChildren = function(selector, property, expectedValue) {
+ assertTrue(selector.length > 0);
+ $.each(selector, function(idx, child) {
+ assertEquals(expectedValue, $(child).css(property));
+ });
};
AxisLabelsTestCase.prototype.testAxisLabelFontSize = function() {
var graph = document.getElementById("graph");
var g = new Dygraph(graph, AxisLabelsTestCase.simpleData, {});
- var assertSize = function(className, size) {
- var sizePx = size + "px";
- var labels = graph.getElementsByClassName(className);
- assertTrue(labels.length > 0);
-
- // window.getComputedStyle is apparently compatible with all browsers
- // (IE first became compatible with IE9.)
- // If this test fails on earlier browsers, then enable something like this,
- // because the font size is set by the parent div.
- // if (!window.getComputedStyle) {
- // fontSize = label.parentElement.style.fontSize;
- // }
- for (var idx = 0; idx < labels.length; idx++) {
- var label = labels[idx];
- var fontSize = window.getComputedStyle(label).fontSize;
- assertEquals(sizePx, fontSize);
- }
- }
// Be sure we're dealing with a 14-point default.
assertEquals(14, Dygraph.DEFAULT_ATTRS.axisLabelFontSize);
- assertSize("dygraph-axis-label-x", 14);
- assertSize("dygraph-axis-label-y", 14);
+ var assertFontSize = function(selector, expected) {
+ Util.assertStyleOfChildren(selector, "font-size", expected);
+ }
+
+ assertFontSize($(".dygraph-axis-label-x"), "14px");
+ assertFontSize($(".dygraph-axis-label-y") , "14px");
g.updateOptions({ axisLabelFontSize : 8});
- assertSize("dygraph-axis-label-x", 8);
- assertSize("dygraph-axis-label-y", 8);
-
-/*
- Enable these tests when https://code.google.com/p/dygraphs/issues/detail?id=126
- is fixed.
+ assertFontSize($(".dygraph-axis-label-x"), "8px");
+ assertFontSize($(".dygraph-axis-label-y"), "8px");
g.updateOptions({
axisLabelFontSize : null,
- axes : {
+ axes : {
x : { axisLabelFontSize : 5 },
- }
- });
+ }
+ });
- assertSize("dygraph-axis-label-x", 5);
- assertSize("dygraph-axis-label-y", 14);
+ assertFontSize($(".dygraph-axis-label-x"), "5px");
+ assertFontSize($(".dygraph-axis-label-y"), "14px");
g.updateOptions({
- axisLabelFontSize : null,
- axes : {
- y : { axisLabelFontSize : 3 },
- }
- });
+ axes : {
+ y : { axisLabelFontSize : 20 },
+ }
+ });
- assertSize("dygraph-axis-label-x", 5);
- assertSize("dygraph-axis-label-y", 3);
+ assertFontSize($(".dygraph-axis-label-x"), "5px");
+ assertFontSize($(".dygraph-axis-label-y"), "20px");
g.updateOptions({
- series : {
+ series : {
Y2 : { axis : "y2" } // copy y2 series to y2 axis.
- },
- axes : {
- y2 : { axisLabelFontSize : 8 },
- }
- });
-
- assertSize("dygraph-axis-label-x", 5);
- assertSize("dygraph-axis-label-y", 3);
- assertSize("dygraph-axis-label-y2", 8);
-*/
+ },
+ axes : {
+ y2 : { axisLabelFontSize : 12 },
+ }
+ });
+
+ assertFontSize($(".dygraph-axis-label-x"), "5px");
+ assertFontSize($(".dygraph-axis-label-y1"), "20px");
+ assertFontSize($(".dygraph-axis-label-y2"), "12px");
}
AxisLabelsTestCase.prototype.testAxisLabelFontSizeNull = function() {
axisLabelFontSize: null
});
+ var assertFontSize = function(selector, expected) {
+ Util.assertStyleOfChildren(selector, "font-size", expected);
+ };
+
+ // Be sure we're dealing with a 14-point default.
+ assertEquals(14, Dygraph.DEFAULT_ATTRS.axisLabelFontSize);
+
+ assertFontSize($(".dygraph-axis-label-x"), "14px");
+ assertFontSize($(".dygraph-axis-label-y"), "14px");
+}
+
+AxisLabelsTestCase.prototype.testAxisLabelColor = function() {
+ var graph = document.getElementById("graph");
+ var g = new Dygraph(graph, AxisLabelsTestCase.simpleData, {});
+
+ // Be sure we're dealing with a black default.
+ assertEquals("black", Dygraph.DEFAULT_ATTRS.axisLabelColor);
+
+ var assertColor = function(selector, expected) {
+ Util.assertStyleOfChildren(selector, "color", expected);
+ }
+
+ assertColor($(".dygraph-axis-label-x"), "rgb(0, 0, 0)");
+ assertColor($(".dygraph-axis-label-y"), "rgb(0, 0, 0)");
+
+ g.updateOptions({ axisLabelColor : "red"});
+ assertColor($(".dygraph-axis-label-x"), "rgb(255, 0, 0)");
+ assertColor($(".dygraph-axis-label-y"), "rgb(255, 0, 0)");
+
+ g.updateOptions({
+ axisLabelColor : null,
+ axes : {
+ x : { axisLabelColor : "blue" },
+ }
+ });
+
+ assertColor($(".dygraph-axis-label-x"), "rgb(0, 0, 255)");
+ assertColor($(".dygraph-axis-label-y"), "rgb(0, 0, 0)");
+
+ g.updateOptions({
+ axes : {
+ y : { axisLabelColor : "green" },
+ }
+ });
+
+ assertColor($(".dygraph-axis-label-x"), "rgb(0, 0, 255)");
+ assertColor($(".dygraph-axis-label-y"), "rgb(0, 128, 0)");
+
+ g.updateOptions({
+ series : {
+ Y2 : { axis : "y2" } // copy y2 series to y2 axis.
+ },
+ axes : {
+ y2 : { axisLabelColor : "yellow" },
+ }
+ });
+
+ assertColor($(".dygraph-axis-label-x"), "rgb(0, 0, 255)");
+ assertColor($(".dygraph-axis-label-y1"), "rgb(0, 128, 0)");
+ assertColor($(".dygraph-axis-label-y2"), "rgb(255, 255, 0)");
+}
+
+AxisLabelsTestCase.prototype.testAxisLabelColorNull = function() {
+ var graph = document.getElementById("graph");
+ var g = new Dygraph(graph, AxisLabelsTestCase.simpleData,
+ {
+ axisLabelColor: null
+ });
+
+ var assertColor = function(selector, expected) {
+ Util.assertStyleOfChildren(selector, "color", expected);
+ }
+
// Be sure we're dealing with a 14-point default.
assertEquals(14, Dygraph.DEFAULT_ATTRS.axisLabelFontSize);
- Util.assertFontSizes(graph, "dygraph-axis-label-x", 14);
- Util.assertFontSizes(graph, "dygraph-axis-label-y", 14);
+ assertColor($(".dygraph-axis-label-x"), "rgb(0, 0, 0)");
+ assertColor($(".dygraph-axis-label-y"), "rgb(0, 0, 0)");
}
* dygraph_ - the graph.
* global_ - global attributes (common among all graphs, AIUI)
* user - attributes set by the user
- * axes_ - array of axis index to { series : [ series names ] , options : { axis-specific options. }
+ * yAxes_ - array of axis index to { series : [ series names ] , options : { axis-specific options. }
+ * xAxis_ - { options : { axis-specific options. }
* series_ - { seriesName -> { idx, yAxis, options }}
* labels_ - used as mapping from index to series name.
*/
*/
var DygraphOptions = function(dygraph) {
this.dygraph_ = dygraph;
- this.axes_ = [];
+ this.yAxes_ = [];
+ this.xAxis_ = {};
this.series_ = {};
// Once these two objects are initialized, you can call get();
DygraphOptions.prototype.reparseSeries = function() {
this.labels = this.get("labels").slice(1);
- this.axes_ = [ { series : [], options : {}} ]; // Always one axis at least.
+ this.yAxes_ = [ { series : [], options : {}} ]; // Always one axis at least.
+ this.xAxis_ = { options : {} };
this.series_ = {};
// Traditionally, per-series options were specified right up there with the options. For instance
var axis = optionsForSeries["axis"];
if (typeof(axis) == 'object') {
yAxis = ++axisId;
- this.axes_[yAxis] = { series : [ seriesName ], options : axis };
+ this.yAxes_[yAxis] = { series : [ seriesName ], options : axis };
}
// Associate series without axis options with axis 0.
if (!axis) { // undefined
- this.axes_[0].series.push(seriesName);
+ this.yAxes_[0].series.push(seriesName);
}
this.series_[seriesName] = { idx: idx, yAxis: yAxis, options : optionsForSeries };
}
var yAxis = this.series_[axis].yAxis;
this.series_[seriesName].yAxis = yAxis;
- this.axes_[yAxis].series.push(seriesName);
+ this.yAxes_[yAxis].series.push(seriesName);
}
}
} else {
yAxis: yAxis,
options : optionsForSeries };
- if (!this.axes_[yAxis]) {
- this.axes_[yAxis] = { series : [ seriesName ], options : {} };
+ if (!this.yAxes_[yAxis]) {
+ this.yAxes_[yAxis] = { series : [ seriesName ], options : {} };
} else {
- this.axes_[yAxis].series.push(seriesName);
+ this.yAxes_[yAxis].series.push(seriesName);
}
}
}
- // This doesn't support reading from the 'x' axis, only 'y' and 'y2.
var axis_opts = this.user_["axes"] || {};
- Dygraph.update(this.axes_[0].options, axis_opts["y"] || {});
- if (this.axes_.length > 1) {
- Dygraph.update(this.axes_[1].options, axis_opts["y2"] || {});
+ Dygraph.update(this.yAxes_[0].options, axis_opts["y"] || {});
+ if (this.yAxes_.length > 1) {
+ Dygraph.update(this.yAxes_[1].options, axis_opts["y2"] || {});
}
+ Dygraph.update(this.xAxis_.options, axis_opts["x"] || {});
};
/**
* ("y", "y2") or the axis number (0, 1).
*/
DygraphOptions.prototype.getForAxis = function(name, axis) {
- var axisIdx = 0;
+ var axisIdx;
+ var axisString;
+
+ // Since axis can be a number or a string, straighten everything out here.
if (typeof(axis) == 'number') {
axisIdx = axis;
+ axisString = axisIdx == 0 ? "y" : "y2";
} else {
- // TODO(konigsberg): Accept only valid axis strings?
- axisIdx = (axis == "y2") ? 1 : 0;
+ if (axis == "y1") { axis = "y"; } // Standardize on 'y'. Is this bad? I think so.
+ if (axis == "y") {
+ axisIdx = 0;
+ } else if (axis == "y2") {
+ axisIdx = 1;
+ } else if (axis == "x") {
+ axisIdx = -1; // simply a placeholder for below.
+ } else {
+ throw "Unknown axis " + axis;
+ }
+ axisString = axis;
}
+
+ var userAxis = (axisIdx == -1) ? this.xAxis_ : this.yAxes_[axisIdx];
+
// Search the user-specified axis option first.
- if (this.axes_[axisIdx]) {
- var axisOptions = this.axes_[axisIdx].options;
+ if (userAxis) { // This condition could be removed if we always set up this.yAxes_ for y2.
+ var axisOptions = userAxis.options;
if (axisOptions.hasOwnProperty(name)) {
return axisOptions[name];
}
}
// Default axis options third.
- var axisString = axis == 0 ? "y" : "y2";
var defaultAxisOptions = Dygraph.DEFAULT_ATTRS.axes[axisString];
if (defaultAxisOptions.hasOwnProperty(name)) {
return defaultAxisOptions[name];
* @return {Number} the number of axes.
*/
DygraphOptions.prototype.numAxes = function() {
- return this.axes_.length;
+ return this.yAxes_.length;
};
/**
/**
* Returns the options for the specified axis.
*/
+// TODO(konigsberg): this is y-axis specific. Support the x axis.
DygraphOptions.prototype.axisOptions = function(yAxis) {
- return this.axes_[yAxis].options;
+ return this.yAxes_[yAxis].options;
};
/**
* Return the series associated with an axis.
*/
DygraphOptions.prototype.seriesForAxis = function(yAxis) {
- return this.axes_[yAxis].series;
+ return this.yAxes_[yAxis].series;
};
/**
return this.attr_(name, opt_seriesName);
};
+Dygraph.prototype.getOptionForAxis = function(name, axis) {
+ return this.attributes_.getForAxis(name, axis);
+}
/**
* @private
* @param String} axis The name of the axis (i.e. 'x', 'y' or 'y2')
},
axisLabelColor : {
type : "string",
- // scope : [ "x", "y", "y2" ]
+ scope : [ "global", "x", "y", "y2" ]
},
axisLabelFontSize : {
type : "int",
- // scope : [ "x", "y", "y2" ]
+ scope : [ "global", "x", "y", "y2" ]
},
axisLabelFormatter : {
type : "function(numberOrDate, granularity, opts, dygraph)",
},
axisLabelWidth : {
type : "int",
- // scope : [ "x", "y", "y2" ]
+ // scope : [ "global", "x", "y", "y2" ]
},
axisLineColor : {
type : "string",
- // scope : [ "x", "y", "y2" ]
+ scope : [ "global", "x", "y", "y2" ]
},
axisLineWidth : {
type : "int",
- // scope : [ "x", "y", "y2" ]
+ scope : [ "global", "x", "y", "y2" ]
},
axisTickSize : {
type : "int",
- // scope : [ "x", "y", "y2" ]
+ // scope : [ "global", "x", "y", "y2" ]
},
clickCallback : {
type : "function(e, x, points)"
"use strict";
/*
-
Bits of jankiness:
- Direct layout access
- Direct area access
- Should include calculation of ticks, not just the drawing.
+Options left to make axis-friendly.
+ ('axisTickSize')
+ ('drawAxesAtZero')
+ ('xAxisHeight')
+
+These too. What is the difference between axisLablelWidth and {x,y}AxisLabelWidth?
+ ('axisLabelWidth')
+ ('xAxisLabelWidth')
+ ('yAxisLabelWidth')
*/
/**
if (g.getOption('drawXAxis')) {
var h;
+ // NOTE: I think this is probably broken now, since g.getOption() now
+ // hits the dictionary. (That is, g.getOption('xAxisHeight') now always
+ // has a value.)
if (g.getOption('xAxisHeight')) {
h = g.getOption('xAxisHeight');
} else {
- h = g.getOption('axisLabelFontSize') + 2 * g.getOption('axisTickSize');
+ h = g.getOptionForAxis('axisLabelFontSize', 'x') + 2 * g.getOption('axisTickSize');
}
var x_axis_rect = e.reserveSpaceBottom(h);
}
var label, x, y, tick, i;
- var labelStyle = {
- position: "absolute",
- fontSize: g.getOption('axisLabelFontSize') + "px",
- zIndex: 10,
- color: g.getOption('axisLabelColor'),
- width: g.getOption('axisLabelWidth') + "px",
- // height: this.attr_('axisLabelFontSize') + 2 + "px",
- lineHeight: "normal", // Something other than "normal" line-height screws up label positioning.
- overflow: "hidden"
+ var makeLabelStyle = function(axis) {
+ return {
+ position: "absolute",
+ fontSize: g.getOptionForAxis('axisLabelFontSize', axis) + "px",
+ zIndex: 10,
+ color: g.getOptionForAxis('axisLabelColor', axis),
+ width: g.getOption('axisLabelWidth') + "px",
+ // height: g.getOptionForAxis('axisLabelFontSize', 'x') + 2 + "px",
+ lineHeight: "normal", // Something other than "normal" line-height screws up label positioning.
+ overflow: "hidden"
+ };
+ }
+
+ var labelStyles = {
+ x : makeLabelStyle('x'),
+ y : makeLabelStyle('y'),
+ y2 : makeLabelStyle('y2'),
};
+
var makeDiv = function(txt, axis, prec_axis) {
+ /*
+ * This seems to be called with the following three sets of axis/prec_axis:
+ * x: undefined
+ * y: y1
+ * y: y2
+ */
var div = document.createElement("div");
+ var labelStyle = labelStyles[prec_axis == 'y2' ? 'y2' : axis];
for (var name in labelStyle) {
if (labelStyle.hasOwnProperty(name)) {
div.style[name] = labelStyle[name];
// axis lines
context.save();
- context.strokeStyle = g.getOption('axisLineColor');
- context.lineWidth = g.getOption('axisLineWidth');
var layout = g.layout_;
var area = e.dygraph.plotter_.area;
sgn = -1;
prec_axis = 'y2';
}
+ var fontSize = g.getOptionForAxis('axisLabelFontSize', prec_axis);
y = area.y + tick[1] * area.h;
/* Tick marks are currently clipped, so don't bother drawing them.
*/
label = makeDiv(tick[2], 'y', num_axes == 2 ? prec_axis : null);
- var top = (y - g.getOption('axisLabelFontSize') / 2);
+ var top = (y - fontSize / 2);
if (top < 0) top = 0;
- if (top + g.getOption('axisLabelFontSize') + 3 > canvasHeight) {
+ if (top + fontSize + 3 > canvasHeight) {
label.style.bottom = "0px";
} else {
label.style.top = top + "px";
// tick on the x-axis. Shift the bottom tick up a little bit to
// compensate if necessary.
var bottomTick = this.ylabels_[0];
- var fontSize = g.getOption('axisLabelFontSize');
+ // Interested in the y2 axis also?
+ var fontSize = g.getOptionForAxis('axisLabelFontSize', "y");
var bottom = parseInt(bottomTick.style.top, 10) + fontSize;
if (bottom > canvasHeight - fontSize) {
bottomTick.style.top = (parseInt(bottomTick.style.top, 10) -
} else {
axisX = halfUp(area.x);
}
+
+ context.strokeStyle = g.getOptionForAxis('axisLineColor', 'y');
+ context.lineWidth = g.getOptionForAxis('axisLineWidth', 'y');
+
context.beginPath();
context.moveTo(axisX, halfDown(area.y));
context.lineTo(axisX, halfDown(area.y + area.h));
// if there's a secondary y-axis, draw a vertical line for that, too.
if (g.numAxes() == 2) {
+ context.strokeStyle = g.getOptionForAxis('axisLineColor', 'y2');
+ context.lineWidth = g.getOptionForAxis('axisLineWidth', 'y2');
context.beginPath();
context.moveTo(halfDown(area.x + area.w), halfDown(area.y));
context.lineTo(halfDown(area.x + area.w), halfDown(area.y + area.h));
}
}
+ context.strokeStyle = g.getOptionForAxis('axisLineColor', 'x');
+ context.lineWidth = g.getOptionForAxis('axisLineWidth', 'x');
context.beginPath();
var axisY;
if (g.getOption('drawAxesAtZero')) {