[Feature Request] Provide option to set color and width for annotation line (#703)
[dygraphs.git] / src / plugins / annotations.js
CommitLineData
ee53deb9
DV
1/**
2 * @license
3 * Copyright 2012 Dan Vanderkam (danvdk@gmail.com)
4 * MIT-licensed (http://opensource.org/licenses/MIT)
5 */
6
0cd1ad15
DV
7/*global Dygraph:false */
8
13f8b047
DV
9"use strict";
10
ee53deb9
DV
11/**
12Current bits of jankiness:
13- Uses dygraph.layout_ to get the parsed annotations.
14- Uses dygraph.plotter_.area
d38c6191
DV
15
16It would be nice if the plugin didn't require so much special support inside
17the core dygraphs classes, but annotations involve quite a bit of parsing and
18layout.
19
20TODO(danvk): cache DOM elements.
ee53deb9
DV
21*/
22
23var annotations = function() {
24 this.annotations_ = [];
25};
26
27annotations.prototype.toString = function() {
28 return "Annotations Plugin";
29};
30
31annotations.prototype.activate = function(g) {
32 return {
33 clearChart: this.clearChart,
98eb4713 34 didDrawChart: this.didDrawChart
ee53deb9
DV
35 };
36};
37
38annotations.prototype.detachLabels = function() {
39 for (var i = 0; i < this.annotations_.length; i++) {
40 var a = this.annotations_[i];
41 if (a.parentNode) a.parentNode.removeChild(a);
42 this.annotations_[i] = null;
43 }
44 this.annotations_ = [];
45};
46
47annotations.prototype.clearChart = function(e) {
48 this.detachLabels();
49};
50
98eb4713 51annotations.prototype.didDrawChart = function(e) {
ee53deb9
DV
52 var g = e.dygraph;
53
54 // Early out in the (common) case of zero annotations.
55 var points = g.layout_.annotated_points;
42a9ebb8 56 if (!points || points.length === 0) return;
ee53deb9
DV
57
58 var containerDiv = e.canvas.parentNode;
ee53deb9
DV
59
60 var bindEvt = function(eventName, classEventName, pt) {
61 return function(annotation_event) {
62 var a = pt.annotation;
63 if (a.hasOwnProperty(eventName)) {
64 a[eventName](a, pt, g, annotation_event);
65 } else if (g.getOption(classEventName)) {
66 g.getOption(classEventName)(a, pt, g, annotation_event );
67 }
68 };
69 };
70
71 // Add the annotations one-by-one.
f0e47200 72 var area = e.dygraph.getArea();
9bb94ee7
DV
73
74 // x-coord to sum of previous annotation's heights (used for stacking).
75 var xToUsedHeight = {};
76
ee53deb9
DV
77 for (var i = 0; i < points.length; i++) {
78 var p = points[i];
79 if (p.canvasx < area.x || p.canvasx > area.x + area.w ||
80 p.canvasy < area.y || p.canvasy > area.y + area.h) {
81 continue;
82 }
83
84 var a = p.annotation;
85 var tick_height = 6;
86 if (a.hasOwnProperty("tickHeight")) {
87 tick_height = a.tickHeight;
88 }
89
f0e47200 90 // TODO: deprecate axisLabelFontSize in favor of CSS
ee53deb9 91 var div = document.createElement("div");
f0e47200
DV
92 div.style['fontSize'] = g.getOption('axisLabelFontSize') + "px";
93 var className = 'dygraph-annotation';
ee53deb9 94 if (!a.hasOwnProperty('icon')) {
f0e47200
DV
95 // camelCase class names are deprecated.
96 className += ' dygraphDefaultAnnotation dygraph-default-annotation';
ee53deb9
DV
97 }
98 if (a.hasOwnProperty('cssClass')) {
f0e47200 99 className += " " + a.cssClass;
ee53deb9 100 }
f0e47200 101 div.className = className;
ee53deb9
DV
102
103 var width = a.hasOwnProperty('width') ? a.width : 16;
104 var height = a.hasOwnProperty('height') ? a.height : 16;
105 if (a.hasOwnProperty('icon')) {
106 var img = document.createElement("img");
107 img.src = a.icon;
108 img.width = width;
109 img.height = height;
110 div.appendChild(img);
111 } else if (p.annotation.hasOwnProperty('shortText')) {
112 div.appendChild(document.createTextNode(p.annotation.shortText));
113 }
9bb94ee7
DV
114 var left = p.canvasx - width / 2;
115 div.style.left = left + "px";
116 var divTop = 0;
ee53deb9 117 if (a.attachAtBottom) {
9bb94ee7
DV
118 var y = (area.y + area.h - height - tick_height);
119 if (xToUsedHeight[left]) {
120 y -= xToUsedHeight[left];
121 } else {
122 xToUsedHeight[left] = 0;
123 }
124 xToUsedHeight[left] += (tick_height + height);
125 divTop = y;
ee53deb9 126 } else {
9bb94ee7 127 divTop = p.canvasy - height - tick_height;
ee53deb9 128 }
9bb94ee7 129 div.style.top = divTop + "px";
ee53deb9
DV
130 div.style.width = width + "px";
131 div.style.height = height + "px";
132 div.title = p.annotation.text;
133 div.style.color = g.colorsMap_[p.name];
134 div.style.borderColor = g.colorsMap_[p.name];
135 a.div = div;
136
aeca29ac 137 g.addAndTrackEvent(div, 'click',
ee53deb9 138 bindEvt('clickHandler', 'annotationClickHandler', p, this));
aeca29ac 139 g.addAndTrackEvent(div, 'mouseover',
ee53deb9 140 bindEvt('mouseOverHandler', 'annotationMouseOverHandler', p, this));
aeca29ac 141 g.addAndTrackEvent(div, 'mouseout',
ee53deb9 142 bindEvt('mouseOutHandler', 'annotationMouseOutHandler', p, this));
aeca29ac 143 g.addAndTrackEvent(div, 'dblclick',
ee53deb9
DV
144 bindEvt('dblClickHandler', 'annotationDblClickHandler', p, this));
145
146 containerDiv.appendChild(div);
147 this.annotations_.push(div);
148
149 var ctx = e.drawingContext;
150 ctx.save();
0bc4cb54
SR
151 ctx.strokeStyle = a.hasOwnProperty('tickColor') ? a.tickColor : g.colorsMap_[p.name];
152 ctx.lineWidth = a.hasOwnProperty('tickWidth') ? a.tickWidth : g.getOption('strokeWidth');
ee53deb9
DV
153 ctx.beginPath();
154 if (!a.attachAtBottom) {
155 ctx.moveTo(p.canvasx, p.canvasy);
156 ctx.lineTo(p.canvasx, p.canvasy - 2 - tick_height);
157 } else {
9bb94ee7
DV
158 var y = divTop + height;
159 ctx.moveTo(p.canvasx, y);
160 ctx.lineTo(p.canvasx, y + tick_height);
ee53deb9
DV
161 }
162 ctx.closePath();
163 ctx.stroke();
164 ctx.restore();
165 }
166};
167
168annotations.prototype.destroy = function() {
169 this.detachLabels();
170};
171
6ecc0739 172export default annotations;