1 function moveV3(event, g, context) {
2 if (context.isPanning) {
3 Dygraph.movePan(event, g, context);
4 } else if (context.isZooming) {
5 Dygraph.moveZoom(event, g, context);
9 function upV3(event, g, context) {
10 if (context.isPanning) {
11 Dygraph.endPan(event, g, context);
12 } else if (context.isZooming) {
13 Dygraph.endZoom(event, g, context);
17 // Take the offset of a mouse event on the dygraph canvas and
18 // convert it to a pair of percentages from the bottom left.
19 // (Not top left, bottom is where the lower value is.)
20 function offsetToPercentage(g, offsetX, offsetY) {
21 // This is calculating the pixel offset of the leftmost date.
22 var xOffset = g.toDomCoords(g.xAxisRange()[0], null)[0];
23 var yar0 = g.yAxisRange(0);
25 // This is calculating the pixel of the higest value. (Top pixel)
26 var yOffset = g.toDomCoords(null, yar0[1])[1];
28 // x y w and h are relative to the corner of the drawing area,
29 // so that the upper corner of the drawing area is (0, 0).
30 var x = offsetX - xOffset;
31 var y = offsetY - yOffset;
33 // This is computing the rightmost pixel, effectively defining the
35 var w = g.toDomCoords(g.xAxisRange()[1], null)[0] - xOffset;
37 // This is computing the lowest pixel, effectively defining the height.
38 var h = g.toDomCoords(null, yar0[0])[1] - yOffset;
40 // Percentage from the left.
41 var xPct = w == 0 ? 0 : (x / w);
42 // Percentage from the top.
43 var yPct = h == 0 ? 0 : (y / h);
45 // The (1-) part below changes it from "% distance down from the top"
46 // to "% distance up from the bottom".
47 return [xPct, (1-yPct)];
50 function dblClickV3(event, g, context) {
51 // Reducing by 20% makes it 80% the original size, which means
52 // to restore to original size it must grow by 25%
54 if (!(event.offsetX && event.offsetY)){
55 event.offsetX = event.layerX - event.target.offsetLeft;
56 event.offsetY = event.layerY - event.target.offsetTop;
59 var percentages = offsetToPercentage(g, event.offsetX, event.offsetY);
60 var xPct = percentages[0];
61 var yPct = percentages[1];
64 zoom(g, -.25, xPct, yPct);
66 zoom(g, +.2, xPct, yPct);
69 restorePositioning(g);
72 var lastClickedGraph = null;
74 function clickV3(event, g, context) {
76 Dygraph.cancelEvent(event);
79 function scrollV3(event, g, context) {
80 if (lastClickedGraph != g) {
83 var normal = event.detail ? event.detail * -1 : event.wheelDelta / 40;
84 // For me the normalized value shows 0.075 for one click. If I took
85 // that verbatim, it would be a 7.5%.
86 var percentage = normal / 50;
88 if (!(event.offsetX && event.offsetY)){
89 event.offsetX = event.layerX - event.target.offsetLeft;
90 event.offsetY = event.layerY - event.target.offsetTop;
93 var percentages = offsetToPercentage(g, event.offsetX, event.offsetY);
94 var xPct = percentages[0];
95 var yPct = percentages[1];
97 zoom(g, percentage, xPct, yPct);
98 Dygraph.cancelEvent(event);
101 // Adjusts [x, y] toward each other by zoomInPercentage%
102 // Split it so the left/bottom axis gets xBias/yBias of that change and
103 // tight/top gets (1-xBias)/(1-yBias) of that change.
105 // If a bias is missing it splits it down the middle.
106 function zoom(g, zoomInPercentage, xBias, yBias) {
107 xBias = xBias || 0.5;
108 yBias = yBias || 0.5;
109 function adjustAxis(axis, zoomInPercentage, bias) {
110 var delta = axis[1] - axis[0];
111 var increment = delta * zoomInPercentage;
112 var foo = [increment * bias, increment * (1-bias)];
113 return [ axis[0] + foo[0], axis[1] - foo[1] ];
115 var yAxes = g.yAxisRanges();
117 for (var i = 0; i < yAxes.length; i++) {
118 newYAxes[i] = adjustAxis(yAxes[i], zoomInPercentage, yBias);
122 dateWindow: adjustAxis(g.xAxisRange(), zoomInPercentage, xBias),
123 valueRange: newYAxes[0]
127 function restorePositioning(g) {
134 function zoom_custom(res) {
135 var w = g.xAxisRange();
136 desired_range = [w[0] - res * 1000, w[0] ];
141 desired_range = orig_range;
146 var desired_range = null;
147 function approach_range() {
148 if (!desired_range) return;
150 var range = g.xAxisRange();
151 if (Math.abs(desired_range[0] - range[0]) < 60 &&
152 Math.abs(desired_range[1] - range[1]) < 60) {
153 if(desired_range[0]>=orig_range[0])
154 g.updateOptions({dateWindow: desired_range});
156 g.updateOptions({dateWindow: orig_range});
159 // (do not set another timeout.)
162 new_range = [0.5 * (desired_range[0] + range[0]),
163 0.5 * (desired_range[1] + range[1])];
164 g.updateOptions({dateWindow: new_range});
170 setTimeout(approach_range, 50);
174 var v4Active = false;
177 function downV4(event, g, context) {
178 context.initializeMouseDown(event, g, context);
180 Dygraph.Interaction.startTouch(event, g, context);
182 Dygraph.Interaction.moveTouch(event, g, context);
184 Dygraph.Interaction.endTouch(event, g, context);
187 moveV4(event, g, context); // in case the mouse went down on a data point.
192 function moveV4(event, g, context) {
196 var graphPos = Dygraph.findPos(g.graphDiv);
197 var canvasx = Dygraph.pageX(event) - graphPos.x;
198 var canvasy = Dygraph.pageY(event) - graphPos.y;
200 var rows = g.numRows();
202 // [date, [val1, stdev1], [val2, stdev2]]
203 for (var row = 0; row < rows; row++) {
204 var date = g.getValue(row, 0);
205 var x = g.toDomCoords(date, null)[0];
206 var diff = Math.abs(canvasx - x);
208 for (var col = 1; col < 3; col++) {
209 // TODO(konigsberg): these will throw exceptions as data is removed.
210 var vals = g.getValue(row, col);
211 if (vals == null) { continue; }
213 var y = g.toDomCoords(null, val)[1];
214 var diff2 = Math.abs(canvasy - y);
217 for (var i in processed) {
218 var stored = processed[i];
219 if(stored[0] == row && stored[1] == col) {
225 //processed.push([row, col]);
236 function upV4(event, g, context) {
242 function dblClickV4(event, g, context) {
243 restorePositioning(g);
246 function drawV4(x, y) {
249 ctx.strokeStyle = "#000000";
250 //ctx.fillStyle = "#FFFF00";
251 ctx.fillStyle = "#FF0000";
253 ctx.arc(x,y,5,0,Math.PI*2,true);
259 function captureCanvas(canvas, area, g) {
263 function newDygraphTouchstart(event, g, context) {
264 // This right here is what prevents IOS from doing its own zoom/touch behavior
265 // It stops the node from being selected too
266 event.preventDefault(); // touch browsers are all nice.
268 if (event.touches.length > 1) {
269 // If the user ever puts two fingers down, it's not a double tap.
270 context.startTimeForDoubleTapMs = null;
274 for (var i = 0; i < event.touches.length; i++) {
275 var t = event.touches[i];
276 // we dispense with 'dragGetX_' because all touchBrowsers support pageX
280 dataX: g.toDataXCoord(t.pageX),
281 dataY: g.toDataYCoord(t.pageY)
282 // identifier: t.identifier
285 context.initialTouches = touches;
287 if (touches.length == 1) {
288 // This is just a swipe.
289 context.initialPinchCenter = touches[0];
290 context.touchDirections = { x: true, y: true };
292 // ADDITION - this needs to select the points
293 //var closestTouchP = g.findClosestPoint(touches[0].pageX,touches[0].pageY);
294 //if(closestTouchP) {
295 //var selectionChanged = g.setSelection(closestTouchP.row, closestTouchP.seriesName);
299 } else if (touches.length >= 2) {
300 // It's become a pinch!
301 // In case there are 3+ touches, we ignore all but the "first" two.
303 // only screen coordinates can be averaged (data coords could be log scale).
304 context.initialPinchCenter = {
305 pageX: 0.5 * (touches[0].pageX + touches[1].pageX),
306 pageY: 0.5 * (touches[0].pageY + touches[1].pageY),
308 // TODO(danvk): remove
309 dataX: 0.5 * (touches[0].dataX + touches[1].dataX),
310 dataY: 0.5 * (touches[0].dataY + touches[1].dataY)
313 // Make pinches in a 45-degree swath around either axis 1-dimensional zooms.
314 var initialAngle = 180 / Math.PI * Math.atan2(
315 context.initialPinchCenter.pageY - touches[0].pageY,
316 touches[0].pageX - context.initialPinchCenter.pageX);
318 // use symmetry to get it into the first quadrant.
319 initialAngle = Math.abs(initialAngle);
320 if (initialAngle > 90) initialAngle = 90 - initialAngle;
322 context.touchDirections = {
323 x: (initialAngle < (90 - 45/2)),
324 y: (initialAngle > 45/2)
328 // save the full x & y ranges.
329 context.initialRange = {