Skip to content

Instantly share code, notes, and snippets.

@ozydingo
Last active February 3, 2018 23:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ozydingo/6b7b3c6504cd1dfc2693daabbdaa14e8 to your computer and use it in GitHub Desktop.
Save ozydingo/6b7b3c6504cd1dfc2693daabbdaa14e8 to your computer and use it in GitHub Desktop.
Barebones js x,y graph using canvas element
function Graph2(canvas) {
if (canvas.tagName !== 'CANVAS') { throw 'Graph2 requires a canvas element'; }
this.canvas = canvas;
this.cursor = canvas.getContext("2d");
this.axes = {
display: false,
xlim: [-1, 1],
ylim: [-1, 1],
}
this.paths = [];
this.clear_canvas();
};
Graph2.prototype = {
axis: function(val) {
if (val === undefined) { return this.axes; }
this.axes.display = !!val;
this.redraw();
return this.axes;
},
path: function(path) {
this.validate_path(path);
this.paths[this.paths.length] = path;
this.draw_path(path);
},
xlim: function(low, high) {
if (typeof(low) !== 'number' || typeof(high) !== 'number') {
throw 'Invalid xlim: numeric type required.'
}
this.axes.xlim = [low, high];
this.redraw();
},
ylim: function(low, high) {
if (typeof(low) !== 'number' || typeof(high) !== 'number') {
throw 'Invalid ylim: numeric type required.'
}
this.axes.ylim = [low, high];
this.redraw();
},
//---------private-ish-----------//
clear_canvas: function() {
this.canvas.width = this.canvas.width;
},
redraw: function() {
var graph = this;
this.clear_canvas();
if (this.axes.display) { this.draw_axes(); }
this.paths.forEach(function(path) { graph.draw_path(path)});
},
draw_axes: function () {
this.draw_path([[this.axes.xlim[0], 0], [this.axes.xlim[1], 0]]);
this.draw_path([[0, this.axes.ylim[0]], [0, this.axes.ylim[1]]]);
},
draw_path: function(path) {
var graph = this;
var pencil_down = false;
path.forEach(function(xy, index) {
if (graph.is_point_in_view(xy)) {
if (pencil_down) {
graph.cursor.lineTo(graph.x_to_px(xy[0]), graph.y_to_px(xy[1]));
} else {
pencil_down = true;
graph.cursor.moveTo(graph.x_to_px(xy[0]), graph.y_to_px(xy[1]));
}
} else {
if (pencil_down) { graph.cursor.stroke(); }
pencil_down = false
}
});
if (pencil_down) { graph.cursor.stroke(); }
},
is_point_in_view: function(xy) {
return (
xy[0] >= this.axes.xlim[0] && xy[0] <= this.axes.xlim[1] &&
xy[1] >= this.axes.ylim[0] && xy[1] <= this.axes.ylim[1]
);
},
x_to_px: function(x) {
return (x - this.axes.xlim[0]) / (this.axes.xlim[1] - this.axes.xlim[0]) * this.canvas.width;
},
y_to_px: function(y) {
return (this.axes.ylim[1] - y) / (this.axes.ylim[1] - this.axes.ylim[0]) * this.canvas.height;
},
validate_path: function(path) {
path.forEach(function(xy, idx) {
if (
typeof(xy) !== 'object' ||
xy.length !== 2
) { throw 'Invalid path: must be array of [x,y] pairs.' }
if (typeof(xy[0]) !== 'number' || typeof(xy[1]) !== 'number') {
throw 'Invalid path: numeric data pairs required (received ' + typeof(xy[0]) + ', ' + typeof(xy[1]) + ').'
}
})
},
}
// Example usage: requires a <canvas> element on the page!!
var sigmoid = function(x) { return 1 / (1 + Math.exp(-x)) };
data = new Array(50);
for (ii=0; ii<data.length; ii++) {
data[ii] = [(ii-25)/25, sigmoid(5*(ii-25)/25) - 0.2]
}
var canvas = $("canvas")[0];
var graph = new Graph2(canvas);
graph.axis(true);
graph.path(data)
graph.ylim(-0.3, 1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment