X-Git-Url: https://adrianiainlam.tk/git/?a=blobdiff_plain;f=dygraph.js;h=ff05507fa702505db1fd0cbdf910958a96879613;hb=26ee26180c1d26cee046e33bc2f442c5deb616e7;hp=66d32fa981330e2a53fc845c3b0b37cb9b80e2c6;hpb=88e95c462340958bdfd0ac4c0736b94c5fd21024;p=dygraphs.git diff --git a/dygraph.js b/dygraph.js index 66d32fa..ff05507 100644 --- a/dygraph.js +++ b/dygraph.js @@ -244,6 +244,12 @@ Dygraph.DEFAULT_ATTRS = { interactionModel: null, // will be set to Dygraph.Interaction.defaultModel + // Range selector options + showRangeSelector: false, + rangeSelectorHeight: 40, + rangeSelectorPlotStrokeColor: "#808FAB", + rangeSelectorPlotFillColor: "#A7B1C4", + // per-axis options axes: { x: { @@ -305,6 +311,7 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { document.readyState != 'complete') { var self = this; setTimeout(function() { self.__init__(div, file, attrs) }, 100); + return; } // Support two-argument constructor @@ -317,6 +324,8 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { return; } + this.isUsingExcanvas_ = typeof(G_vmlCanvasManager) != 'undefined'; + // Copy the important bits into the object // TODO(danvk): most of these should just stay in the attrs_ dictionary. this.maindiv_ = div; @@ -348,15 +357,15 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { if (div.style.height == '' && attrs.height) { div.style.height = attrs.height + "px"; } - if (div.style.height == '' && div.offsetHeight == 0) { + if (div.style.height == '' && div.clientHeight == 0) { div.style.height = Dygraph.DEFAULT_HEIGHT + "px"; if (div.style.width == '') { div.style.width = Dygraph.DEFAULT_WIDTH + "px"; } } // these will be zero if the dygraph's div is hidden. - this.width_ = div.offsetWidth; - this.height_ = div.offsetHeight; + this.width_ = div.clientWidth; + this.height_ = div.clientHeight; // TODO(danvk): set fillGraph to be part of attrs_ here, not user_attrs_. if (attrs['stackedGraph']) { @@ -779,10 +788,33 @@ Dygraph.prototype.createInterface_ = function() { this.hidden_ = this.createPlotKitCanvas_(this.canvas_); this.hidden_ctx_ = Dygraph.getContext(this.hidden_); + if (this.attr_('showRangeSelector')) { + // The range selector must be created here so that its canvases and contexts get created here. + // For some reason, if the canvases and contexts don't get created here, things don't work in IE. + // The range selector also sets xAxisHeight in order to reserve space. + this.rangeSelector_ = new DygraphRangeSelector(this); + } + // The interactive parts of the graph are drawn on top of the chart. this.graphDiv.appendChild(this.hidden_); this.graphDiv.appendChild(this.canvas_); - this.mouseEventElement_ = this.canvas_; + this.mouseEventElement_ = this.createMouseEventElement_(); + + // Create the grapher + this.layout_ = new DygraphLayout(this); + + if (this.rangeSelector_) { + // This needs to happen after the graph canvases are added to the div and the layout object is created. + this.rangeSelector_.addToGraph(this.graphDiv, this.layout_); + } + + // Create the grapher + this.layout_ = new DygraphLayout(this); + + if (this.rangeSelector_) { + // This needs to happen after the graph canvases are added to the div and the layout object is created. + this.rangeSelector_.addToGraph(this.graphDiv, this.layout_); + } var dygraph = this; Dygraph.addEvent(this.mouseEventElement_, 'mousemove', function(e) { @@ -792,9 +824,6 @@ Dygraph.prototype.createInterface_ = function() { dygraph.mouseOut_(e); }); - // Create the grapher - this.layout_ = new DygraphLayout(this); - this.createStatusMessage_(); this.createDragInterface_(); @@ -857,6 +886,26 @@ Dygraph.prototype.createPlotKitCanvas_ = function(canvas) { }; /** + * Creates an overlay element used to handle mouse events. + * @return {Object} The mouse event element. + * @private + */ +Dygraph.prototype.createMouseEventElement_ = function() { + if (this.isUsingExcanvas_) { + var elem = document.createElement("div"); + elem.style.position = 'absolute'; + elem.style.backgroundColor = 'white'; + elem.style.filter = 'alpha(opacity=0)'; + elem.style.width = this.width_ + "px"; + elem.style.height = this.height_ + "px"; + this.graphDiv.appendChild(elem); + return elem; + } else { + return this.canvas_; + } +}; + +/** * Generate a set of distinct colors for the data series. This is done with a * color wheel. Saturation/Value are customizable, and the hue is * equally-spaced around the color wheel. If a custom set of colors is @@ -1106,7 +1155,7 @@ Dygraph.prototype.createDragInterface_ = function() { * up any previous zoom rectangles that were drawn. This could be optimized to * avoid extra redrawing, but it's tricky to avoid interactions with the status * dots. - * + * * @param {Number} direction the direction of the zoom rectangle. Acceptable * values are Dygraph.HORIZONTAL and Dygraph.VERTICAL. * @param {Number} startX The X position where the drag started, in canvas @@ -1130,28 +1179,40 @@ Dygraph.prototype.drawZoomRect_ = function(direction, startX, endX, startY, // Clean up from the previous rect if necessary if (prevDirection == Dygraph.HORIZONTAL) { - ctx.clearRect(Math.min(startX, prevEndX), 0, - Math.abs(startX - prevEndX), this.height_); + ctx.clearRect(Math.min(startX, prevEndX), this.layout_.getPlotArea().y, + Math.abs(startX - prevEndX), this.layout_.getPlotArea().h); } else if (prevDirection == Dygraph.VERTICAL){ - ctx.clearRect(0, Math.min(startY, prevEndY), - this.width_, Math.abs(startY - prevEndY)); + ctx.clearRect(this.layout_.getPlotArea().x, Math.min(startY, prevEndY), + this.layout_.getPlotArea().w, Math.abs(startY - prevEndY)); } // Draw a light-grey rectangle to show the new viewing area if (direction == Dygraph.HORIZONTAL) { if (endX && startX) { ctx.fillStyle = "rgba(128,128,128,0.33)"; - ctx.fillRect(Math.min(startX, endX), 0, - Math.abs(endX - startX), this.height_); + ctx.fillRect(Math.min(startX, endX), this.layout_.getPlotArea().y, + Math.abs(endX - startX), this.layout_.getPlotArea().h); } - } - if (direction == Dygraph.VERTICAL) { + } else if (direction == Dygraph.VERTICAL) { if (endY && startY) { ctx.fillStyle = "rgba(128,128,128,0.33)"; - ctx.fillRect(0, Math.min(startY, endY), - this.width_, Math.abs(endY - startY)); + ctx.fillRect(this.layout_.getPlotArea().x, Math.min(startY, endY), + this.layout_.getPlotArea().w, Math.abs(endY - startY)); } } + + if (this.isUsingExcanvas_) { + this.currentZoomRectArgs_ = [direction, startX, endX, startY, endY, 0, 0, 0]; + } +}; + +/** + * Clear the zoom rectangle (and perform no zoom). + * @private + */ +Dygraph.prototype.clearZoomRect_ = function() { + this.currentZoomRectArgs_ = null; + this.canvas_ctx_.clearRect(0, 0, this.canvas_.width, this.canvas_.height); }; /** @@ -1165,6 +1226,7 @@ Dygraph.prototype.drawZoomRect_ = function(direction, startX, endX, startY, * @private */ Dygraph.prototype.doZoomX_ = function(lowX, highX) { + this.currentZoomRectArgs_ = null; // Find the earliest and latest dates contained in this canvasx range. // Convert the call to date ranges of the raw data. var minDate = this.toDataXCoord(lowX); @@ -1199,6 +1261,7 @@ Dygraph.prototype.doZoomXDates_ = function(minDate, maxDate) { * @private */ Dygraph.prototype.doZoomY_ = function(lowY, highY) { + this.currentZoomRectArgs_ = null; // Find the highest and lowest values in pixel range for each axis. // Note that lowY (in pixels) corresponds to the max Value (in data coords). // This is because pixels increase as you go down on the screen, whereas data @@ -1447,6 +1510,10 @@ Dygraph.prototype.updateSelection_ = function() { 2 * maxCircleSize + 2, this.height_); } + if (this.isUsingExcanvas_ && this.currentZoomRectArgs_) { + Dygraph.prototype.drawZoomRect_.apply(this, this.currentZoomRectArgs_); + } + if (this.selPoints_.length > 0) { // Set the status message to indicate the selected point(s) if (this.attr_('showLabelsOnHighlight')) { @@ -1492,11 +1559,11 @@ Dygraph.prototype.setSelection = function(row) { for (var i in this.layout_.datasets) { if (row < this.layout_.datasets[i].length) { var point = this.layout_.points[pos+row]; - + if (this.attr_("stackedGraph")) { point = this.layout_.unstackPointAtIndex(pos+row); } - + this.selPoints_.push(point); } pos += this.layout_.datasets[i].length; @@ -1665,6 +1732,10 @@ Dygraph.prototype.predraw_ = function() { // edge of the div, if we have two y-axes. this.positionLabelsDiv_(); + if (this.rangeSelector_) { + this.rangeSelector_.renderStaticLayer(); + } + // If the data or options have changed, then we'd better redraw. this.drawGraph_(); @@ -1857,6 +1928,10 @@ Dygraph.prototype.renderGraph_ = function(is_initial_draw, clearSelection) { } } + if (this.rangeSelector_) { + this.rangeSelector_.renderInteractiveLayer(); + } + if (this.attr_("drawCallback") !== null) { this.attr_("drawCallback")(this, is_initial_draw); } @@ -2824,8 +2899,8 @@ Dygraph.prototype.resize = function(width, height) { this.width_ = width; this.height_ = height; } else { - this.width_ = this.maindiv_.offsetWidth; - this.height_ = this.maindiv_.offsetHeight; + this.width_ = this.maindiv_.clientWidth; + this.height_ = this.maindiv_.clientHeight; } if (old_width != this.width_ || old_height != this.height_) {