--- /dev/null
+/**
+ * @fileoverview Test cases for the per-axis grid options, including the new
+ * option "gridLinePattern".
+ *
+ * @author david.eberlein@ch.sauter-bc.com (Fr. Sauter AG)
+ */
+var GridPerAxisTestCase = TestCase("grid-per-axis");
+
+GridPerAxisTestCase.prototype.setUp = function() {
+ document.body.innerHTML = "<div id='graph'></div>";
+};
+
+GridPerAxisTestCase.origFunc = Dygraph.getContext;
+
+GridPerAxisTestCase.prototype.setUp = function() {
+ document.body.innerHTML = "<div id='graph'></div>";
+ Dygraph.getContext = function(canvas) {
+ return new Proxy(GridPerAxisTestCase.origFunc(canvas));
+ };
+};
+
+GridPerAxisTestCase.prototype.tearDown = function() {
+ Dygraph.getContext = GridPerAxisTestCase.origFunc;
+};
+
+GridPerAxisTestCase.prototype.testIndependentGrids = function() {
+ var opts = {
+ width : 480,
+ height : 320,
+ errorBars : false,
+ labels : [ "X", "Left", "Right" ],
+ series : {
+ Left : {
+ axis : "y"
+ },
+ Right : {
+ axis : "y2"
+ }
+ },
+ axes : {
+ y2 : {
+ drawGrid : true,
+ independentTicks : true
+ }
+ }
+ };
+
+ var data = [ [ 1, 0, 0 ], [ 2, 12, 88 ], [ 3, 88, 122 ], [ 4, 63, 273 ],
+ [ 5, 110, 333 ] ];
+ var graph = document.getElementById("graph");
+ var g = new Dygraph(graph, data, opts);
+
+ htx = g.hidden_ctx_;
+
+ // The expected gridlines
+ var yGridlines = [ 0, 20, 40, 60, 80, 100, 120 ];
+ var y2Gridlines = [ 0, 50, 100, 150, 200, 250, 300, 350 ];
+ var gridlines = [ yGridlines, y2Gridlines ];
+
+ function halfUp(x) {
+ return Math.round(x) + 0.5;
+ }
+ function halfDown(y) {
+ return Math.round(y) - 0.5;
+ }
+
+ var attrs = {}, x, y;
+ x = halfUp(g.plotter_.area.x);
+ // Step through y(0) and y2(1) axis
+ for ( var axis = 0; axis < 2; axis++) {
+ // Step through all gridlines of the axis
+ for ( var i = 0; i < gridlines[axis].length; i++) {
+ // Check the labels:
+ var labels = Util.getYLabels(axis + 1);
+ assertEquals("Expected label not found.", gridlines[axis][i], labels[i]);
+
+ // Check that the grid was drawn.
+ y = halfDown(g.toDomYCoord(gridlines[axis][i], axis));
+ var p1 = [ x, y ];
+ var p2 = [ x + g.plotter_.area.w, y ];
+ CanvasAssertions.assertLineDrawn(htx, p1, p2, attrs);
+ }
+ }
+};
+
+GridPerAxisTestCase.prototype.testPerAxisGridColors = function() {
+ var opts = {
+ width : 480,
+ height : 320,
+ errorBars : false,
+ labels : [ "X", "Left", "Right" ],
+ series : {
+ Left : {
+ axis : "y"
+ },
+ Right : {
+ axis : "y2"
+ }
+ },
+ axes : {
+ y : {
+ gridLineColor : "#0000ff",
+ gridLineWidth : 2
+ },
+ y2 : {
+ drawGrid : true,
+ independentTicks : true,
+ gridLineColor : "#ff0000",
+ gridLineWidth : 2,
+ }
+ }
+ };
+ var data = [ [ 1, 0, 0 ], [ 2, 12, 88 ], [ 3, 88, 122 ], [ 4, 63, 273 ],
+ [ 5, 110, 333 ] ];
+ var graph = document.getElementById("graph");
+ var g = new Dygraph(graph, data, opts);
+ htx = g.hidden_ctx_;
+
+ // The expected gridlines
+ var yGridlines = [ 20, 40, 60, 80, 100, 120 ];
+ var y2Gridlines = [ 50, 100, 150, 200, 250, 300, 350 ];
+ var gridlines = [ yGridlines, y2Gridlines ];
+ var gridColors = [ [ 0, 0, 255, 255 ], [ 255, 0, 0, 255 ] ];
+
+ function halfUp(x) {
+ return Math.round(x) + 1;
+ }
+ function halfDown(y) {
+ return Math.round(y) - 1;
+ }
+ var x, y;
+ x = halfUp(g.plotter_.area.x);
+ // Step through y(0) and y2(1) axis
+ for ( var axis = 0; axis < 2; axis++) {
+ // Step through all gridlines of the axis
+ for ( var i = 0; i < gridlines[axis].length; i++) {
+ y = halfDown(g.toDomYCoord(gridlines[axis][i], axis));
+ // Check the grid colors.
+ assertEquals("Unexpected grid color found at pixel: x: " + x + "y: " + y,
+ gridColors[axis], Util.samplePixel(g.hidden_, x, y));
+ }
+ }
+};
+GridPerAxisTestCase.prototype.testPerAxisGridWidth = function() {
+ var opts = {
+ width : 480,
+ height : 320,
+ errorBars : false,
+ gridLineColor : "#ff0000",
+ labels : [ "X", "Left", "Right" ],
+ series : {
+ Left : {
+ axis : "y"
+ },
+ Right : {
+ axis : "y2"
+ }
+ },
+ axes : {
+ x : {
+ gridLineWidth : 4
+ },
+ y : {
+ gridLineWidth : 2
+ },
+ y2 : {
+ drawGrid : true,
+ independentTicks : true,
+ gridLineWidth : 1
+ }
+ }
+ };
+ var data = [ [ 1, 0, 0 ], [ 2, 12, 88 ], [ 3, 88, 122 ], [ 4, 63, 273 ],
+ [ 5, 110, 333 ] ];
+ var graph = document.getElementById("graph");
+ var g = new Dygraph(graph, data, opts);
+ htx = g.hidden_ctx_;
+
+ // The expected gridlines
+ var yGridlines = [ 20, 40, 60, 80 ];
+ var y2Gridlines = [ 50, 100, 150, 200, 250, 350 ];
+ var gridlines = [ yGridlines, y2Gridlines ];
+ var xGridlines = [ 2, 3, 4 ];
+ var gridColor = [ 255, 0, 0 ];
+ var emptyColor = [ 0, 0, 0 ];
+
+ function halfUp(x) {
+ return Math.round(x) + 1;
+ }
+ function halfDown(y) {
+ return Math.round(y) - 1;
+ }
+ var x, y;
+ x = halfUp(g.plotter_.area.x + 10);
+ // Step through y(0) and y2(1) axis
+ for ( var axis = 0; axis < 2; axis++) {
+ // Step through all gridlines of the axis
+ for ( var i = 0; i < gridlines[axis].length; i++) {
+ y = halfDown(g.toDomYCoord(gridlines[axis][i], axis));
+ // Ignore the alpha value
+ var drawnPixeldown2 = Util.samplePixel(g.hidden_, x, y - 2).slice(0, 3);
+ var drawnPixeldown1 = Util.samplePixel(g.hidden_, x, y - 1).slice(0, 3);
+ var drawnPixel = Util.samplePixel(g.hidden_, x, y).slice(0, 3);
+ var drawnPixelup1 = Util.samplePixel(g.hidden_, x, y + 1).slice(0, 3);
+ var drawnPixelup2 = Util.samplePixel(g.hidden_, x, y + 2).slice(0, 3);
+ // Check the grid width.
+ switch (axis) {
+ case 0: // y with 2 pixels width
+ assertEquals("Unexpected y-grid color found at pixel: x: " + x + "y: "
+ + y, emptyColor, drawnPixeldown2);
+ assertEquals("Unexpected y-grid color found at pixel: x: " + x + "y: "
+ + y, gridColor, drawnPixeldown1);
+ assertEquals("Unexpected y-grid color found at pixel: x: " + x + "y: "
+ + y, gridColor, drawnPixel);
+ assertEquals("Unexpected y-grid color found at pixel: x: " + x + "y: "
+ + y, gridColor, drawnPixelup1);
+ assertEquals("Unexpected y-grid color found at pixel: x: " + x + "y: "
+ + y, emptyColor, drawnPixelup2);
+ break;
+ case 1: // y2 with 1 pixel width
+ assertEquals("Unexpected y2-grid color found at pixel: x: " + x + "y: "
+ + y, emptyColor, drawnPixeldown1);
+ assertEquals("Unexpected y2-grid color found at pixel: x: " + x + "y: "
+ + y, gridColor, drawnPixel);
+ assertEquals("Unexpected y2-grid color found at pixel: x: " + x + "y: "
+ + y, emptyColor, drawnPixelup1);
+ break;
+ }
+ }
+ }
+
+ // Check the x axis grid
+ y = halfDown(g.plotter_.area.y) + 10;
+ for ( var i = 0; i < xGridlines.length; i++) {
+ x = halfUp(g.toDomXCoord(xGridlines[i]));
+ assertEquals("Unexpected x-grid color found at pixel: x: " + x + "y: " + y,
+ emptyColor, Util.samplePixel(g.hidden_, x - 4, y).slice(0, 3));
+ assertEquals("Unexpected x-grid color found at pixel: x: " + x + "y: " + y,
+ gridColor, Util.samplePixel(g.hidden_, x - 3, y).slice(0, 3));
+ assertEquals("Unexpected x-grid color found at pixel: x: " + x + "y: " + y,
+ gridColor, Util.samplePixel(g.hidden_, x - 2, y).slice(0, 3));
+ assertEquals("Unexpected x-grid color found at pixel: x: " + x + "y: " + y,
+ gridColor, Util.samplePixel(g.hidden_, x - 1, y).slice(0, 3));
+ assertEquals("Unexpected x-grid color found at pixel: x: " + x + "y: " + y,
+ gridColor, Util.samplePixel(g.hidden_, x, y).slice(0, 3));
+ assertEquals("Unexpected x-grid color found at pixel: x: " + x + "y: " + y,
+ gridColor, Util.samplePixel(g.hidden_, x + 1, y).slice(0, 3));
+ assertEquals("Unexpected x-grid color found at pixel: x: " + x + "y: " + y,
+ emptyColor, Util.samplePixel(g.hidden_, x + 2, y).slice(0, 3));
+ }
+};
+GridPerAxisTestCase.prototype.testGridLinePattern = function() {
+ var opts = {
+ width : 480,
+ height : 320,
+ errorBars : false,
+ drawXGrid : false,
+ drawXAxis : false,
+ drawYAxis : false,
+ labels : [ "X", "Left", "Right" ],
+ colors : [ "rgba(0,0,0,0)", "rgba(0,0,0,0)" ],
+ series : {
+ Left : {
+ axis : "y"
+ },
+ Right : {
+ axis : "y2"
+ }
+ },
+ axes : {
+ y : {
+ gridLineColor : "#0000ff",
+ gridLinePattern : [ 10, 10 ]
+ }
+ }
+ };
+ var data = [ [ 1, 0, 0 ], [ 2, 12, 88 ], [ 3, 88, 122 ], [ 4, 63, 273 ],
+ [ 5, 110, 333 ] ];
+ var graph = document.getElementById("graph");
+ var g = new Dygraph(graph, data, opts);
+ htx = g.hidden_ctx_;
+
+ // The expected gridlines
+ var yGridlines = [ 0, 20, 40, 60, 80, 100, 120 ];
+
+ function halfUp(x) {
+ return Math.round(x) + 1;
+ }
+ function halfDown(y) {
+ return Math.round(y) - 1;
+ }
+ var x, y;
+ // Step through all gridlines of the axis
+ for ( var i = 0; i < yGridlines.length; i++) {
+ y = halfDown(g.toDomYCoord(yGridlines[i], 0));
+ // Step through the pixels of the line and test the pattern.
+ for (x = halfUp(g.plotter_.area.x); x < g.plotter_.area.w; x++) {
+ // avoid checking the edge pixels since they differ depending on the OS.
+ var pixelpos = x % 10;
+ if(pixelpos < 1 || pixelpos > 8) continue;
+
+ // Ignore alpha
+ var drawnPixel = Util.samplePixel(g.hidden_, x, y).slice(0,3);
+ var pattern = (Math.floor((x) / 10)) % 2;
+ switch (pattern) {
+ case 0: // fill
+ assertEquals("Unexpected filled grid-pattern color found at pixel: x: " + x + "y: "
+ + y, [ 0, 0, 255 ], drawnPixel);
+ break;
+ case 1: // no fill
+ assertEquals("Unexpected empty grid-pattern color found at pixel: x: " + x + "y: "
+ + y, [ 0, 0, 0 ], drawnPixel);
+ break;
+ }
+ }
+ }
+};
pixelsPerLabel: 60,
axisLabelFormatter: Dygraph.dateAxisFormatter,
valueFormatter: Dygraph.dateString_,
+ drawGrid: true,
+ independentTicks: true,
ticker: null // will be set in dygraph-tickers.js
},
y: {
pixelsPerLabel: 30,
valueFormatter: Dygraph.numberValueFormatter,
axisLabelFormatter: Dygraph.numberAxisLabelFormatter,
+ drawGrid: true,
+ independentTicks: true,
ticker: null // will be set in dygraph-tickers.js
},
y2: {
pixelsPerLabel: 30,
valueFormatter: Dygraph.numberValueFormatter,
axisLabelFormatter: Dygraph.numberAxisLabelFormatter,
+ drawGrid: false,
+ independentTicks: false,
ticker: null // will be set in dygraph-tickers.js
}
}
};
var numAxes = this.attributes_.numAxes();
var ypadCompat, span, series, ypad;
+
+ var p_axis;
// Compute extreme values, a span and tick marks for each axis.
for (var i = 0; i < numAxes; i++) {
var axis = this.axes_[i];
var logscale = this.attributes_.getForAxis("logscale", i);
var includeZero = this.attributes_.getForAxis("includeZero", i);
+ var independentTicks = this.attributes_.getForAxis("independentTicks", i);
series = this.attributes_.seriesForAxis(i);
// Add some padding. This supports two Y padding operation modes:
} else {
axis.computedValueRange = axis.extremeRange;
}
-
- // 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.
- var opts = this.optionsViewForAxis_('y' + (i ? '2' : ''));
- var ticker = opts('ticker');
- if (i === 0 || axis.independentTicks) {
+
+
+ if(independentTicks) {
+ axis.independentTicks = independentTicks;
+ var opts = this.optionsViewForAxis_('y' + (i ? '2' : ''));
+ var ticker = opts('ticker');
axis.ticks = ticker(axis.computedValueRange[0],
- axis.computedValueRange[1],
- this.height_, // TODO(danvk): should be area.height
- opts,
- this);
- } else {
- var p_axis = this.axes_[0];
+ axis.computedValueRange[1],
+ this.height_, // TODO(danvk): should be area.height
+ opts,
+ this);
+ // Define the first independent axis as primary axis.
+ if (!p_axis) p_axis = axis;
+ }
+ }
+ 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.
+ for (var i = 0; i < numAxes; i++) {
+ var axis = this.axes_[i];
+
+ if (!axis.independentTicks) {
+ var opts = this.optionsViewForAxis_('y' + (i ? '2' : ''));
+ var ticker = opts('ticker');
var p_ticks = p_axis.ticks;
var p_scale = p_axis.computedValueRange[1] - p_axis.computedValueRange[0];
var scale = axis.computedValueRange[1] - axis.computedValueRange[0];
<body>
<h2>Multiple y-axes</h2>
<p>The same data with both one and two y-axes. Two y-axes:</p>
+ <p>Two y-axes with y as primary axis (default):</p>
<div id="demodiv" style="width: 640; height: 350; border: 1px solid black"></div>
- <p>A single y-axis:</p>
+ <p>Two y-axes with y2 as primary axis:</p>
+ <div id="demodiv_y2_primary" style="width: 640; height: 350; border: 1px solid black"></div>
+ <p>Two y-axes using different grids:</p>
+ <div id="demodiv_two_grids" style="width: 640; height: 350; border: 1px solid black"></div>
+ <p>A single y-axis (left):</p>
<div id="demodiv_one" style="width: 640; height: 350; border: 1px solid black"></div>
+ <p>A single y-axis (right):</p>
+ <div id="demodiv_one_right" style="width: 640; height: 350; border: 1px solid black"></div>
<script type="text/javascript">
var data = [];
yAxisLabelWidth: 60
}
);
-
+
g2 = new Dygraph(
- document.getElementById("demodiv_one"),
+ document.getElementById("demodiv_y2_primary"),
data,
{
labels: [ 'Date', 'Y1', 'Y2', 'Y3', 'Y4' ],
- labelsKMB: true,
ylabel: 'Primary y-axis',
- y2label: 'Secondary y-axis'
+ y2label: 'Secondary y-axis',
+ series : {
+ 'Y3': {
+ axis: 'y2'
+ },
+ 'Y4': {
+ axis: 'y2'
+ }
+ },
+ axes: {
+ y: {
+ // set axis-related properties here
+ drawGrid: false,
+ independentTicks: false
+ },
+ y2: {
+ // set axis-related properties here
+ labelsKMB: true,
+ drawGrid: true,
+ independentTicks: true
+ }
+ }
+ }
+ );
+
+ g3 = new Dygraph(
+ document.getElementById("demodiv_two_grids"),
+ data,
+ {
+ labels: [ 'Date', 'Y1', 'Y2', 'Y3', 'Y4' ],
+ ylabel: 'Primary y-axis',
+ y2label: 'Secondary y-axis',
+ series : {
+ 'Y3': {
+ axis: 'y2'
+ },
+ 'Y4': {
+ axis: 'y2'
+ }
+ },
+ axes: {
+ y2: {
+ // set axis-related properties here
+ labelsKMB: true,
+ drawGrid: true,
+ independentTicks: true,
+ gridLinePattern: [2,2]
+ }
+ }
}
);
+ g4 = new Dygraph(
+ document.getElementById("demodiv_one"),
+ data,
+ {
+ labels: [ 'Date', 'Y1', 'Y2', 'Y3', 'Y4' ],
+ labelsKMB: true,
+ ylabel: 'Primary y-axis',
+ y2label: 'Secondary y-axis',
+ }
+ );
+
+ g5 = new Dygraph(
+ document.getElementById("demodiv_one_right"),
+ data,
+ {
+ labels: [ 'Date', 'Y1', 'Y2', 'Y3', 'Y4' ],
+ ylabel: 'Primary y-axis',
+ y2label: 'Secondary y-axis',
+ series : {
+ 'Y1': {
+ axis: 'y2'
+ },
+ 'Y2': {
+ axis: 'y2'
+ },
+ 'Y3': {
+ axis: 'y2'
+ },
+ 'Y4': {
+ axis: 'y2'
+ }
+ },
+ axes: {
+ y: {
+ // set axis-related properties here
+ drawGrid: false,
+ independentTicks: false
+ },
+ y2: {
+ // set axis-related properties here
+ labelsKMB: true,
+ drawGrid: true,
+ independentTicks: true
+ }
+ }
+ }
+ );
+
function update(el) {
g.updateOptions( { fillGraph: el.checked } );
g2.updateOptions( { fillGraph: el.checked } );
+ g3.updateOptions( { fillGraph: el.checked } );
+ g4.updateOptions( { fillGraph: el.checked } );
+ g5.updateOptions( { fillGraph: el.checked } );
}
</script>