Merge pull request #293 from gmadrid/master
[dygraphs.git] / gallery / drawing.js
1 /*global Gallery,Dygraph,data */
2 Gallery.register(
3 'drawing',
4 {
5 name: 'Time Series Drawing Demo',
6 title: 'Time Series Drawing Demo',
7 setup: function(parent) {
8 parent.innerHTML = [
9 "<div id='toolbar'>",
10 "<div id='tool_zoom'></div>",
11 "<div id='tool_pencil'></div>",
12 "<div id='tool_eraser'></div>",
13 "</div>",
14 "<div id='draw_div' style='width: 600px; height: 300px;'></div>",
15 "<p style='font-size: 10pt'>Toolbar/cursor icons are CC-licensed from ",
16 "<a href='http://www.fatcow.com/free-icons'>FatCow</a>.</p>"].join("\n");
17 },
18
19 run: function() {
20 var change_tool; // defined below.
21 var zoom = document.getElementById('tool_zoom');
22 zoom.onclick = function() { change_tool(zoom); };
23 var pencil = document.getElementById('tool_pencil');
24 pencil.onclick = function() { change_tool(pencil); };
25 var eraser = document.getElementById('tool_eraser');
26 eraser.onclick = function() { change_tool(eraser); };
27
28 var start_date = new Date("2002/12/29").getTime();
29 var end_date = new Date().getTime();
30 var data = [];
31 for (var d = start_date; d < end_date; d += 604800 * 1000) {
32 var millis = d + 2 * 3600 * 1000;
33 data.push( [ new Date(Dygraph.dateString_(millis)), 50 ]);
34 }
35
36 var isDrawing = false;
37 var lastDrawRow = null, lastDrawValue = null;
38 var tool = 'pencil';
39 var valueRange = [0, 100];
40
41 function setPoint(event, g, context) {
42 var graphPos = Dygraph.findPos(g.graphDiv);
43 var canvasx = Dygraph.pageX(event) - graphPos.x;
44 var canvasy = Dygraph.pageY(event) - graphPos.y;
45 var xy = g.toDataCoords(canvasx, canvasy);
46 var x = xy[0], value = xy[1];
47 var rows = g.numRows();
48 var closest_row = -1;
49 var smallest_diff = -1;
50 // TODO(danvk): binary search
51 for (var row = 0; row < rows; row++) {
52 var date = g.getValue(row, 0); // millis
53 var diff = Math.abs(date - x);
54 if (smallest_diff < 0 || diff < smallest_diff) {
55 smallest_diff = diff;
56 closest_row = row;
57 }
58 }
59
60 if (closest_row != -1) {
61 if (lastDrawRow === null) {
62 lastDrawRow = closest_row;
63 lastDrawValue = value;
64 }
65 var coeff = (value - lastDrawValue) / (closest_row - lastDrawRow);
66 if (closest_row == lastDrawRow) coeff = 0.0;
67 var minRow = Math.min(lastDrawRow, closest_row);
68 var maxRow = Math.max(lastDrawRow, closest_row);
69 for (var row = minRow; row <= maxRow; row++) {
70 if (tool == 'pencil') {
71 var val = lastDrawValue + coeff * (row - lastDrawRow);
72 val = Math.max(valueRange[0], Math.min(val, valueRange[1]));
73 data[row][1] = val;
74 if (val === null || value === undefined || isNaN(val)) {
75 console.log(val);
76 }
77 } else if (tool == 'eraser') {
78 data[row][1] = null;
79 }
80 }
81 lastDrawRow = closest_row;
82 lastDrawValue = value;
83 g.updateOptions({ file: data });
84 g.setSelection(closest_row); // prevents the dot from being finnicky.
85 }
86 }
87
88 function finishDraw() {
89 isDrawing = false;
90 lastDrawRow = null;
91 lastDrawValue = null;
92 }
93
94 change_tool = function(tool_div) {
95 var ids = ['tool_zoom', 'tool_pencil', 'tool_eraser'];
96 for (var i = 0; i < ids.length; i++) {
97 var div = document.getElementById(ids[i]);
98 if (div == tool_div) {
99 div.style.backgroundPosition = -(i * 32) + 'px -32px';
100 } else {
101 div.style.backgroundPosition = -(i * 32) + 'px 0px';
102 }
103 }
104 tool = tool_div.id.replace('tool_', '');
105
106 var dg_div = document.getElementById("draw_div");
107 if (tool == 'pencil') {
108 dg_div.style.cursor = 'url(images/cursor-pencil.png) 2 30, auto';
109 } else if (tool == 'eraser') {
110 dg_div.style.cursor = 'url(images/cursor-eraser.png) 10 30, auto';
111 } else if (tool == 'zoom') {
112 dg_div.style.cursor = 'crosshair';
113 }
114 };
115 change_tool(document.getElementById("tool_pencil"));
116
117 new Dygraph(document.getElementById("draw_div"), data,
118 {
119 valueRange: valueRange,
120 labels: [ 'Date', 'Value' ],
121 interactionModel: {
122 mousedown: function (event, g, context) {
123 if (tool == 'zoom') {
124 Dygraph.defaultInteractionModel.mousedown(event, g, context);
125 } else {
126 // prevents mouse drags from selecting page text.
127 if (event.preventDefault) {
128 event.preventDefault(); // Firefox, Chrome, etc.
129 } else {
130 event.returnValue = false; // IE
131 event.cancelBubble = true;
132 }
133 isDrawing = true;
134 setPoint(event, g, context);
135 }
136 },
137 mousemove: function (event, g, context) {
138 if (tool == 'zoom') {
139 Dygraph.defaultInteractionModel.mousemove(event, g, context);
140 } else {
141 if (!isDrawing) return;
142 setPoint(event, g, context);
143 }
144 },
145 mouseup: function(event, g, context) {
146 if (tool == 'zoom') {
147 Dygraph.defaultInteractionModel.mouseup(event, g, context);
148 } else {
149 finishDraw();
150 }
151 },
152 mouseout: function(event, g, context) {
153 if (tool == 'zoom') {
154 Dygraph.defaultInteractionModel.mouseout(event, g, context);
155 }
156 },
157 dblclick: function(event, g, context) {
158 Dygraph.defaultInteractionModel.dblclick(event, g, context);
159 },
160 mousewheel: function(event, g, context) {
161 var normal = event.detail ? event.detail * -1 : event.wheelDelta / 40;
162 var percentage = normal / 50;
163 var axis = g.xAxisRange();
164 var xOffset = g.toDomCoords(axis[0], null)[0];
165 var x = event.offsetX - xOffset;
166 var w = g.toDomCoords(axis[1], null)[0] - xOffset;
167 var xPct = w === 0 ? 0 : (x / w);
168
169 var delta = axis[1] - axis[0];
170 var increment = delta * percentage;
171 var foo = [increment * xPct, increment * (1 - xPct)];
172 var dateWindow = [ axis[0] + foo[0], axis[1] - foo[1] ];
173
174 g.updateOptions({
175 dateWindow: dateWindow
176 });
177 Dygraph.cancelEvent(event);
178 }
179 },
180 strokeWidth: 1.5,
181 gridLineColor: 'rgb(196, 196, 196)',
182 drawYGrid: false,
183 drawYAxis: false
184 });
185 window.onmouseup = finishDraw;
186 }
187 });