X-Git-Url: https://adrianiainlam.tk/git/?a=blobdiff_plain;f=dygraph.js;h=8858396e8d0cc2df9ea52cd3f973f4b7003f6c21;hb=f18986e594ec54f8402757b9c087f6a20d611b06;hp=8c3bc599e4768b64552ab379746567da17457f3f;hpb=964f30c6acd7b20818da824da434f18efaf63575;p=dygraphs.git diff --git a/dygraph.js b/dygraph.js index 8c3bc59..8858396 100644 --- a/dygraph.js +++ b/dygraph.js @@ -525,12 +525,15 @@ Dygraph.prototype.createDragInterface_ = function() { var self = this; // Tracks whether the mouse is down right now - var mouseDown = false; + var isZooming = false; + var isPanning = false; var dragStartX = null; var dragStartY = null; var dragEndX = null; var dragEndY = null; var prevEndX = null; + var draggingDate = null; + var dateRange = null; // Utility function to convert page-wide coordinates to canvas coords var px = 0; @@ -540,37 +543,63 @@ Dygraph.prototype.createDragInterface_ = function() { // Draw zoom rectangles when the mouse is down and the user moves around Dygraph.addEvent(this.hidden_, 'mousemove', function(event) { - if (mouseDown) { + if (isZooming) { dragEndX = getX(event); dragEndY = getY(event); self.drawZoomRect_(dragStartX, dragEndX, prevEndX); prevEndX = dragEndX; + } else if (isPanning) { + dragEndX = getX(event); + dragEndY = getY(event); + + // Want to have it so that: + // 1. draggingDate appears at dragEndX + // 2. daterange = (dateWindow_[1] - dateWindow_[0]) is unaltered. + + self.dateWindow_[0] = draggingDate - (dragEndX / self.width_) * dateRange; + self.dateWindow_[1] = self.dateWindow_[0] + dateRange; + self.drawGraph_(self.rawData_); } }); // Track the beginning of drag events Dygraph.addEvent(this.hidden_, 'mousedown', function(event) { - mouseDown = true; px = Dygraph.findPosX(self.canvas_); py = Dygraph.findPosY(self.canvas_); dragStartX = getX(event); dragStartY = getY(event); + + if (event.altKey || event.shiftKey) { + if (!self.dateWindow_) return; // have to be zoomed in to pan. + isPanning = true; + dateRange = self.dateWindow_[1] - self.dateWindow_[0]; + draggingDate = (dragStartX / self.width_) * dateRange + + self.dateWindow_[0]; + } else { + isZooming = true; + } }); // If the user releases the mouse button during a drag, but not over the // canvas, then it doesn't count as a zooming action. Dygraph.addEvent(document, 'mouseup', function(event) { - if (mouseDown) { - mouseDown = false; + if (isZooming || isPanning) { + isZooming = false; dragStartX = null; dragStartY = null; } + + if (isPanning) { + isPanning = false; + draggingDate = null; + dateRange = null; + } }); // Temporarily cancel the dragging event when the mouse leaves the graph Dygraph.addEvent(this.hidden_, 'mouseout', function(event) { - if (mouseDown) { + if (isZooming) { dragEndX = null; dragEndY = null; } @@ -579,8 +608,8 @@ Dygraph.prototype.createDragInterface_ = function() { // If the mouse is released on the canvas during a drag event, then it's a // zoom. Only do the zoom if it's over a large enough area (>= 10 pixels) Dygraph.addEvent(this.hidden_, 'mouseup', function(event) { - if (mouseDown) { - mouseDown = false; + if (isZooming) { + isZooming = false; dragEndX = getX(event); dragEndY = getY(event); var regionWidth = Math.abs(dragEndX - dragStartX); @@ -605,6 +634,12 @@ Dygraph.prototype.createDragInterface_ = function() { dragStartX = null; dragStartY = null; } + + if (isPanning) { + isPanning = false; + draggingDate = null; + dateRange = null; + } }); // Double-clicking zooms back out @@ -941,7 +976,7 @@ Dygraph.prototype.GetXAxis = function(start_time, end_time, granularity) { if (granularity < Dygraph.MONTHLY) { // Generate one tick mark for every fixed interval of time. var spacing = Dygraph.SHORT_SPACINGS[granularity]; - var format = '%d%b'; // e.g. "1 Jan" + var format = '%d%b'; // e.g. "1Jan" // TODO(danvk): be smarter about making sure this really hits a "nice" time. if (granularity < Dygraph.HOURLY) { start_time = spacing * Math.floor(0.5 + start_time / spacing); @@ -1030,12 +1065,20 @@ Dygraph.numericTicks = function(minV, maxV, self) { // Try labels every 1, 2, 5, 10, 20, 50, 100, etc. // Calculate the resulting tick spacing (i.e. this.height_ / nTicks). // The first spacing greater than pixelsPerYLabel is what we use. - var mults = [1, 2, 5]; + if (self.attr_("labelsKMG2")) { + var mults = [1, 2, 4, 8]; + } else { + var mults = [1, 2, 5]; + } var scale, low_val, high_val, nTicks; // TODO(danvk): make it possible to set this for x- and y-axes independently. var pixelsPerTick = self.attr_('pixelsPerYLabel'); for (var i = -10; i < 50; i++) { - var base_scale = Math.pow(10, i); + if (self.attr_("labelsKMG2")) { + var base_scale = Math.pow(16, i); + } else { + var base_scale = Math.pow(10, i); + } for (var j = 0; j < mults.length; j++) { scale = base_scale * mults[j]; low_val = Math.floor(minV / scale) * scale; @@ -1122,7 +1165,7 @@ Dygraph.prototype.extremeValues_ = function(series) { } else { for (var j = 0; j < series.length; j++) { var y = series[j][1]; - if (!y) continue; + if (y === null || isNaN(y)) continue; if (maxY == null || y > maxY) { maxY = y; } @@ -1214,11 +1257,12 @@ Dygraph.prototype.drawGraph_ = function(data) { this.addXTicks_(); // Tell PlotKit to use this new data and render itself + this.layout_.updateOptions({dateWindow: this.dateWindow_}); this.layout_.evaluateWithError(); this.plotter_.clear(); this.plotter_.render(); - this.canvas_.getContext('2d').clearRect(0, 0, - this.canvas_.width, this.canvas_.height); + this.canvas_.getContext('2d').clearRect(0, 0, this.canvas_.width, + this.canvas_.height); }; /** @@ -1601,7 +1645,13 @@ Dygraph.prototype.parseDataTable_ = function(data) { var ret = []; for (var i = 0; i < rows; i++) { var row = []; - if (!data.getValue(i, 0)) continue; + if (typeof(data.getValue(i, 0)) === 'undefined' || + data.getValue(i, 0) === null) { + this.warning("Ignoring row " + i + + " of DataTable because of undefined or null first column."); + continue; + } + if (indepType == 'date') { row.push(data.getValue(i, 0).getTime()); } else { @@ -1760,7 +1810,10 @@ Dygraph.prototype.resize = function(width, height) { width = height = null; } + // TODO(danvk): there should be a clear() method. this.maindiv_.innerHTML = ""; + this.attrs_.labelsDiv = null; + if (width) { this.maindiv_.style.width = width + "px"; this.maindiv_.style.height = height + "px";