public
Created

Plots functions over a domain of 2*PI on * http://www.google.com/trends/correlate/draw.

  • Download Gist
googleCorrelateDraw.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
/**
* Plots functions over a domain of 2*PI on
* http://www.google.com/trends/correlate/draw.
*
* More here:
*
* http://www.jeffpalm.com/blog/archives/002216.html
*/
(function() {
 
/*
* Translation coordinates for the canvas used for the graph --
* found by inspection. They work for me, god knows if they'll work
* for anyone else?
*
* (MIN_X,MAX_VALUE) (MAX_X,MAX_VALUE)
* ^
* |
* (MIN_X,MIN_VALUE) ----------> (MAX_X,MIN_VALUE)
*
*/
const MIN_VALUE = 0, MAX_VALUE = 250, MIN_X = 34, MAX_X = 600;
 
function plot(f) {
var period = 2*Math.PI;
var steps = 30;
for (var step=0; step<=steps; step++) {
var x = step/period;
var value = eval(f.replace(/y/g,x));
//
// Translate to the canvas coords:
// - tranlate x and scale
// - invert and reflect the y value with the origin down the middle
//
var canvasx = MIN_X + (MAX_X-MIN_X)*(1.0*step/steps);
var canvasy = -(value*((MAX_VALUE-MIN_VALUE)/2) -
((MAX_VALUE-MIN_VALUE)/2));
setPoint2(canvasx,canvasy,g);
}
}
/**
* Just like the setPoint(event,g,context) function in original
* draw.js, except we don't use the context, which is ignored, and
* just pass in canvasx and canvasy, which are easier to manage than
* creating an event, etc. Seems to work?
*/
function setPoint2(canvasx, canvasy, g) {
var xy = g.toDataCoords(canvasx, canvasy);
var x = xy[0], value = xy[1];
var rows = g.numRows();
var closest_row = -1;
var smallest_diff = -1;
for (var row = 0; row < rows; row++) {
var date = g.getValue(row, 0); // millis
var diff = Math.abs(date - x);
if (smallest_diff < 0 || diff < smallest_diff) {
smallest_diff = diff;
closest_row = row;
}
}
if (closest_row != -1) {
if (lastDrawRow === null) {
lastDrawRow = closest_row;
lastDrawValue = value;
}
// If the mouse moves quickly from point A to point B, we won't get events
// for the intervening x-values. We use a linear interpolation to create
// the impression of smooth drawing.
var coeff = (value - lastDrawValue) / (closest_row - lastDrawRow);
if (closest_row == lastDrawRow) coeff = 0.0;
var minRow = Math.min(lastDrawRow, closest_row);
var maxRow = Math.max(lastDrawRow, closest_row);
for (var row = minRow; row <= maxRow; row++) {
var val = lastDrawValue + coeff * (row - lastDrawRow);
val = Math.max(valueRange[0], Math.min(val, valueRange[1]));
if (val != null && !isNaN(val)) {
data[row][1] = val;
}
}
lastDrawRow = closest_row;
lastDrawValue = value;
g.updateOptions({ file: data }); // this redraws the chart
g.setSelection(closest_row); // prevents the dot from being finnicky.
}
}
 
function main() {
var f = prompt('Enter a function f(y) -- e.g. Math.sin(y):');
plot(f);
}
 
main();
})();

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.