diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md
similarity index 80%
rename from CONTRIBUTING.md
rename to .github/CONTRIBUTING.md
index ee72da0ef..80d7cf27a 100644
--- a/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -7,13 +7,13 @@ It also helps if you include the non-compacted version of the JS on your
page. For instance, instead of doing this:
```html
-
+
```
do this:
```html
-
+
```
This makes error messages and debugging simpler. The jsfiddle does this automatically.
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 000000000..3bbac0493
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,20 @@
+Filing a bug report? Please include the following:
+
+1. Link to a page which demonstrates the problem, preferably a jsfiddle (use http://dygraphs.com/fiddle as a template)
+2. Browser and Operating System that exhibit the problem
+3. Version of dygraphs that you're using
+
+It also helps if you include the non-compacted version of the JS on your
+page. For instance, instead of doing this:
+
+```html
+
+```
+
+do this:
+
+```html
+
+```
+
+This makes error messages and debugging simpler. The jsfiddle does this automatically.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 000000000..474eeed5b
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,14 @@
+Please read the guide to making dygraphs changes:
+http://dygraphs.com/changes.html
+
+Pull Requests will only be accepted if:
+
+- You clearly explain what you're adding and why you believe it's an
+ improvement. For example: "Fixes issue #123".
+- You adhere to the style of the rest of the dygraphs code base.
+- You write an `auto_test` for the code that you're adding.
+
+Be sure to document any new options you add. Also be aware that PRs which add
+options are likely to be rejected. dygraphs already has many options. If you
+can fit your feature into one of those or implement it as a plugin, it will be
+more likely to get merged.
diff --git a/.gitignore b/.gitignore
index 121cd6678..1a6f93b9c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,5 @@ env
dist
coverage
*.log
+*.pyc
+src-es5
diff --git a/.travis.yml b/.travis.yml
index 198ce97c2..130ac697a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,6 @@
language: node_js
node_js:
- - "0.10"
+ - "6"
sudo: false # Use container-based architecture
script: >
diff --git a/DEVELOP.md b/DEVELOP.md
index 9a13888c9..6eb43fb19 100644
--- a/DEVELOP.md
+++ b/DEVELOP.md
@@ -6,6 +6,10 @@ This is a step-by-step guide explaining how to do it.
### How-to
+To install dependencies, run
+
+ npm install
+
To build dygraphs, run
npm run build
diff --git a/README.md b/README.md
index 9abb9a1a9..e539994d9 100644
--- a/README.md
+++ b/README.md
@@ -7,24 +7,23 @@ The dygraphs JavaScript library produces interactive, zoomable charts of time se
Learn more about it at [dygraphs.com](http://www.dygraphs.com).
-Get help with dygraphs on
-[Stack Overflow](http://stackoverflow.com/questions/tagged/dygraphs) (preferred) and
-[Google Groups](http://groups.google.com/group/dygraphs-users)
+Get help with dygraphs by browsing the on [Stack Overflow][] (preferred) and [Google Groups][].
## Features
* Plots time series without using an external server or Flash
-* Supports [error bands](http://dygraphs.com/tests/legend-values.html) around data series
-* Interactive [pan and zoom](http://dygraphs.com/tests/link-interaction.html)
-* Displays values [on mouseover](http://dygraphs.com/tests/legend-values.html)
-* Adjustable [averaging period](http://dygraphs.com/tests/temperature-sf-ny.html)
-* Extensive set of [options](http://www.dygraphs.com/options.html) for customization.
-* Compatible with the [Google Visualization API](http://dygraphs.com/data.html#datatable)
+* Supports [error bands][] around data series
+* Interactive [pan and zoom][]
+* Displays values [on mouseover][]
+* Adjustable [averaging period][]
+* Extensive set of [options][] for customization.
+* Compatible with the [Google Visualization API][gviz]
## Minimal Example
```html
-
+
+
@@ -42,9 +41,27 @@ Get help with dygraphs on
```
-Learn more by reading [the tutorial](http://www.dygraphs.com/tutorial.html) and
-seeing demonstrations of what dygraphs can do in the
-[gallery](http://www.dygraphs.com/gallery).
+Learn more by reading [the tutorial][] and seeing demonstrations of what
+dygraphs can do in the [gallery][]. You can get `dygraph.js` and `dygraph.css`
+from [cdnjs][] or [from NPM][npm] (see below).
+
+## Usage with a module loader
+
+Get dygraphs from NPM:
+
+ npm install dygraphs
+
+You'll find pre-built JS & CSS files in `node_modules/dygraphs/dist`. If you're
+using a module bundler like browserify or webpack, you can import dygraphs:
+
+```js
+import Dygraph from 'dygraphs';
+// or: const Dygraph = require('dygraphs');
+
+const g = new Dygraph('graphdiv', data, { /* options */ });
+```
+
+Check out the [dygraphs-es6 repo][] for a fully-worked example.
## Development
@@ -59,3 +76,17 @@ Read more about the dygraphs development process in the [developer guide](/DEVEL
## License(s)
dygraphs is available under the MIT license, included in LICENSE.txt.
+
+[cdnjs]: https://cdnjs.com/libraries/dygraph
+[the tutorial]: http://www.dygraphs.com/tutorial.html
+[gallery]: http://www.dygraphs.com/gallery
+[error bands]: http://dygraphs.com/tests/legend-values.html
+[pan and zoom]: http://dygraphs.com/tests/link-interaction.html
+[on mouseover]: http://dygraphs.com/tests/legend-values.html
+[averaging period]: http://dygraphs.com/tests/temperature-sf-ny.html
+[options]: http://www.dygraphs.com/options.html
+[Stack Overflow]: http://stackoverflow.com/questions/tagged/dygraphs?sort=votes&pageSize=50
+[Google Groups]: http://groups.google.com/group/dygraphs-users
+[gviz]: http://dygraphs.com/data.html#datatable
+[npm]: https://www.npmjs.com/package/dygraphs
+[dygraphs-es6 repo]: https://github.com/danvk/dygraphs-es6
diff --git a/auto_tests/coverage.html b/auto_tests/coverage.html
index 04573478f..adf263998 100644
--- a/auto_tests/coverage.html
+++ b/auto_tests/coverage.html
@@ -3,14 +3,12 @@
dygraphs tests
+
-
-
-
diff --git a/auto_tests/data/out-of-order-dates.csv b/auto_tests/data/out-of-order-dates.csv
new file mode 100644
index 000000000..a05ef062e
--- /dev/null
+++ b/auto_tests/data/out-of-order-dates.csv
@@ -0,0 +1,9 @@
+Date,r17,r82,r83,r9
+2013-10-17T21:00:00Z,,,,9
+2014-05-29T18:00:00Z,,,,9
+2013-10-17T21:00:00Z,17,,,
+2014-05-29T17:00:00Z,17,,,
+2014-05-29T18:00:00Z,,82,,
+2014-05-29T18:00:00Z,,,83,
+2014-10-11T04:00:00Z,,,83,
+2015-05-22T04:00:00Z,,82,,
diff --git a/auto_tests/data/out-of-order.csv b/auto_tests/data/out-of-order.csv
new file mode 100644
index 000000000..51f40a688
--- /dev/null
+++ b/auto_tests/data/out-of-order.csv
@@ -0,0 +1,5 @@
+X,Y1,Y2
+0,0,0
+1,1,1
+3,3,9
+2,2,4
diff --git a/auto_tests/data/sample.csv b/auto_tests/data/sample.csv
new file mode 100644
index 000000000..5bae60ee9
--- /dev/null
+++ b/auto_tests/data/sample.csv
@@ -0,0 +1,5 @@
+X,Y1,Y2
+0,0,0
+1,1,1
+2,2,4
+3,3,9
diff --git a/auto_tests/runner.html b/auto_tests/runner.html
index c3a3d8797..7ceb0d08c 100644
--- a/auto_tests/runner.html
+++ b/auto_tests/runner.html
@@ -3,14 +3,12 @@
dygraphs tests
+
-
-
-
diff --git a/auto_tests/tests/axis_labels.js b/auto_tests/tests/axis_labels.js
index 0af808522..5a631fa13 100644
--- a/auto_tests/tests/axis_labels.js
+++ b/auto_tests/tests/axis_labels.js
@@ -687,6 +687,33 @@ it('testLogScale', function() {
assert.deepEqual(['0','200','400','600','800','1000'], Util.getYLabels());
});
+/**
+ * Verify that log scale axis range works with yRangePad.
+ *
+ * This is a regression test for https://github.com/danvk/dygraphs/issues/661 .
+ */
+it('testLogScalePad', function() {
+ var g = new Dygraph("graph",
+ [[0, 1e-5], [1, 0.25], [2, 1], [3, 3], [4, 10]], {
+ width: 250,
+ height: 130,
+ logscale: true,
+ yRangePad: 30,
+ axes: {y: {valueRange: [1, 10]}},
+ labels: ['X', 'Y']
+ });
+ var nonEmptyLabels = Util.getYLabels().filter(function(x) { return x.length > 0; });
+ assert.deepEqual(['1', '7', '30'], nonEmptyLabels);
+
+ g.updateOptions({ yRangePad: 10, axes: {y: {valueRange: [0.25005, 3]}} });
+ nonEmptyLabels = Util.getYLabels().filter(function(x) { return x.length > 0; });
+ assert.deepEqual(['0.4', '1', '3'], nonEmptyLabels);
+
+ g.updateOptions({ axes: {y: {valueRange: [0.01, 3]}} });
+ nonEmptyLabels = Util.getYLabels().filter(function(x) { return x.length > 0; });
+ assert.deepEqual(['0.01','0.1','0.7','5'], nonEmptyLabels);
+});
+
/**
* Verify that include zero range is properly specified.
*/
@@ -771,75 +798,6 @@ it('testAxisLabelFontSizeNull', function() {
assertFontSize(document.querySelectorAll(".dygraph-axis-label-y"), "14px");
});
-it('testAxisLabelColor', function() {
- var graph = document.getElementById("graph");
- var g = new Dygraph(graph, simpleData, {});
-
- // Be sure we're dealing with a black default.
- assert.equal("black", DEFAULT_ATTRS.axisLabelColor);
-
- var assertColor = function(selector, expected) {
- Util.assertStyleOfChildren(selector, "color", expected);
- }
-
- assertColor(document.querySelectorAll(".dygraph-axis-label-x"), "rgb(0, 0, 0)");
- assertColor(document.querySelectorAll(".dygraph-axis-label-y"), "rgb(0, 0, 0)");
-
- g.updateOptions({ axisLabelColor : "red"});
- assertColor(document.querySelectorAll(".dygraph-axis-label-x"), "rgb(255, 0, 0)");
- assertColor(document.querySelectorAll(".dygraph-axis-label-y"), "rgb(255, 0, 0)");
-
- g.updateOptions({
- axisLabelColor : null,
- axes : {
- x : { axisLabelColor : "blue" },
- }
- });
-
- assertColor(document.querySelectorAll(".dygraph-axis-label-x"), "rgb(0, 0, 255)");
- assertColor(document.querySelectorAll(".dygraph-axis-label-y"), "rgb(0, 0, 0)");
-
- g.updateOptions({
- axes : {
- y : { axisLabelColor : "green" },
- }
- });
-
- assertColor(document.querySelectorAll(".dygraph-axis-label-x"), "rgb(0, 0, 255)");
- assertColor(document.querySelectorAll(".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(document.querySelectorAll(".dygraph-axis-label-x"), "rgb(0, 0, 255)");
- assertColor(document.querySelectorAll(".dygraph-axis-label-y1"), "rgb(0, 128, 0)");
- assertColor(document.querySelectorAll(".dygraph-axis-label-y2"), "rgb(255, 255, 0)");
-});
-
-it('testAxisLabelColorNull', function() {
- var graph = document.getElementById("graph");
- var g = new Dygraph(graph, simpleData,
- {
- axisLabelColor: null
- });
-
- var assertColor = function(selector, expected) {
- Util.assertStyleOfChildren(selector, "color", expected);
- }
-
- // Be sure we're dealing with a 14-point default.
- assert.equal(14, DEFAULT_ATTRS.axisLabelFontSize);
-
- assertColor(document.querySelectorAll(".dygraph-axis-label-x"), "rgb(0, 0, 0)");
- assertColor(document.querySelectorAll(".dygraph-axis-label-y"), "rgb(0, 0, 0)");
-});
-
/*
* This test shows that the label formatter overrides labelsKMB for all values.
*/
diff --git a/auto_tests/tests/data_api.js b/auto_tests/tests/data_api.js
index e692fc61e..631990980 100644
--- a/auto_tests/tests/data_api.js
+++ b/auto_tests/tests/data_api.js
@@ -4,6 +4,7 @@
* @author danvdk@gmail.com (Dan Vanderkam)
*/
import Dygraph from '../../src/dygraph';
+import * as utils from '../../src/dygraph-utils';
describe("data-api", function() {
cleanupAfterEach();
@@ -99,4 +100,21 @@ it('testGetRowForXDuplicates', function() {
assert.equal(5, g.getRowForX(9));
});
+// indexFromSeriesName should return a value even if the series is invisible
+// In 1.1.1, if you request the last set and it's invisible, the method returns undefined.
+it('testIndexFromSetNameOnInvisibleSet', function() {
+
+ var localOpts = utils.clone(opts);
+ localOpts.visibility = [true, false];
+
+ var g = new Dygraph(graphDiv, [
+ "x,y1,y2",
+ "1,1,1",
+ "2,2,2",
+ "3,3,3"
+ ].join('\n'), localOpts);
+
+ assert.equal(2, g.indexFromSetName("y2"));
+});
+
});
diff --git a/auto_tests/tests/data_types.js b/auto_tests/tests/data_types.js
new file mode 100644
index 000000000..023d60864
--- /dev/null
+++ b/auto_tests/tests/data_types.js
@@ -0,0 +1,34 @@
+/**
+ * @fileoverview Test cases for DygraphOptions.
+ */
+
+import Dygraph from '../../src/dygraph';
+
+describe("dygraph-data-types", function() {
+
+ cleanupAfterEach();
+
+ var graph;
+
+ beforeEach(function() {
+ graph = document.getElementById("graph");
+ });
+
+ /*
+ * Test to ensure ints are correctly interpreted as ints and not as dates
+ */
+ it('testNumberOfData', function() {
+ var opts = {
+ width: 480,
+ height: 320
+ };
+ var data = "x y\n" +
+ "20033000 1\n" +
+ "20034000 2\n" +
+ "20035000 3\n" +
+ "20036000 4";
+
+ var g = new Dygraph(graph, data, opts);
+ assert.deepEqual(4, g.rawData_.length);
+ });
+});
diff --git a/auto_tests/tests/date_formats.js b/auto_tests/tests/date_formats.js
index f157b8dd4..5148fe7fb 100644
--- a/auto_tests/tests/date_formats.js
+++ b/auto_tests/tests/date_formats.js
@@ -36,4 +36,12 @@ it('testHyphenatedDate', function() {
assert.equal(Date.UTC(2000, 1, 2), utils.dateParser(str));
});
+it('testMillisecondsDate', function() {
+ // Format: YYYY-MM-DD HH:MM:SS.MS
+
+ // Midnight February 2, 2000 14:25:42.123 UTC
+ var ts = Date.UTC(2000, 1, 2, 14, 25, 42, 123);
+ assert.equal("2000/02/02 14:25:42.123", utils.dateString_(ts, true));
+});
+
});
diff --git a/auto_tests/tests/date_ticker.js b/auto_tests/tests/date_ticker.js
index c02331dc7..fc18733ed 100644
--- a/auto_tests/tests/date_ticker.js
+++ b/auto_tests/tests/date_ticker.js
@@ -263,6 +263,19 @@ it('testAllDateTickers', function() {
assert.deepEqual([{"v":1307908020000,"label":"19:47"},{"v":1307908050000,"label":"19:47:30"},{"v":1307908080000,"label":"19:48"},{"v":1307908110000,"label":"19:48:30"},{"v":1307908140000,"label":"19:49"},{"v":1307908170000,"label":"19:49:30"}], ticker(1307908000112, 1307908172259, 800, options));
assert.deepEqual([{"v":1307908020000,"label":"19:47"},{"v":1307908050000,"label":"19:47:30"},{"v":1307908080000,"label":"19:48"},{"v":1307908110000,"label":"19:48:30"},{"v":1307908140000,"label":"19:49"},{"v":1307908170000,"label":"19:49:30"}], ticker(1307908000112, 1307908173260, 800, options));
assert.deepEqual([{"v":978307200000,"label":"Jan 2001"},{"v":986083200000,"label":"Apr 2001"},{"v":993945600000,"label":"Jul 2001"},{"v":1001894400000,"label":"Oct 2001"}], ticker(978307200000, 1001894400000, 400, options));
+
+ assert.deepEqual([{"v":1307908000110,"label":"40.110"},{"v":1307908000111,"label":"40.111"},{"v":1307908000112,"label":"40.112"},{"v":1307908000113,"label":"40.113"}], ticker(1307908000110, 1307908000113, 200, options));
+ assert.deepEqual([{"v":1307908000110,"label":"40.110"},{"v":1307908000112,"label":"40.112"},{"v":1307908000114,"label":"40.114"},{"v":1307908000116,"label":"40.116"}], ticker(1307908000110, 1307908000116, 200, options));
+ assert.deepEqual([{"v":1307908000110,"label":"40.110"},{"v":1307908000115,"label":"40.115"},{"v":1307908000120,"label":"40.120"},{"v":1307908000125,"label":"40.125"}], ticker(1307908000110, 1307908000125, 200, options));
+ assert.deepEqual([{"v":1307908000110,"label":"40.110"},{"v":1307908000120,"label":"40.120"},{"v":1307908000130,"label":"40.130"},{"v":1307908000140,"label":"40.140"}], ticker(1307908000110, 1307908000140, 200, options));
+
+ assert.deepEqual([{"v":1307908000100,"label":"40.100"},{"v":1307908000150,"label":"40.150"},{"v":1307908000200,"label":"40.200"},{"v":1307908000250,"label":"40.250"}], ticker(1307908000100, 1307908000250, 200, options));
+ assert.deepEqual([{"v":1307908000100,"label":"40.100"},{"v":1307908000150,"label":"40.150"},{"v":1307908000200,"label":"40.200"},{"v":1307908000250,"label":"40.250"}], ticker(1307908000090, 1307908000260, 200, options));
+
+ assert.deepEqual([{"v":1307908000100,"label":"40.100"},{"v":1307908000200,"label":"40.200"},{"v":1307908000300,"label":"40.300"},{"v":1307908000400,"label":"40.400"}], ticker(1307908000100, 1307908000400, 200, options));
+ assert.deepEqual([{"v":1307908000100,"label":"40.100"},{"v":1307908000200,"label":"40.200"},{"v":1307908000300,"label":"40.300"},{"v":1307908000400,"label":"40.400"}], ticker(1307908000100, 1307908000410, 200, options));
+
+ assert.deepEqual([{"v":1307908000000,"label":"40.000"},{"v":1307908000500,"label":"40.500"},{"v":1307908001000,"label":"41.000"},{"v":1307908001500,"label":"41.500"}], ticker(1307908000000, 1307908001500, 200, options));
});
});
diff --git a/auto_tests/tests/draw_gap_edge_points.js b/auto_tests/tests/draw_gap_edge_points.js
new file mode 100644
index 000000000..3d92b0f32
--- /dev/null
+++ b/auto_tests/tests/draw_gap_edge_points.js
@@ -0,0 +1,47 @@
+/**
+ * @fileoverview Test cases for the option "drawGapEdgePoints"
+ */
+
+import Dygraph from '../../src/dygraph';
+import * as utils from '../../src/dygraph-utils';
+
+describe("draw-gap-edge-points", function() {
+
+ cleanupAfterEach();
+
+ it("shouldn't draw any points by default", function() {
+ var called = false;
+ var g = new Dygraph(document.getElementById("graph"),
+ [[0, 0],
+ [1, 1],
+ [2, 2],
+ [3, 3],
+ [4, 4],
+ [5, 5]],
+ {labels: ['a', 'b'],
+ drawGapEdgePoints: true,
+ drawPointCallback: function() { called = true; }});
+
+ assert.isFalse(called);
+ });
+
+ it("shouldn't draw any points by default (no axes)", function() {
+ var called = false;
+ var g = new Dygraph(document.getElementById("graph"),
+ [[0, 0],
+ [1, 1],
+ [2, 2],
+ [3, 3],
+ [4, 4],
+ [5, 5]],
+ {labels: ['a', 'b'],
+ drawGapEdgePoints: true,
+ drawPointCallback: function() { called = true; },
+ axes: {
+ x: { drawAxis: false },
+ y: { drawAxis: false }
+ }});
+
+ assert.isFalse(called);
+ });
+});
diff --git a/auto_tests/tests/formats.js b/auto_tests/tests/formats.js
index f16cc6d88..2548d99fd 100644
--- a/auto_tests/tests/formats.js
+++ b/auto_tests/tests/formats.js
@@ -77,6 +77,16 @@ it('testXValueParser', function() {
assert.equal(6, g.getValue(3, 0));
});
+it('should throw on strings in native format', () => {
+ assert.throws(() => {
+ new Dygraph('graph', [['1', '10'], ['2', '20']])
+ }, /expected number or date/i);
+
+ assert.throws(() => {
+ new Dygraph('graph', [[new Date(), '10'], [new Date(), '20']])
+ }, /expected number or array/i);
+});
+
var assertData = function(g) {
var expected = dataArray;
diff --git a/auto_tests/tests/hidpi.js b/auto_tests/tests/hidpi.js
index 1dd131c7b..ceb3a49dc 100644
--- a/auto_tests/tests/hidpi.js
+++ b/auto_tests/tests/hidpi.js
@@ -45,5 +45,36 @@ it('testDoesntCreateScrollbars', function() {
assert.equal(sw, document.body.scrollWidth);
});
+it('should be influenced by options.pixelRatio', function () {
+ var graph = document.getElementById("graph");
+
+ // make sure devicePixelRatio is still setup to not 1.
+ assert(devicePixelRatio > 1.5, 'devicePixelRatio is not much greater than 1.');
+
+ var data = "X,Y\n" +
+ "0,-1\n" +
+ "1,0\n" +
+ "2,1\n" +
+ "3,0\n";
+
+ // first try a default one
+ var g1 = new Dygraph(graph, data, {});
+ var area1 = g1.getArea();
+
+ var g2 = new Dygraph(graph, data, { pixelRatio: 1 });
+ var area2 = g2.getArea();
+
+ var g3 = new Dygraph(graph, data, { pixelRatio: 3 });
+ var area3 = g3.getArea();
+
+ assert.deepEqual(area1, area2, 'areas 1 and 2 are not the same');
+ assert.deepEqual(area2, area3, 'areas 2 and 3 are not the same');
+
+ assert.notEqual(g1.canvas_.width, g2.canvas_.width,
+ 'Expected, for devicePixelRatio != 1, '
+ + 'that setting options.pixelRatio would change the canvas width');
+ assert.equal(g2.canvas_.width * 3, g3.canvas_.width,
+ 'Expected that pixelRatio of 3 vs 1 would triple the canvas width.');
+});
});
diff --git a/auto_tests/tests/interaction_model.js b/auto_tests/tests/interaction_model.js
index a846df5cf..2015e111f 100644
--- a/auto_tests/tests/interaction_model.js
+++ b/auto_tests/tests/interaction_model.js
@@ -1,4 +1,4 @@
-/**
+/**
* @fileoverview Test cases for the interaction model.
*
* @author konigsberg@google.com (Robert Konigsbrg)
@@ -344,7 +344,7 @@ it('testCorrectAxisValueRangeAfterUnzoom', function() {
dateWindow: [1, 9],
animatedZooms:false
});
-
+
// Zoom x axis
DygraphOps.dispatchMouseDown_Point(g, 100, 100);
DygraphOps.dispatchMouseMove_Point(g, 130, 100);
@@ -356,13 +356,13 @@ it('testCorrectAxisValueRangeAfterUnzoom', function() {
DygraphOps.dispatchMouseUp_Point(g, 100, 130);
var currentYAxisRange = g.yAxisRange();
var currentXAxisRange = g.xAxisRange();
-
+
//check that the range for the axis has changed
assert.notEqual(1, currentXAxisRange[0]);
assert.notEqual(10, currentXAxisRange[1]);
assert.notEqual(1, currentYAxisRange[0]);
assert.notEqual(50, currentYAxisRange[1]);
-
+
// unzoom by doubleclick. This is really the order in which a browser
// generates events, and we depend on it.
DygraphOps.dispatchMouseDown_Point(g, 10, 10);
@@ -370,13 +370,10 @@ it('testCorrectAxisValueRangeAfterUnzoom', function() {
DygraphOps.dispatchMouseDown_Point(g, 10, 10);
DygraphOps.dispatchMouseUp_Point(g, 10, 10);
DygraphOps.dispatchDoubleClick(g, null);
-
- // check if range for y-axis was reset to original value
- // TODO check if range for x-axis is correct.
- // Currently not possible because dateRange is set to null and extremes are returned
- var newYAxisRange = g.yAxisRange();
- assert.equal(1, newYAxisRange[0]);
- assert.equal(50, newYAxisRange[1]);
+
+ // check if the range for both axis was reset to show the full data.
+ assert.deepEqual(g.yAxisExtremes()[0], g.yAxisRange());
+ assert.deepEqual(g.xAxisExtremes(), g.xAxisRange());
});
/**
@@ -468,8 +465,9 @@ it('testCorrectAxisPaddingAfterUnzoom', function() {
animatedZooms:false
});
- var extremes = g.xAxisExtremes();
-
+ var xExtremes = g.xAxisExtremes();
+ var [ yExtremes ] = g.yAxisExtremes();
+
// Zoom x axis
DygraphOps.dispatchMouseDown_Point(g, 100, 100);
DygraphOps.dispatchMouseMove_Point(g, 130, 100);
@@ -479,15 +477,11 @@ it('testCorrectAxisPaddingAfterUnzoom', function() {
DygraphOps.dispatchMouseDown_Point(g, 100, 100);
DygraphOps.dispatchMouseMove_Point(g, 100, 130);
DygraphOps.dispatchMouseUp_Point(g, 100, 130);
- var currentYAxisRange = g.yAxisRange();
- var currentXAxisRange = g.xAxisRange();
-
+
//check that the range for the axis has changed
- assert.notEqual(1, currentXAxisRange[0]);
- assert.notEqual(10, currentXAxisRange[1]);
- assert.notEqual(1, currentYAxisRange[0]);
- assert.notEqual(50, currentYAxisRange[1]);
-
+ assert.notDeepEqual([1, 10], g.xAxisRange());
+ assert.notDeepEqual([1, 50], g.yAxisRange());
+
// unzoom by doubleclick. This is really the order in which a browser
// generates events, and we depend on it.
DygraphOps.dispatchMouseDown_Point(g, 10, 10);
@@ -495,11 +489,10 @@ it('testCorrectAxisPaddingAfterUnzoom', function() {
DygraphOps.dispatchMouseDown_Point(g, 10, 10);
DygraphOps.dispatchMouseUp_Point(g, 10, 10);
DygraphOps.dispatchDoubleClick(g, null);
-
- // check if range for x-axis was reset to original value
- var newXAxisRange = g.xAxisRange();
- assert.equal(extremes[0], newXAxisRange[0]);
- assert.equal(extremes[1], newXAxisRange[1]);
+
+ // check if range for x-axis was reset to original value.
+ assert.deepEqual(xExtremes, g.xAxisRange());
+ assert.deepEqual(yExtremes, g.yAxisRange());
});
});
diff --git a/auto_tests/tests/pathological_cases.js b/auto_tests/tests/pathological_cases.js
index 0bcab0b79..326fefb71 100644
--- a/auto_tests/tests/pathological_cases.js
+++ b/auto_tests/tests/pathological_cases.js
@@ -70,10 +70,6 @@ it('testCombinations', function() {
var variantOpts = {
none: {},
- avoidMinZero: {
- avoidMinZero: true,
- includeZero: true
- },
padded: {
includeZero: true,
drawAxesAtZero: true,
@@ -90,7 +86,6 @@ it('testCombinations', function() {
var opts = {
width: 300,
height: 150,
- labelsDivWidth: 100,
pointSize: 10
};
for (var key in base) {
diff --git a/auto_tests/tests/plugins_legend.js b/auto_tests/tests/plugins_legend.js
index 5f6759159..e2ee4f105 100644
--- a/auto_tests/tests/plugins_legend.js
+++ b/auto_tests/tests/plugins_legend.js
@@ -113,6 +113,18 @@ it('should use a legendFormatter', function() {
assert.equal(calls[2].series[0].y, undefined);
});
+it('should work with highlight series', () => {
+ var calls = [];
+ var g = new Dygraph(graph, 'X,y1,y2\n1,2,3\n', {
+ highlightSeriesOpts: {
+ strokeWidth: 3,
+ }
+ });
+
+ g.setSelection(false, 'y2');
+ assert.equal(Util.getLegend(graph), '');
+});
+
it('should include point drawn where canvas-y is 0', function () {
var graph = document.getElementById("graph");
var calls = []
diff --git a/auto_tests/tests/range_selector.js b/auto_tests/tests/range_selector.js
index 82884c835..1bba35361 100644
--- a/auto_tests/tests/range_selector.js
+++ b/auto_tests/tests/range_selector.js
@@ -630,6 +630,73 @@ it('testTwoCombinedSeriesCustomBars', function() {
}, combinedSeries);
});
+it('testHiddenSeriesExcludedFromMiniplot', function() {
+ var opts = {
+ showRangeSelector: true,
+ labels: ['X', 'Y1', 'Y2'],
+ visibility: [true, false]
+ };
+ var data = [
+ [0, 1, 3], // average = 2
+ [5, 4, 6], // average = 5
+ [10, 7, 9] // average = 8
+ ];
+ var graph = document.getElementById("graph");
+ var g = new Dygraph(graph, data, opts);
+
+ var rangeSelector = g.getPluginInstance_(RangeSelectorPlugin);
+ assert.isNotNull(rangeSelector);
+
+ // Invisible series (e.g. Y2) are not included in the combined series.
+ var combinedSeries = rangeSelector.computeCombinedSeriesAndLimits_();
+ assert.deepEqual({
+ yMin: 1 - 6 * 0.25, // 25% padding on single series range.
+ yMax: 7 + 6 * 0.25,
+ data: [
+ [0, 1],
+ [5, 4],
+ [10, 7]
+ ]
+ }, combinedSeries);
+
+ // If Y2 is explicitly marked to be included in the range selector,
+ // then it will be (even if it's not visible). Since we've started being
+ // explicit about marking series for inclusion, this means that Y1 is no
+ // longer included.
+ g.updateOptions({
+ series: {
+ Y2: { showInRangeSelector: true },
+ }
+ });
+ combinedSeries = rangeSelector.computeCombinedSeriesAndLimits_();
+ assert.deepEqual({
+ yMin: 3 - 6 * 0.25, // 25% padding on combined series range.
+ yMax: 9 + 6 * 0.25,
+ data: [
+ [0, 3],
+ [5, 6],
+ [10, 9]
+ ]
+ }, combinedSeries);
+
+ // If we explicitly mark Y1, too, then it also gets included.
+ g.updateOptions({
+ series: {
+ Y1: { showInRangeSelector: true },
+ Y2: { showInRangeSelector: true },
+ }
+ });
+ combinedSeries = rangeSelector.computeCombinedSeriesAndLimits_();
+ assert.deepEqual({
+ yMin: 2 - 6 * 0.25, // 25% padding on combined series range.
+ yMax: 8 + 6 * 0.25,
+ data: [
+ [0, 2],
+ [5, 5],
+ [10, 8]
+ ]
+ }, combinedSeries);
+});
var assertGraphExistence = function(g, graph) {
assert.isNotNull(g);
diff --git a/auto_tests/tests/range_tests.js b/auto_tests/tests/range_tests.js
index 353edcce7..7a952d175 100644
--- a/auto_tests/tests/range_tests.js
+++ b/auto_tests/tests/range_tests.js
@@ -252,15 +252,6 @@ it('testHugeRange', function() {
assert.closeTo(1, 1.1e230 / g.yAxisRange(0)[1], 0.001);
});
-/**
- * Verify old-style avoidMinZero option.
- */
-it('testAvoidMinZero', function() {
- var g = createGraph({
- avoidMinZero: true,
- }, ZERO_TO_FIFTY_STEPS, [10, 20], [-5, 55]);
-});
-
/**
* Verify ranges with user-specified padding, implicit avoidMinZero.
*/
@@ -342,24 +333,7 @@ it('testLogscalePad', function() {
yRangePad: 30
},
[[-10, 10], [10, 10], [30, 1000]],
- [-10, 30], [5.01691, 1993.25801]);
-});
-
-/**
- * Verify scrolling all-zero region, traditional.
- */
-it('testZeroScroll', function() {
- var g = new Dygraph(
- document.getElementById("graph"),
- "X,Y\n" +
- "1,0\n" +
- "8,0\n" +
- "9,0.1\n",
- {
- drawAxesAtZero: true,
- animatedZooms: true,
- avoidMinZero: true
- });
+ [-10, 30], [5.623, 1778.279]);
});
/**
diff --git a/auto_tests/tests/to_dom_coords.js b/auto_tests/tests/to_dom_coords.js
index 454050115..e5bda3b19 100644
--- a/auto_tests/tests/to_dom_coords.js
+++ b/auto_tests/tests/to_dom_coords.js
@@ -225,6 +225,20 @@ it('testChartLogarithmic_YAxis', function() {
assert.deepEqual([400, 0], g.toDomCoords(10, 4));
assert.deepEqual([400, 400], g.toDomCoords(10, 1));
assert.deepEqual([400, 200], g.toDomCoords(10, 2));
+
+ // Verify that the margins are adjusted appropriately for yRangePad.
+ g.updateOptions({yRangePad: 40});
+ assertDeepCloseTo([0, 4], g.toDataCoords(0, 40), epsilon);
+ assertDeepCloseTo([0, 1], g.toDataCoords(0, 360), epsilon);
+ assertDeepCloseTo([10, 4], g.toDataCoords(400, 40), epsilon);
+ assertDeepCloseTo([10, 1], g.toDataCoords(400, 360), epsilon);
+ assertDeepCloseTo([10, 2], g.toDataCoords(400, 200), epsilon);
+
+ assertDeepCloseTo([0, 40], g.toDomCoords(0, 4), epsilon);
+ assertDeepCloseTo([0, 360], g.toDomCoords(0, 1), epsilon);
+ assertDeepCloseTo([400, 40], g.toDomCoords(10, 4), epsilon);
+ assertDeepCloseTo([400, 360], g.toDomCoords(10, 1), epsilon);
+ assertDeepCloseTo([400, 200], g.toDomCoords(10, 2), epsilon);
});
it('testChartLogarithmic_XAxis', function() {
diff --git a/auto_tests/tests/xhr.js b/auto_tests/tests/xhr.js
new file mode 100644
index 000000000..ba06e61a7
--- /dev/null
+++ b/auto_tests/tests/xhr.js
@@ -0,0 +1,68 @@
+/**
+ * @fileoverview Tests involving issuing XHRs for data.
+ *
+ * Note that these tests must be run with an HTTP server.
+ * XHRs can't be issued from file:/// URLs.
+ * This can be done with
+ *
+ * npm install http-server
+ * http-server
+ * open http://localhost:8080/auto_tests/runner.html
+ *
+ */
+
+import Dygraph from '../../src/dygraph';
+import Util from './Util';
+
+import 'core-js/es6/promise';
+
+function dygraphPromise(div, data, opts) {
+ return new Promise((resolve, reject) => {
+ const g = new Dygraph(div, data, opts);
+ g.ready(() => resolve(g));
+ });
+}
+
+describe("xhr", () => {
+
+it('should issue XHRs for CSV data', () => {
+ return dygraphPromise('graph', 'data/sample.csv').then(g => {
+ assert.isNotNull(g);
+ assert.equal(g.numRows(), 4);
+ assert.equal(g.numColumns(), 3);
+ });
+});
+
+it('should warn on out-of-order CSV data', () => {
+ const calls = {};
+ const restore = Util.captureConsole(calls);
+ return dygraphPromise('graph', 'data/out-of-order.csv').then(g => {
+ restore();
+ assert.isNotNull(g);
+ assert.equal(g.numRows(), 4);
+ assert.equal(g.numColumns(), 3);
+ assert.equal(calls.warn.length, 1);
+ assert(/out of order/.exec(calls.warn[0]));
+ }, e => {
+ restore();
+ return Promise.reject(e);
+ });
+});
+
+it('should warn on out-of-order CSV data with dates', () => {
+ const calls = {};
+ const restore = Util.captureConsole(calls);
+ return dygraphPromise('graph', 'data/out-of-order-dates.csv').then(g => {
+ restore();
+ assert.isNotNull(g);
+ assert.equal(g.numRows(), 8);
+ assert.equal(g.numColumns(), 5);
+ assert.equal(calls.warn.length, 1);
+ assert(/out of order/.exec(calls.warn[0]));
+ }, e => {
+ restore();
+ return Promise.reject(e);
+ });
+});
+
+});
diff --git a/bower.json b/bower.json
deleted file mode 100644
index 6ebcc5cda..000000000
--- a/bower.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "name": "dygraphs",
- "main": "dist/dygraph.js",
- "ignore": [
- "Makefile",
- "NOTES",
- "auto_tests",
- "common",
- "data.js",
- "docs",
- "experimental",
- "file-size-stats.sh",
- "gadget.xml",
- "gallery",
- "generate-combined.sh",
- "generate-documentation.py",
- "generate-download.py",
- "generate-jar.sh",
- "generate-jsdoc.sh",
- "gwt",
- "jsTestDriver.conf",
- "jsdoc-toolkit",
- "lint.sh",
- "node_modules",
- "package.json",
- "phantom-driver.js",
- "phantom-perf.js",
- "push-to-web.sh",
- "release.sh",
- "releases.json",
- "screenshot.png",
- "scripts",
- "test.sh",
- "tests",
- "thumbnail.png"
- ]
-}
diff --git a/css/dygraph.css b/css/dygraph.css
new file mode 100644
index 000000000..75d58685f
--- /dev/null
+++ b/css/dygraph.css
@@ -0,0 +1,117 @@
+/**
+ * Default styles for the dygraphs charting library.
+ */
+
+.dygraph-legend {
+ position: absolute;
+ font-size: 14px;
+ z-index: 10;
+ width: 250px; /* labelsDivWidth */
+ /*
+ dygraphs determines these based on the presence of chart labels.
+ It might make more sense to create a wrapper div around the chart proper.
+ top: 0px;
+ right: 2px;
+ */
+ background: white;
+ line-height: normal;
+ text-align: left;
+ overflow: hidden;
+}
+
+/* styles for a solid line in the legend */
+.dygraph-legend-line {
+ display: inline-block;
+ position: relative;
+ bottom: .5ex;
+ padding-left: 1em;
+ height: 1px;
+ border-bottom-width: 2px;
+ border-bottom-style: solid;
+ /* border-bottom-color is set based on the series color */
+}
+
+/* styles for a dashed line in the legend, e.g. when strokePattern is set */
+.dygraph-legend-dash {
+ display: inline-block;
+ position: relative;
+ bottom: .5ex;
+ height: 1px;
+ border-bottom-width: 2px;
+ border-bottom-style: solid;
+ /* border-bottom-color is set based on the series color */
+ /* margin-right is set based on the stroke pattern */
+ /* padding-left is set based on the stroke pattern */
+}
+
+.dygraph-roller {
+ position: absolute;
+ z-index: 10;
+}
+
+/* This class is shared by all annotations, including those with icons */
+.dygraph-annotation {
+ position: absolute;
+ z-index: 10;
+ overflow: hidden;
+}
+
+/* This class only applies to annotations without icons */
+/* Old class name: .dygraphDefaultAnnotation */
+.dygraph-default-annotation {
+ border: 1px solid black;
+ background-color: white;
+ text-align: center;
+}
+
+.dygraph-axis-label {
+ /* position: absolute; */
+ /* font-size: 14px; */
+ z-index: 10;
+ line-height: normal;
+ overflow: hidden;
+ color: black; /* replaces old axisLabelColor option */
+}
+
+.dygraph-axis-label-x {
+}
+
+.dygraph-axis-label-y {
+}
+
+.dygraph-axis-label-y2 {
+}
+
+.dygraph-title {
+ font-weight: bold;
+ z-index: 10;
+ text-align: center;
+ /* font-size: based on titleHeight option */
+}
+
+.dygraph-xlabel {
+ text-align: center;
+ /* font-size: based on xLabelHeight option */
+}
+
+/* For y-axis label */
+.dygraph-label-rotate-left {
+ text-align: center;
+ /* See http://caniuse.com/#feat=transforms2d */
+ transform: rotate(90deg);
+ -webkit-transform: rotate(90deg);
+ -moz-transform: rotate(90deg);
+ -o-transform: rotate(90deg);
+ -ms-transform: rotate(90deg);
+}
+
+/* For y2-axis label */
+.dygraph-label-rotate-right {
+ text-align: center;
+ /* See http://caniuse.com/#feat=transforms2d */
+ transform: rotate(-90deg);
+ -webkit-transform: rotate(-90deg);
+ -moz-transform: rotate(-90deg);
+ -o-transform: rotate(-90deg);
+ -ms-transform: rotate(-90deg);
+}
diff --git a/docs/annotations.html b/docs/annotations.html
index 0a3ba17c4..7a0c1e3ad 100644
--- a/docs/annotations.html
+++ b/docs/annotations.html
@@ -6,6 +6,9 @@
.annotation {
font-size: 12px !important;
}
+ .dygraph-legend {
+ width: 300px;
+ }
+ Ghanastocks.net
+
+ Ghanastocks.net is a financial platform offering information on the stocks traded on the Ghana Stock Exchange.
+ Dygraphs is used to display the stock charts. On the front page a tiny preview graph with no interaction model and
+ labels is used, the quote pages uses a standard version of dygraphs and the detailed chart is displayed using two
+ dygraphs instances, one for the volume bars and one for the chart, which are synchronized through a custom highlight
+ callback.
+
+
+
Are you using dygraphs? Please let Dan know and he'll add your link here!