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