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);
+ Util.assertFontSizes(graph, "dygraph-axis-label-x", 14);
+ Util.assertFontSizes(graph, "dygraph-axis-label-y", 14);
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.
+ Util.assertFontSizes(graph, "dygraph-axis-label-x", 8);
+ Util.assertFontSizes(graph, "dygraph-axis-label-y", 8);
g.updateOptions({
axisLabelFontSize : null,
- axes : {
+ axes : {
x : { axisLabelFontSize : 5 },
- }
- });
+ }
+ });
- assertSize("dygraph-axis-label-x", 5);
- assertSize("dygraph-axis-label-y", 14);
+ Util.assertFontSizes(graph, "dygraph-axis-label-x", 5);
+ Util.assertFontSizes(graph, "dygraph-axis-label-y", 14);
g.updateOptions({
- axisLabelFontSize : null,
- axes : {
- y : { axisLabelFontSize : 3 },
- }
- });
+ axes : {
+ y : { axisLabelFontSize : 20 },
+ }
+ });
- assertSize("dygraph-axis-label-x", 5);
- assertSize("dygraph-axis-label-y", 3);
+ Util.assertFontSizes(graph, "dygraph-axis-label-x", 5);
+ Util.assertFontSizes(graph, "dygraph-axis-label-y", 20);
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 },
+ }
+ });
+
+ Util.assertFontSizes(graph, "dygraph-axis-label-x", 5);
+ Util.assertFontSizes(graph, "dygraph-axis-label-y1", 20);
+ Util.assertFontSizes(graph, "dygraph-axis-label-y2", 12);
}
AxisLabelsTestCase.prototype.testAxisLabelFontSizeNull = function() {
* 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"] || {});
};
/**
*
* @param {String} name the name of the option.
* @param {String|number} axis the axis to search. Can be the string representation
- * ("y", "y2") or the axis number (0, 1).
+ * ("x", "y", "y2") or the y-axis number (0, 1). (x-axis can't be specified by number.')
*/
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')
MultiPalette.prototype.showHash = function() {
var hash = this.read();
var textarea = new TextArea();
- textarea.cancel.style.display = "none";
-
- /*
- * JSON.stringify isn't built to be nice to functions. The following fixes
- * this.
- *
- * First, val.toString only does part of the work, turning it into
- * "function () {\n alert(\"p-click!\");\n}",
- *
- * {start,end}Marker make the surrounding quotes easy to find, and then
- * remove them. It also converts the instances of \n and \" so the
- * result looks like:
- * function () {
- * alert("p-click!");
- * }",
- */
- var startMarker = "<~%!<";
- var endMarker = ">!%~>";
- var replacer = function(key, val) {
- if (typeof val === 'function') {
- return startMarker + val.toString() + endMarker;
- }
- return val;
- }
- var text = JSON.stringify(hash, replacer, 2);
- while(true) {
- var start = text.indexOf(startMarker);
- var end = text.indexOf(endMarker);
- if (start == -1) {
- break;
- }
- var substring = text.substring(start + startMarker.length, end);
- while(substring.indexOf("\\n") >= 0) {
- substring = substring.replace("\\n", "\n");
+
+ var hashToString = function(hash) {
+ /*
+ * JSON.stringify isn't built to be nice to functions. The following fixes
+ * this.
+ *
+ * First, val.toString only does part of the work, turning it into
+ * "function () {\n alert(\"p-click!\");\n}",
+ *
+ * {start,end}Marker make the surrounding quotes easy to find, and then
+ * remove them. It also converts the instances of \n and \" so the
+ * result looks like:
+ * function () {
+ * alert("p-click!");
+ * }",
+ */
+ var startMarker = "<~%!<";
+ var endMarker = ">!%~>";
+ var replacer = function(key, val) {
+ if (typeof val === 'function') {
+ return startMarker + val.toString() + endMarker;
+ }
+ return val;
}
- while(substring.indexOf("\\\"") >= 0) {
- substring = substring.replace("\\\"", "\"");
+ var text = JSON.stringify(hash, replacer, 2);
+ while(true) {
+ var start = text.indexOf(startMarker);
+ var end = text.indexOf(endMarker);
+ if (start == -1) {
+ break;
+ }
+ var substring = text.substring(start + startMarker.length, end);
+ while(substring.indexOf("\\n") >= 0) {
+ substring = substring.replace("\\n", "\n");
+ }
+ while(substring.indexOf("\\\"") >= 0) {
+ substring = substring.replace("\\\"", "\"");
+ }
+ text = text.substring(0, start - 1)
+ + substring
+ + text.substring(end + endMarker.length + 1);
}
- text = text.substring(0, start - 1)
- + substring
- + text.substring(end + endMarker.length + 1);
+ return text;
}
+
+ var text = hashToString(hash);
+ var self = this;
textarea.show("options", text);
+ textarea.okCallback = function(value) {
+ if (value != text) {
+ var newHash;
+ eval("newHash = " + value + ";");
+ self.write(newHash);
+ self.onchange();
+ }
+ };
}
/**
avoidMinZero : {
type : "boolean"
},
+ axis : {
+ type : "string",
+ scope : [ "series" ]
+ },
axisLabelColor : {
type : "string",
// scope : [ "x", "y", "y2" ]
},
axisLabelFontSize : {
type : "int",
- // scope : [ "x", "y", "y2" ]
+ scope : [ "global", "x", "y", "y2" ]
},
axisLabelFormatter : {
type : "function(numberOrDate, granularity, opts, dygraph)",
* Write to input elements.
*/
Palette.prototype.write = function(hash) {
+ if (!hash) {
+ return;
+ }
var results = {};
for (var opt in this.model) {
if (this.model.hasOwnProperty(opt)) {
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.getOption('axisLabelColor'),
+ 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/perc_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];
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) -