this.isUsingExcanvas_ = dygraph.isUsingExcanvas_;
this.dygraph_ = dygraph;
this.hasTouchInterface_ = typeof(TouchEvent) != 'undefined';
- this.isMobileDevice_ = Math.min(screen.width, screen.height) < 480;
+ this.isMobileDevice_ = /mobile|android/gi.test(navigator.appVersion);
this.createCanvases_();
if (this.isUsingExcanvas_) {
this.createIEPanOverlay_();
}
var plotArea = this.layout_.getPlotArea();
- var xAxisLabelHeight = this.attr_('axisLabelFontSize') + 2 * this.attr_('axisTickSize');
+ var xAxisLabelHeight = this.attr_('xAxisHeight') || (this.attr_('axisLabelFontSize') + 2 * this.attr_('axisTickSize'));
this.canvasRect_ = {
x: plotArea.x,
y: plotArea.y + plotArea.h + xAxisLabelHeight + 4,
'qSTDH32I1pQA2Pb9sZecAxc5r3IAb21d6878xsAAAAAASUVORK5CYII=';
}
- var minScreenDim = Math.min(screen.width, screen.height);
- if (minScreenDim < 480) {
- img.width *= 3;
- img.height *= 3;
- } else if (minScreenDim < 768) {
+ if (this.isMobileDevice_) {
img.width *= 2;
img.height *= 2;
}
var isPanning = false;
var dynamic = !this.isMobileDevice_ && !this.isUsingExcanvas_;
+ // We cover iframes during mouse interactions. See comments in
+ // dygraph-utils.js for more info on why this is a good idea.
+ var tarp = new Dygraph.IFrameTarp();
+
// 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;
+ onPanStart, onPan, onPanEnd, doPan, onCanvasMouseMove, applyBrowserZoomLevel;
// Touch event functions
var onZoomHandleTouchEvent, onCanvasTouchEvent, addTouchEvents;
return [xDataMin, xDataMax];
};
+ applyBrowserZoomLevel = function(delX) {
+ var zoom = window.outerWidth/document.documentElement.clientWidth;
+ if (!isNaN(zoom)) {
+ return delX/zoom;
+ } else {
+ return delX;
+ }
+ };
+
onZoomStart = function(e) {
Dygraph.cancelEvent(e);
isZooming = true;
self.dygraph_.addEvent(topElem, 'mousemove', onZoom);
self.dygraph_.addEvent(topElem, 'mouseup', onZoomEnd);
self.fgcanvas_.style.cursor = 'col-resize';
+ tarp.cover();
+ return true;
};
onZoom = function(e) {
if (!isZooming) {
- return;
+ return false;
}
+ Dygraph.cancelEvent(e);
var delX = e.screenX - xLast;
- if (Math.abs(delX) < 4) {
- return;
+ if (Math.abs(delX) < 4 || e.screenX === 0) {
+ // First iPad move event seems to have screenX = 0
+ return true;
}
xLast = e.screenX;
+ delX = applyBrowserZoomLevel(delX);
+
+ // Move handle.
var zoomHandleStatus = self.getZoomHandleStatus_();
var newPos;
if (handle == self.leftZoomHandle_) {
if (dynamic) {
doZoom();
}
+ return true;
};
onZoomEnd = function(e) {
if (!isZooming) {
- return;
+ return false;
}
isZooming = false;
+ tarp.uncover();
Dygraph.removeEvent(topElem, 'mousemove', onZoom);
Dygraph.removeEvent(topElem, 'mouseup', onZoomEnd);
self.fgcanvas_.style.cursor = 'default';
if (!dynamic) {
doZoom();
}
+ return true;
};
doZoom = function() {
xLast = e.screenX;
self.dygraph_.addEvent(topElem, 'mousemove', onPan);
self.dygraph_.addEvent(topElem, 'mouseup', onPanEnd);
+ return true;
}
+ return false;
};
onPan = function(e) {
if (!isPanning) {
- return;
+ return false;
}
Dygraph.cancelEvent(e);
var delX = e.screenX - xLast;
if (Math.abs(delX) < 4) {
- return;
+ return true;
}
xLast = e.screenX;
+ delX = applyBrowserZoomLevel(delX);
// Move range view
var zoomHandleStatus = self.getZoomHandleStatus_();
if (dynamic) {
doPan();
}
+ return true;
};
onPanEnd = function(e) {
if (!isPanning) {
- return;
+ return false;
}
isPanning = false;
Dygraph.removeEvent(topElem, 'mousemove', onPan);
if (!dynamic) {
doPan();
}
+ return true;
};
doPan = function() {
};
onZoomHandleTouchEvent = function(e) {
- e.preventDefault();
- if (e.type == 'touchstart') {
- onZoomStart(e.targetTouches[0]);
- } else if (e.type == 'touchmove') {
- onZoom(e.targetTouches[0]);
+ if (e.type == 'touchstart' && e.targetTouches.length == 1) {
+ if (onZoomStart(e.targetTouches[0])) {
+ Dygraph.cancelEvent(e);
+ }
+ } else if (e.type == 'touchmove' && e.targetTouches.length == 1) {
+ if (onZoom(e.targetTouches[0])) {
+ Dygraph.cancelEvent(e);
+ }
} 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]);
+ if (e.type == 'touchstart' && e.targetTouches.length == 1) {
+ if (onPanStart(e.targetTouches[0])) {
+ Dygraph.cancelEvent(e);
+ }
+ } else if (e.type == 'touchmove' && e.targetTouches.length == 1) {
+ if (onPan(e.targetTouches[0])) {
+ Dygraph.cancelEvent(e);
+ }
} else {
onPanEnd(e);
}
return;
}
+ var stepPlot = this.attr_('stepPlot');
+
var combinedSeriesData = this.computeCombinedSeriesAndLimits_();
var yRange = combinedSeriesData.yMax - combinedSeriesData.yMin;
var canvasWidth = this.canvasRect_.w - margin;
var canvasHeight = this.canvasRect_.h - margin;
+ var prevX = null, prevY = null;
+
ctx.beginPath();
ctx.moveTo(margin, canvasHeight);
for (var i = 0; i < combinedSeriesData.data.length; i++) {
var dataPoint = combinedSeriesData.data[i];
- var x = (dataPoint[0] - xExtremes[0])*xFact;
- var y = canvasHeight - (dataPoint[1] - combinedSeriesData.yMin)*yFact;
+ var x = ((dataPoint[0] !== null) ? ((dataPoint[0] - xExtremes[0])*xFact) : NaN);
+ var y = ((dataPoint[1] !== null) ? (canvasHeight - (dataPoint[1] - combinedSeriesData.yMin)*yFact) : NaN);
if (isFinite(x) && isFinite(y)) {
+ if(prevX === null) {
+ ctx.lineTo(x, canvasHeight);
+ }
+ else if (stepPlot) {
+ ctx.lineTo(x, prevY);
+ }
ctx.lineTo(x, y);
+ prevX = x;
+ prevY = y;
+ }
+ else {
+ if(prevX !== null) {
+ if (stepPlot) {
+ ctx.lineTo(x, prevY);
+ ctx.lineTo(x, canvasHeight);
+ }
+ else {
+ ctx.lineTo(prevX, canvasHeight);
+ }
+ }
+ prevX = prevY = null;
}
}
ctx.lineTo(canvasWidth, canvasHeight);