Interaction model demo: Clever hack -- now when scrolling down the page,
[dygraphs.git] / tests / interaction.js
1
2 function downV3(event, g, context) {
3 resetGraphScroll();
4 context.initializeMouseDown(event, g, context);
5 if (event.altKey || event.shiftKey) {
6 Dygraph.startZoom(event, g, context);
7 } else {
8 Dygraph.startPan(event, g, context);
9 }
10 }
11
12 function moveV3(event, g, context) {
13 resetGraphScroll();
14 if (context.isPanning) {
15 Dygraph.movePan(event, g, context);
16 } else if (context.isZooming) {
17 Dygraph.moveZoom(event, g, context);
18 }
19 }
20
21 function upV3(event, g, context) {
22 if (context.isPanning) {
23 Dygraph.endPan(event, g, context);
24 } else if (context.isZooming) {
25 Dygraph.endZoom(event, g, context);
26 }
27 }
28
29 // Take the offset of a mouse event on the dygraph canvas and
30 // convert it to a pair of percentages from the bottom left.
31 // (Not top left, bottom is where the lower value is.)
32 function offsetToPercentage(g, offsetX, offsetY) {
33 // This is calculating the pixel offset of the leftmost date.
34 var xOffset = g.toDomCoords(g.xAxisRange()[0], null)[0];
35 var yar0 = g.yAxisRange(0);
36
37 // This is calculating the pixel of the higest value. (Top pixel)
38 var yOffset = g.toDomCoords(null, yar0[1])[1];
39
40 // x y w and h are relative to the corner of the drawing area,
41 // so that the upper corner of the drawing area is (0, 0).
42 var x = offsetX - xOffset;
43 var y = offsetY - yOffset;
44
45 // This is computing the rightmost pixel, effectively defining the
46 // width.
47 var w = g.toDomCoords(g.xAxisRange()[1], null)[0] - xOffset;
48
49 // This is computing the lowest pixel, effectively defining the height.
50 var h = g.toDomCoords(null, yar0[0])[1] - yOffset;
51
52 // Percentage from the left.
53 var xPct = w == 0 ? 0 : (x / w);
54 // Percentage from the top.
55 var yPct = h == 0 ? 0 : (y / h);
56
57 // The (1-) part below changes it from "% distance down from the top"
58 // to "% distance up from the bottom".
59 return [xPct, (1-yPct)];
60 }
61
62 function dblClickV3(event, g, context) {
63 // Reducing by 20% makes it 80% the original size, which means
64 // to restore to original size it must grow by 25%
65 var percentages = offsetToPercentage(g, event.offsetX, event.offsetY);
66 var xPct = percentages[0];
67 var yPct = percentages[1];
68
69 if (event.ctrlKey) {
70 zoom(g, -.25, xPct, yPct);
71 } else {
72 zoom(g, +.2, xPct, yPct);
73 }
74 }
75
76 var scrollTimeMillis = 0;
77
78 function suspendGraphScroll() {
79 scrollTimeMillis = new Date().getTime();
80 }
81
82 function resetGraphscroll() {
83 scrollTimeMillis = 0;
84 }
85
86 function scrollV3(event, g, context) {
87 var millis = new Date().getTime();
88 if (millis - scrollTimeMillis < 250) {
89 suspendGraphScroll();
90 return;
91 }
92 var normal = event.detail ? event.detail * -1 : event.wheelDelta / 40;
93 // For me the normalized value shows 0.075 for one click. If I took
94 // that verbatim, it would be a 7.5%.
95 var percentage = normal / 50;
96
97 var percentages = offsetToPercentage(g, event.offsetX, event.offsetY);
98 var xPct = percentages[0];
99 var yPct = percentages[1];
100
101 zoom(g, percentage, xPct, yPct);
102 Dygraph.cancelEvent(event);
103 }
104
105 // Adjusts [x, y] toward each other by zoomInPercentage%
106 // Split it so the left/bottom axis gets xBias/yBias of that change and
107 // tight/top gets (1-xBias)/(1-yBias) of that change.
108 //
109 // If a bias is missing it splits it down the middle.
110 function zoom(g, zoomInPercentage, xBias, yBias) {
111 xBias = xBias || 0.5;
112 yBias = yBias || 0.5;
113 function adjustAxis(axis, zoomInPercentage, bias) {
114 var delta = axis[1] - axis[0];
115 var increment = delta * zoomInPercentage;
116 var foo = [increment * bias, increment * (1-bias)];
117 return [ axis[0] + foo[0], axis[1] - foo[1] ];
118 }
119 var yAxes = g.yAxisRanges();
120 var newYAxes = [];
121 for (var i = 0; i < yAxes.length; i++) {
122 newYAxes[i] = adjustAxis(yAxes[i], zoomInPercentage, yBias);
123 }
124
125 g.updateOptions({
126 dateWindow: adjustAxis(g.xAxisRange(), zoomInPercentage, xBias),
127 valueRange: newYAxes[0]
128 });
129 }
130
131 var v4Active = false;
132 var v4Canvas = null;
133
134 function downV4(event, g, context) {
135 context.initializeMouseDown(event, g, context);
136 v4Active = true;
137 moveV4(event, g, context); // in case the mouse went down on a data point.
138 }
139
140 var processed = [];
141
142 function moveV4(event, g, context) {
143 var RANGE = 7;
144
145 if (v4Active) {
146 var canvasx = Dygraph.pageX(event) - Dygraph.findPosX(g.graphDiv);
147 var canvasy = Dygraph.pageY(event) - Dygraph.findPosY(g.graphDiv);
148
149 var rows = g.numRows();
150 // Row layout:
151 // [date, [val1, stdev1], [val2, stdev2]]
152 for (var row = 0; row < rows; row++) {
153 var date = g.getValue(row, 0);
154 var x = g.toDomCoords(date, null)[0];
155 var diff = Math.abs(canvasx - x);
156 if (diff < RANGE) {
157 for (var col = 1; col < 3; col++) {
158 // TODO(konigsberg): these will throw exceptions as data is removed.
159 var vals = g.getValue(row, col);
160 if (vals == null) { continue; }
161 var val = vals[0];
162 var y = g.toDomCoords(null, val)[1];
163 var diff2 = Math.abs(canvasy - y);
164 if (diff2 < RANGE) {
165 var found = false;
166 for (var i in processed) {
167 var stored = processed[i];
168 if(stored[0] == row && stored[1] == col) {
169 found = true;
170 break;
171 }
172 }
173 if (!found) {
174 processed.push([row, col]);
175 drawV4(x, y);
176 }
177 return;
178 }
179 }
180 }
181 }
182 }
183 }
184
185 function upV4(event, g, context) {
186 if (v4Active) {
187 v4Active = false;
188 }
189 }
190
191 function dblClickV4(event, g, context) {
192 restorePositioning(g4);
193 }
194
195 function drawV4(x, y) {
196 var ctx = v4Canvas;
197
198 ctx.strokeStyle = "#000000";
199 ctx.fillStyle = "#FFFF00";
200 ctx.beginPath();
201 ctx.arc(x,y,5,0,Math.PI*2,true);
202 ctx.closePath();
203 ctx.stroke();
204 ctx.fill();
205 }
206
207 function captureCanvas(canvas, area, g) {
208 v4Canvas = canvas;
209 }
210
211 function restorePositioning(g) {
212 g.updateOptions({
213 dateWindow: null,
214 valueRange: null
215 });
216 }