From: Dan Vanderkam Date: Sat, 31 Mar 2012 21:45:08 +0000 (-0400) Subject: Merge branch 'master' of github.com:danvk/dygraphs X-Git-Tag: v1.0.0~295 X-Git-Url: https://adrianiainlam.tk/git/?a=commitdiff_plain;h=e6b0b7c295a1c3838817744e4548c52bbbdf051f;hp=86a3e64f8f73d854b3b4ac35f52b54bfda3056a4;p=dygraphs.git Merge branch 'master' of github.com:danvk/dygraphs --- diff --git a/auto_tests/tests/annotations.js b/auto_tests/tests/annotations.js index 939c83f..857dd60 100644 --- a/auto_tests/tests/annotations.js +++ b/auto_tests/tests/annotations.js @@ -3,16 +3,16 @@ * * @author danvk@google.com (Dan Vanderkam) */ -var annotationsTestCase = TestCase("annotations"); +var AnnotationsTestCase = TestCase("annotations"); -annotationsTestCase.prototype.setUp = function() { +AnnotationsTestCase.prototype.setUp = function() { document.body.innerHTML = "
"; }; -annotationsTestCase.prototype.tearDown = function() { +AnnotationsTestCase.prototype.tearDown = function() { }; -annotationsTestCase.prototype.testAnnotationsDrawn = function() { +AnnotationsTestCase.prototype.testAnnotationsDrawn = function() { var opts = { width: 480, height: 320 @@ -59,7 +59,7 @@ annotationsTestCase.prototype.testAnnotationsDrawn = function() { // 1. Invalid series name (e.g. 'X' or 'non-existent') // 2. Passing a string as 'x' instead of a number (e.g. x: '1') -annotationsTestCase.prototype.testAnnotationsDontDisappearOnResize = function() { +AnnotationsTestCase.prototype.testAnnotationsDontDisappearOnResize = function() { var opts = { }; var data = "X,Y\n" + @@ -98,7 +98,7 @@ annotationsTestCase.prototype.testAnnotationsDontDisappearOnResize = function() }; // Verify that annotations outside of the visible x-range are not shown. -annotationsTestCase.prototype.testAnnotationsOutOfRangeX = function() { +AnnotationsTestCase.prototype.testAnnotationsOutOfRangeX = function() { var opts = { }; var data = "X,Y\n" + @@ -141,7 +141,7 @@ annotationsTestCase.prototype.testAnnotationsOutOfRangeX = function() { }; // Verify that annotations outside of the visible y-range are not shown. -annotationsTestCase.prototype.testAnnotationsOutOfRangeY = function() { +AnnotationsTestCase.prototype.testAnnotationsOutOfRangeY = function() { var opts = { }; var data = "X,Y\n" + @@ -175,3 +175,33 @@ annotationsTestCase.prototype.testAnnotationsOutOfRangeY = function() { a1 = document.getElementsByClassName('ann1'); assertEquals(1, a1.length); }; + +AnnotationsTestCase.prototype.testAnnotationsDrawnInDrawCallback = function() { + var data = "X,Y\n" + + "0,-1\n" + + "1,0\n" + + "2,1\n"; + + var graph = document.getElementById("graph"); + + var calls = []; + var g = new Dygraph(graph, data, { + width: 480, + height: 320, + drawCallback: function(g, initial) { + calls.push(initial); + if (initial) { + g.setAnnotations([ + { + series: 'Y', + x: 1, + shortText: 'A', + text: 'Long A', + }, + ]); + } + } + }); + + assertEquals([true, false], calls); +}; diff --git a/auto_tests/tests/callback.js b/auto_tests/tests/callback.js index 8c054a9..4d0b172 100644 --- a/auto_tests/tests/callback.js +++ b/auto_tests/tests/callback.js @@ -375,7 +375,7 @@ CallbackTestCase.prototype.testNaNDataStack = function() { }; CallbackTestCase.prototype.testGapHighlight = function() { -var dataGap = [ + var dataGap = [ [1, null, 3], [2, 2, null], [3, null, 5], diff --git a/dygraph-range-selector.js b/dygraph-range-selector.js index 9ae04d0..6cc184e 100644 --- a/dygraph-range-selector.js +++ b/dygraph-range-selector.js @@ -19,6 +19,8 @@ var DygraphRangeSelector = function(dygraph) { this.isIE_ = /MSIE/.test(navigator.userAgent) && !window.opera; this.isUsingExcanvas_ = dygraph.isUsingExcanvas_; this.dygraph_ = dygraph; + this.hasTouchInterface_ = typeof(TouchEvent) != 'undefined'; + this.isMobileDevice_ = Math.min(screen.width, screen.height) < 480; this.createCanvases_(); if (this.isUsingExcanvas_) { this.createIEPanOverlay_(); @@ -135,15 +137,16 @@ DygraphRangeSelector.prototype.createZoomHandles_ = function() { img.style.zIndex = 10; img.style.visibility = 'hidden'; // Initially hidden so they don't show up in the wrong place. img.style.cursor = 'col-resize'; + if (/MSIE 7/.test(navigator.userAgent)) { // IE7 doesn't support embedded src data. - img.width = 7; - img.height = 14; - img.style.backgroundColor = 'white'; - img.style.border = '1px solid #333333'; // Just show box in IE7. + img.width = 7; + img.height = 14; + img.style.backgroundColor = 'white'; + img.style.border = '1px solid #333333'; // Just show box in IE7. } else { - img.width = 9; - img.height = 16; - img.src = 'data:image/png;base64,' + + img.width = 9; + img.height = 16; + img.src = 'data:image/png;base64,' + 'iVBORw0KGgoAAAANSUhEUgAAAAkAAAAQCAYAAADESFVDAAAAAXNSR0IArs4c6QAAAAZiS0dEANAA' + 'zwDP4Z7KegAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB9sHGw0cMqdt1UwAAAAZdEVYdENv' + 'bW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAaElEQVQoz+3SsRFAQBCF4Z9WJM8KCDVwownl' + @@ -151,6 +154,15 @@ DygraphRangeSelector.prototype.createZoomHandles_ = function() { 'qSTDH32I1pQA2Pb9sZecAxc5r3IAb21d6878xsAAAAAASUVORK5CYII='; } + var minScreenDim = Math.min(screen.width, screen.height); + if (minScreenDim < 480) { + img.width *= 3; + img.height *= 3; + } else if (minScreenDim < 768) { + img.width *= 2; + img.height *= 2; + } + this.leftZoomHandle_ = img; this.rightZoomHandle_ = img.cloneNode(false); }; @@ -166,12 +178,16 @@ DygraphRangeSelector.prototype.initInteraction_ = function() { var handle = null; var isZooming = false; var isPanning = false; + var dynamic = !this.isMobileDevice_ && !this.isUsingExcanvas_; // functions, defined below. Defining them this way (rather than with // "function foo() {...}" makes JSHint happy. var toXDataWindow, onZoomStart, onZoom, onZoomEnd, doZoom, isMouseInPanZone, onPanStart, onPan, onPanEnd, doPan, onCanvasMouseMove; + // Touch event functions + var onZoomHandleTouchEvent, onCanvasTouchEvent, addTouchEvents; + toXDataWindow = function(zoomHandleStatus) { var xDataLimits = self.dygraph_.xAxisExtremes(); var fact = (xDataLimits[1] - xDataLimits[0])/self.canvasRect_.w; @@ -215,7 +231,7 @@ DygraphRangeSelector.prototype.initInteraction_ = function() { self.drawInteractiveLayer_(); // Zoom on the fly (if not using excanvas). - if (!self.isUsingExcanvas_) { + if (dynamic) { doZoom(); } }; @@ -230,7 +246,7 @@ DygraphRangeSelector.prototype.initInteraction_ = function() { self.fgcanvas_.style.cursor = 'default'; // If using excanvas, Zoom now. - if (self.isUsingExcanvas_) { + if (!dynamic) { doZoom(); } }; @@ -254,15 +270,11 @@ DygraphRangeSelector.prototype.initInteraction_ = function() { if (self.isUsingExcanvas_) { return e.srcElement == self.iePanOverlay_; } else { - // Getting clientX directly from the event is not accurate enough :( - var clientX; - if (e.offsetX != undefined) { - clientX = self.canvasRect_.x + e.offsetX; - } else { - clientX = e.clientX; - } - var zoomHandleStatus = self.getZoomHandleStatus_(); - return (clientX > zoomHandleStatus.leftHandlePos && clientX < zoomHandleStatus.rightHandlePos); + var rect = self.leftZoomHandle_.getBoundingClientRect(); + var leftHandleClientX = rect.left + rect.width/2; + rect = self.rightZoomHandle_.getBoundingClientRect(); + var rightHandleClientX = rect.left + rect.width/2; + return (e.clientX > leftHandleClientX && e.clientX < rightHandleClientX); } }; @@ -309,7 +321,7 @@ DygraphRangeSelector.prototype.initInteraction_ = function() { self.drawInteractiveLayer_(); // Do pan on the fly (if not using excanvas). - if (!self.isUsingExcanvas_) { + if (dynamic) { doPan(); } }; @@ -322,7 +334,7 @@ DygraphRangeSelector.prototype.initInteraction_ = function() { Dygraph.removeEvent(topElem, 'mousemove', onPan); Dygraph.removeEvent(topElem, 'mouseup', onPanEnd); // If using excanvas, do pan now. - if (self.isUsingExcanvas_) { + if (!dynamic) { doPan(); } }; @@ -347,6 +359,35 @@ DygraphRangeSelector.prototype.initInteraction_ = function() { } }; + onZoomHandleTouchEvent = function(e) { + e.preventDefault(); + if (e.type == 'touchstart') { + onZoomStart(e.targetTouches[0]); + } else if (e.type == 'touchmove') { + onZoom(e.targetTouches[0]); + } else { + onZoomEnd(e); + } + }; + + onCanvasTouchEvent = function(e) { + e.preventDefault(); + if (e.type == 'touchstart') { + onPanStart(e.targetTouches[0]); + } else if (e.type == 'touchmove') { + onPan(e.targetTouches[0]); + } else { + onPanEnd(e); + } + }; + + addTouchEvents = function(elem, fn) { + var types = ['touchstart', 'touchend', 'touchmove', 'touchcancel']; + for (var i = 0; i < types.length; i++) { + Dygraph.addEvent(elem, types[i], fn); + } + }; + this.dygraph_.attrs_.interactionModel = Dygraph.Interaction.dragIsPanInteractionModel; this.dygraph_.attrs_.panEdgeFraction = 0.0001; @@ -361,6 +402,13 @@ DygraphRangeSelector.prototype.initInteraction_ = function() { Dygraph.addEvent(this.fgcanvas_, 'mousedown', onPanStart); Dygraph.addEvent(this.fgcanvas_, 'mousemove', onCanvasMouseMove); } + + // Touch events + if (this.hasTouchInterface_) { + addTouchEvents(this.leftZoomHandle_, onZoomHandleTouchEvent); + addTouchEvents(this.rightZoomHandle_, onZoomHandleTouchEvent); + addTouchEvents(this.fgcanvas_, onCanvasTouchEvent); + } }; /** @@ -454,14 +502,14 @@ DygraphRangeSelector.prototype.computeCombinedSeriesAndLimits_ = function() { var combinedSeries = []; var sum; var count; - var yVal, y; var mutipleValues; var i, j, k; + var xVal, yVal; // Find out if data has multiple values per datapoint. // Go to first data point that actually has values (see http://code.google.com/p/dygraphs/issues/detail?id=246) for (i = 0; i < data.length; i++) { - if (data[i].length > 1 && data[i][1] != null) { + if (data[i].length > 1 && data[i][1] !== null) { mutipleValues = typeof data[i][1] != 'number'; if (mutipleValues) { sum = []; @@ -477,7 +525,7 @@ DygraphRangeSelector.prototype.computeCombinedSeriesAndLimits_ = function() { for (i = 0; i < data.length; i++) { var dataPoint = data[i]; - var xVal = dataPoint[0]; + xVal = dataPoint[0]; if (mutipleValues) { for (k = 0; k < sum.length; k++) { @@ -489,6 +537,7 @@ DygraphRangeSelector.prototype.computeCombinedSeriesAndLimits_ = function() { for (j = 1; j < dataPoint.length; j++) { if (this.dygraph_.visibility()[j-1]) { + var y; if (mutipleValues) { for (k = 0; k < sum.length; k++) { y = dataPoint[j][k]; diff --git a/gallery/highlighted-weekends.js b/gallery/highlighted-weekends.js new file mode 100644 index 0000000..287aee5 --- /dev/null +++ b/gallery/highlighted-weekends.js @@ -0,0 +1,100 @@ +Gallery.register( + 'highlighted-weekends', + { + name: 'Highlighted Weekends', + title: 'Draws a time series with weekends highlighted', + setup: function(parent) { + parent.innerHTML = [ + "
", + "

When you zoom and pan, the weekend regions remain highlighted.

"].join("\n"); + }, + run: function() { + // Some sample data + var data = "2011-01-01," + Math.random()*100 + "\n" + + "2011-01-02," + Math.random()*100 + "\n" + + "2011-01-03," + Math.random()*100 + "\n" + + "2011-01-04," + Math.random()*100 + "\n" + + "2011-01-05," + Math.random()*100 + "\n" + + "2011-01-06," + Math.random()*100 + "\n" + + "2011-01-07," + Math.random()*100 + "\n" + + "2011-01-08," + Math.random()*100 + "\n" + + "2011-01-09," + Math.random()*100 + "\n" + + "2011-01-10," + Math.random()*100 + "\n" + + "2011-01-11," + Math.random()*100 + "\n" + + "2011-01-12," + Math.random()*100 + "\n" + + "2011-01-13," + Math.random()*100 + "\n" + + "2011-01-14," + Math.random()*100 + "\n" + + "2011-01-15," + Math.random()*100 + "\n" + + "2011-01-16," + Math.random()*100 + "\n" + + "2011-01-17," + Math.random()*100 + "\n" + + "2011-01-18," + Math.random()*100 + "\n" + + "2011-01-19," + Math.random()*100 + "\n" + + "2011-01-20," + Math.random()*100 + "\n" + + "2011-01-21," + Math.random()*100 + "\n" + + "2011-01-22," + Math.random()*100 + "\n" + + "2011-01-23," + Math.random()*100 + "\n" + + "2011-01-24," + Math.random()*100 + "\n" + + "2011-01-25," + Math.random()*100 + "\n" + + "2011-01-26," + Math.random()*100 + "\n" + + "2011-01-27," + Math.random()*100 + "\n" + + "2011-01-28," + Math.random()*100 + "\n" + + "2011-01-29," + Math.random()*100 + "\n" + + "2011-01-30," + Math.random()*100 + "\n" + + "2011-01-31," + Math.random()*100 + "\n" + ; + + var g = new Dygraph( + document.getElementById("div_g"), + data, + { + labels: ['Date','Value'], + underlayCallback: function(canvas, area, g) { + + canvas.fillStyle = "rgba(255, 255, 102, 1.0)"; + + function highlight_period(x_start, x_end) { + var canvas_left_x = g.toDomXCoord(x_start); + var canvas_right_x = g.toDomXCoord(x_end); + var canvas_width = canvas_right_x - canvas_left_x; + canvas.fillRect(canvas_left_x, area.y, canvas_width, area.h); + } + + var min_data_x = g.getValue(0,0); + var max_data_x = g.getValue(g.numRows()-1,0); + + // get day of week + var d = new Date(min_data_x); + var dow = d.getUTCDay(); + var ds = d.toUTCString(); + + var w = min_data_x; + // starting on Sunday is a special case + if (dow == 0) { + highlight_period(w,w+12*3600*1000); + } + // find first saturday + while (dow != 6) { + w += 24*3600*1000; + d = new Date(w); + dow = d.getUTCDay(); + } + // shift back 1/2 day to center highlight around the point for the day + w -= 12*3600*1000; + while (w < max_data_x) { + var start_x_highlight = w; + var end_x_highlight = w + 2*24*3600*1000; + // make sure we don't try to plot outside the graph + if (start_x_highlight < min_data_x) { + start_x_highlight = min_data_x; + } + if (end_x_highlight > max_data_x) { + end_x_highlight = max_data_x; + } + highlight_period(start_x_highlight,end_x_highlight); + // calculate start of highlight for next Saturday + w += 7*24*3600*1000; + } + } + }); + } + }); diff --git a/gallery/index.html b/gallery/index.html index ca10598..44d8d48 100644 --- a/gallery/index.html +++ b/gallery/index.html @@ -20,6 +20,7 @@ +