- // draw a vertical line on the left to separate the chart from the labels.
- var axisX;
- if (this.attr_('drawAxesAtZero')) {
- var r = this.dygraph_.toPercentXCoord(0);
- if (r > 1 || r < 0) r = 0;
- axisX = halfUp(this.area.x + r * this.area.w);
- } else {
- axisX = halfUp(this.area.x);
- }
- context.beginPath();
- context.moveTo(axisX, halfDown(this.area.y));
- context.lineTo(axisX, halfDown(this.area.y + this.area.h));
- context.closePath();
- context.stroke();
-
- // if there's a secondary y-axis, draw a vertical line for that, too.
- if (this.dygraph_.numAxes() == 2) {
- context.beginPath();
- context.moveTo(halfDown(this.area.x + this.area.w), halfDown(this.area.y));
- context.lineTo(halfDown(this.area.x + this.area.w), halfDown(this.area.y + this.area.h));
- context.closePath();
- context.stroke();
- }
- }
-
- if (this.attr_('drawXAxis')) {
- if (this.layout.xticks) {
- for (i = 0; i < this.layout.xticks.length; i++) {
- tick = this.layout.xticks[i];
- x = this.area.x + tick[0] * this.area.w;
- y = this.area.y + this.area.h;
-
- /* Tick marks are currently clipped, so don't bother drawing them.
- context.beginPath();
- context.moveTo(halfUp(x), halfDown(y));
- context.lineTo(halfUp(x), halfDown(y + this.attr_('axisTickSize')));
- context.closePath();
- context.stroke();
- */
-
- label = makeDiv(tick[1], 'x');
- label.style.textAlign = "center";
- label.style.top = (y + this.attr_('axisTickSize')) + 'px';
-
- var left = (x - this.attr_('axisLabelWidth')/2);
- if (left + this.attr_('axisLabelWidth') > this.width) {
- left = this.width - this.attr_('xAxisLabelWidth');
- label.style.textAlign = "right";
- }
- if (left < 0) {
- left = 0;
- label.style.textAlign = "left";
- }
-
- label.style.left = left + "px";
- label.style.width = this.attr_('xAxisLabelWidth') + "px";
- this.container.appendChild(label);
- this.xlabels.push(label);
- }
- }
-
- context.beginPath();
- var axisY;
- if (this.attr_('drawAxesAtZero')) {
- var r = this.dygraph_.toPercentYCoord(0, 0);
- if (r > 1 || r < 0) r = 1;
- axisY = halfDown(this.area.y + r * this.area.h);
- } else {
- axisY = halfDown(this.area.y + this.area.h);
- }
- context.moveTo(halfUp(this.area.x), axisY);
- context.lineTo(halfUp(this.area.x + this.area.w), axisY);
- context.closePath();
- context.stroke();
- }
-
- context.restore();
-};
-
-
-DygraphCanvasRenderer.prototype._renderChartLabels = function() {
- var div, class_div;
-
- // Generate divs for the chart title, xlabel and ylabel.
- // Space for these divs has already been taken away from the charting area in
- // the DygraphCanvasRenderer constructor.
- if (this.attr_('title')) {
- div = document.createElement("div");
- div.style.position = 'absolute';
- div.style.top = '0px';
- div.style.left = this.area.x + 'px';
- div.style.width = this.area.w + 'px';
- div.style.height = this.attr_('titleHeight') + 'px';
- div.style.textAlign = 'center';
- div.style.fontSize = (this.attr_('titleHeight') - 8) + 'px';
- div.style.fontWeight = 'bold';
- class_div = document.createElement("div");
- class_div.className = 'dygraph-label dygraph-title';
- class_div.innerHTML = this.attr_('title');
- div.appendChild(class_div);
- this.container.appendChild(div);
- this.chartLabels.title = div;
- }
-
- if (this.attr_('xlabel')) {
- div = document.createElement("div");
- div.style.position = 'absolute';
- div.style.bottom = 0; // TODO(danvk): this is lazy. Calculate style.top.
- div.style.left = this.area.x + 'px';
- div.style.width = this.area.w + 'px';
- div.style.height = this.attr_('xLabelHeight') + 'px';
- div.style.textAlign = 'center';
- div.style.fontSize = (this.attr_('xLabelHeight') - 2) + 'px';
-
- class_div = document.createElement("div");
- class_div.className = 'dygraph-label dygraph-xlabel';
- class_div.innerHTML = this.attr_('xlabel');
- div.appendChild(class_div);
- this.container.appendChild(div);
- this.chartLabels.xlabel = div;
- }
-
- var that = this;
- function createRotatedDiv(axis, classes, html) {
- var box = {
- left: 0,
- top: that.area.y,
- width: that.attr_('yLabelWidth'),
- height: that.area.h
- };
- // TODO(danvk): is this outer div actually necessary?
- div = document.createElement("div");
- div.style.position = 'absolute';
- if (axis == 1) {
- div.style.left = box.left;
- } else {
- div.style.right = box.left;
- }
- div.style.top = box.top + 'px';
- div.style.width = box.width + 'px';
- div.style.height = box.height + 'px';
- div.style.fontSize = (that.attr_('yLabelWidth') - 2) + 'px';
-
- var inner_div = document.createElement("div");
- inner_div.style.position = 'absolute';
- inner_div.style.width = box.height + 'px';
- inner_div.style.height = box.width + 'px';
- inner_div.style.top = (box.height / 2 - box.width / 2) + 'px';
- inner_div.style.left = (box.width / 2 - box.height / 2) + 'px';
- inner_div.style.textAlign = 'center';
-
- // CSS rotation is an HTML5 feature which is not standardized. Hence every
- // browser has its own name for the CSS style.
- var val = 'rotate(' + (axis == 1 ? '-' : '') + '90deg)';
- inner_div.style.transform = val; // HTML5
- inner_div.style.WebkitTransform = val; // Safari/Chrome
- inner_div.style.MozTransform = val; // Firefox
- inner_div.style.OTransform = val; // Opera
- inner_div.style.msTransform = val; // IE9
-
- if (typeof(document.documentMode) !== 'undefined' &&
- document.documentMode < 9) {
- // We're dealing w/ an old version of IE, so we have to rotate the text
- // using a BasicImage transform. This uses a different origin of rotation
- // than HTML5 rotation (top left of div vs. its center).
- inner_div.style.filter =
- 'progid:DXImageTransform.Microsoft.BasicImage(rotation=' +
- (axis == 1 ? '3' : '1') + ')';
- inner_div.style.left = '0px';
- inner_div.style.top = '0px';
- }
-
- class_div = document.createElement("div");
- class_div.className = classes;
- class_div.innerHTML = html;
-
- inner_div.appendChild(class_div);
- div.appendChild(inner_div);
- return div;
- }
-
- var div;
- if (this.attr_('ylabel')) {
- div = createRotatedDiv(1, 'dygraph-label dygraph-ylabel',
- this.attr_('ylabel'));
- this.container.appendChild(div);
- this.chartLabels.ylabel = div;
- }
- if (this.attr_('y2label') && this.dygraph_.numAxes() == 2) {
- div = createRotatedDiv(2, 'dygraph-label dygraph-y2label',
- this.attr_('y2label'));
- this.container.appendChild(div);
- this.chartLabels.y2label = div;
- }
-};
-
-
-DygraphCanvasRenderer.prototype._renderAnnotations = function() {
- var annotationStyle = {
- "position": "absolute",
- "fontSize": this.attr_('axisLabelFontSize') + "px",
- "zIndex": 10,
- "overflow": "hidden"
- };
-
- var bindEvt = function(eventName, classEventName, p, self) {
- return function(e) {
- var a = p.annotation;
- if (a.hasOwnProperty(eventName)) {
- a[eventName](a, p, self.dygraph_, e);
- } else if (self.dygraph_.attr_(classEventName)) {
- self.dygraph_.attr_(classEventName)(a, p, self.dygraph_,e );
- }
- };
- };
-
- // Get a list of point with annotations.
- var points = this.layout.annotated_points;
- for (var i = 0; i < points.length; i++) {
- var p = points[i];
- if (p.canvasx < this.area.x || p.canvasx > this.area.x + this.area.w ||
- p.canvasy < this.area.y || p.canvasy > this.area.y + this.area.h) {
- continue;
- }
-
- var a = p.annotation;
- var tick_height = 6;
- if (a.hasOwnProperty("tickHeight")) {
- tick_height = a.tickHeight;
- }
-
- var div = document.createElement("div");
- for (var name in annotationStyle) {
- if (annotationStyle.hasOwnProperty(name)) {
- div.style[name] = annotationStyle[name];
- }
- }
- if (!a.hasOwnProperty('icon')) {
- div.className = "dygraphDefaultAnnotation";
- }
- if (a.hasOwnProperty('cssClass')) {
- div.className += " " + a.cssClass;
- }
-
- var width = a.hasOwnProperty('width') ? a.width : 16;
- var height = a.hasOwnProperty('height') ? a.height : 16;
- if (a.hasOwnProperty('icon')) {
- var img = document.createElement("img");
- img.src = a.icon;
- img.width = width;
- img.height = height;
- div.appendChild(img);
- } else if (p.annotation.hasOwnProperty('shortText')) {
- div.appendChild(document.createTextNode(p.annotation.shortText));
- }
- div.style.left = (p.canvasx - width / 2) + "px";
- if (a.attachAtBottom) {
- div.style.top = (this.area.h - height - tick_height) + "px";
- } else {
- div.style.top = (p.canvasy - height - tick_height) + "px";
- }
- div.style.width = width + "px";
- div.style.height = height + "px";
- div.title = p.annotation.text;
- div.style.color = this.colors[p.name];
- div.style.borderColor = this.colors[p.name];
- a.div = div;
-
- this.dygraph_.addEvent(div, 'click',
- bindEvt('clickHandler', 'annotationClickHandler', p, this));
- this.dygraph_.addEvent(div, 'mouseover',
- bindEvt('mouseOverHandler', 'annotationMouseOverHandler', p, this));
- this.dygraph_.addEvent(div, 'mouseout',
- bindEvt('mouseOutHandler', 'annotationMouseOutHandler', p, this));
- this.dygraph_.addEvent(div, 'dblclick',
- bindEvt('dblClickHandler', 'annotationDblClickHandler', p, this));
-
- this.container.appendChild(div);
- this.annotations.push(div);
-
- var ctx = this.elementContext;
- ctx.strokeStyle = this.colors[p.name];
- ctx.beginPath();
- if (!a.attachAtBottom) {
- ctx.moveTo(p.canvasx, p.canvasy);
- ctx.lineTo(p.canvasx, p.canvasy - 2 - tick_height);
- } else {
- ctx.moveTo(p.canvasx, this.area.h);
- ctx.lineTo(p.canvasx, this.area.h - 2 - tick_height);
- }
- ctx.closePath();
- ctx.stroke();
- }
-};
-
-DygraphCanvasRenderer.makeNextPointStep_ = function(
- connect, points, start, end) {
- if (connect) {
- return function(j) {
- while (++j + start < end) {
- if (!(points[start + j].yval === null)) break;
- }
- return j;
- }
- } else {
- return function(j) { return j + 1 };
- }