Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Joshua Carver
committed
Nov 10, 2011
0 parents
commit d4af9f0
Showing
5 changed files
with
314 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,143 @@ | |||
var global = window | |||
|
|||
if (global.module == undefined) { | |||
global.module = function(name, body) { | |||
var exports = global[name] | |||
if (exports == undefined) { | |||
global[name] = exports = {} | |||
} | |||
body(exports) | |||
} | |||
} | |||
|
|||
|
|||
module('Charts', function(exports) { | |||
var Point, create_random_points, draw_bars, draw_bezier_path, get_control_points, get_derivitive, get_ranges_for_points, scale_points; | |||
Point = (function() { | |||
function Point(x, y) { | |||
this.x = x; | |||
this.y = y; | |||
} | |||
return Point; | |||
})(); | |||
get_ranges_for_points = function(points) { | |||
var max_x, max_y, min_x, min_y, point, xs, ys, _i, _len; | |||
xs = []; | |||
ys = []; | |||
for (_i = 0, _len = points.length; _i < _len; _i++) { | |||
point = points[_i]; | |||
xs.push(point.x); | |||
ys.push(point.y); | |||
} | |||
max_x = Math.max.apply(Math.max, xs); | |||
max_y = Math.max.apply(Math.max, ys); | |||
min_x = Math.min.apply(Math.max, xs); | |||
min_y = Math.min.apply(Math.max, ys); | |||
return [max_x, min_x, max_y, min_y]; | |||
}; | |||
scale_points = function(width, height, points, padding) { | |||
var max_x, max_y, min_x, min_y, padded_height_range, padded_width_range, point, scaled_points, sx, sy, x_range, x_scaling_factor, y_range, y_scaling_factor, _i, _len, _ref; | |||
_ref = get_ranges_for_points(points), max_x = _ref[0], min_x = _ref[1], max_y = _ref[2], min_y = _ref[3]; | |||
padded_width_range = width - 2 * padding; | |||
padded_height_range = height - 2 * padding; | |||
x_range = max_x - min_x; | |||
y_range = max_y - min_y; | |||
x_scaling_factor = padded_width_range / x_range; | |||
y_scaling_factor = padded_height_range / y_range; | |||
scaled_points = []; | |||
for (_i = 0, _len = points.length; _i < _len; _i++) { | |||
point = points[_i]; | |||
sx = x_scaling_factor * point.x + padding; | |||
sy = y_scaling_factor * point.y + padding; | |||
scaled_points.push(new Point(sx, sy)); | |||
} | |||
return scaled_points; | |||
}; | |||
get_derivitive = function(points, i, tension) { | |||
var tension_factor; | |||
if (points.length < 2) { | |||
throw "Error"; | |||
} | |||
tension_factor = 1 - tension; | |||
if (i === 0) { | |||
return new Point((points[1].x - points[0].x) * tension_factor, (points[1].y - points[0].y) * tension_factor); | |||
} else if (i === (points.length - 1)) { | |||
return new Point((points[i].x - points[i - 1].x) * tension_factor, (points[i].y - points[i - 1].y) * tension_factor); | |||
} else { | |||
return new Point((points[i + 1].x - points[i - 1].x) * tension_factor, (points[i + 1].y - points[i - 1].y) * tension_factor); | |||
} | |||
}; | |||
get_control_points = function(points, i, tension) { | |||
var b1, b2, d1, d2; | |||
if (tension == null) { | |||
tension = 0.7; | |||
} | |||
d1 = get_derivitive(points, i, tension); | |||
d2 = get_derivitive(points, i + 1, tension); | |||
b1 = new Point(points[i].x + d1.x / 3, points[i].y + d1.y / 3); | |||
b2 = new Point(points[i + 1].x - d2.x / 3, points[i + 1].y - d2.y / 3); | |||
return [b1, b2]; | |||
}; | |||
create_random_points = function() { | |||
var i, points; | |||
points = (function() { | |||
var _results; | |||
_results = []; | |||
for (i = 0; i <= 25; i++) { | |||
_results.push(new Point(i, i * (i - 5))); | |||
} | |||
return _results; | |||
})(); | |||
points.push(new Point(26, 30)); | |||
points.push(new Point(27, 300)); | |||
points.push(new Point(28, 800)); | |||
points.push(new Point(29, 500)); | |||
points.push(new Point(30, 600)); | |||
points.push(new Point(31, 610)); | |||
points.push(new Point(32, 620)); | |||
return scale_points(1000, 300, points, 20); | |||
}; | |||
draw_bezier_path = function(r, points) { | |||
var b1, b2, dot, i, path, point, _len, _ref; | |||
path = ""; | |||
for (i = 0, _len = points.length; i < _len; i++) { | |||
point = points[i]; | |||
dot = r.circle(point.x, point.y, 3); | |||
dot.attr("fill", "#00aadd"); | |||
if (i === 0) { | |||
path += "M" + point.x + "," + point.y; | |||
} else { | |||
_ref = get_control_points(points, i - 1), b1 = _ref[0], b2 = _ref[1]; | |||
path += "M" + points[i - 1].x + "," + points[i - 1].y + " C" + b1.x + "," + b1.y + " " + b2.x + "," + b2.y + " " + points[i].x + "," + points[i].y; | |||
} | |||
} | |||
return r.path(path); | |||
}; | |||
draw_bars = function(r, points) { | |||
var i, point, rect, x, _len, _results; | |||
x = points[0].x; | |||
_results = []; | |||
for (i = 0, _len = points.length; i < _len; i++) { | |||
point = points[i]; | |||
rect = r.rect(x - 15, point.y, 15, 300 - point.y); | |||
x += 16; | |||
_results.push(rect.attr({ | |||
"fill": "#00aadd", | |||
"stroke": "transparent", | |||
"stroke-width": "0" | |||
})); | |||
} | |||
return _results; | |||
}; | |||
window.onload = function() { | |||
var chart, chart2, points, r, r2; | |||
chart = document.getElementById('chart'); | |||
chart2 = document.getElementById('chart2'); | |||
points = create_random_points(); | |||
r = Raphael(chart, 1000, 300); | |||
r2 = Raphael(chart2, 1000, 300); | |||
draw_bezier_path(r, points); | |||
draw_bars(r2, points); | |||
return exports.create_random_points = create_random_points; | |||
}; | |||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,19 @@ | |||
<!DOCTYPE HTML> | |||
|
|||
<html> | |||
<head> | |||
<script type="text/javascript" src="vendor/raphael.min.js"></script> | |||
<script type="text/javascript" src="compiled/charts.js"></script> | |||
<style type="text/css"> | |||
body { padding: 20px; } | |||
</style> | |||
</head> | |||
<body> | |||
<h1>Chart</h1> | |||
<div style="width:1000px; height: 300px;" id="chart"> | |||
</div> | |||
|
|||
<div style="width:1000px; height: 300px;" id="chart2"> | |||
</div> | |||
</body> | |||
</head> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,144 @@ | |||
class Point | |||
constructor: (@x, @y) -> | |||
|
|||
get_ranges_for_points = (points) -> | |||
xs = [] | |||
ys = [] | |||
|
|||
for point in points | |||
xs.push(point.x) | |||
ys.push(point.y) | |||
|
|||
max_x = Math.max.apply(Math.max, xs) | |||
max_y = Math.max.apply(Math.max, ys) | |||
|
|||
min_x = Math.min.apply(Math.max, xs) | |||
min_y = Math.min.apply(Math.max, ys) | |||
|
|||
[max_x, min_x, max_y, min_y] | |||
|
|||
|
|||
# Scale algorithm: | |||
# (newMax - newMin) / (dataMax - dataMin) * dataPoint + newMin | |||
scale_points = (width, height, points, padding) -> | |||
[max_x, min_x, max_y, min_y] = get_ranges_for_points(points) | |||
|
|||
# 2x padding for top + bottom of axis | |||
# newMax = width - padding | |||
# newMin = padding | |||
# newMax - newMin = width - 2*padding | |||
padded_width_range = width - 2*padding | |||
padded_height_range = height - 2*padding | |||
|
|||
x_range = max_x - min_x | |||
y_range = max_y - min_y | |||
|
|||
# ratio = (newMax - newMin) / (oldMax - oldMin) | |||
x_scaling_factor = padded_width_range / x_range | |||
y_scaling_factor = padded_height_range / y_range | |||
|
|||
scaled_points = [] | |||
|
|||
for point in points | |||
# v * ratio + newMin | |||
sx = x_scaling_factor * point.x + padding | |||
sy = y_scaling_factor * point.y + padding | |||
|
|||
scaled_points.push(new Point(sx, sy)) | |||
|
|||
scaled_points | |||
|
|||
|
|||
get_derivitive = (points, i, tension) -> | |||
throw "Error" if points.length < 2 | |||
|
|||
tension_factor = 1 - tension | |||
|
|||
if i == 0 | |||
new Point( | |||
(points[1].x - points[0].x) * tension_factor, | |||
(points[1].y - points[0].y) * tension_factor | |||
) | |||
|
|||
else if i == (points.length-1) | |||
new Point( | |||
(points[i].x - points[i-1].x) * tension_factor, | |||
(points[i].y - points[i-1].y) * tension_factor | |||
) | |||
|
|||
else | |||
new Point( | |||
(points[i+1].x - points[i-1].x) * tension_factor, | |||
(points[i+1].y - points[i-1].y) * tension_factor | |||
) | |||
|
|||
|
|||
get_control_points = (points, i, tension = 0.7) -> | |||
d1 = get_derivitive(points, i, tension) | |||
d2 = get_derivitive(points, i+1, tension) | |||
|
|||
b1 = new Point( | |||
points[i].x + d1.x / 3, | |||
points[i].y + d1.y / 3 | |||
) | |||
|
|||
b2 = new Point( | |||
points[i+1].x - d2.x / 3, | |||
points[i+1].y - d2.y / 3 | |||
) | |||
|
|||
[b1, b2] | |||
|
|||
|
|||
create_random_points = -> | |||
points = (new Point(i, i*(i-5)) for i in [0..25]) | |||
points.push(new Point(26, 30)) | |||
points.push(new Point(27, 300)) | |||
points.push(new Point(28, 800)) | |||
points.push(new Point(29, 500)) | |||
points.push(new Point(30, 600)) | |||
points.push(new Point(31, 610)) | |||
points.push(new Point(32, 620)) | |||
|
|||
scale_points(1000, 300, points, 20) | |||
|
|||
|
|||
draw_bezier_path = (r, points) -> | |||
path = "" | |||
for point, i in points | |||
dot = r.circle(point.x, point.y, 3) | |||
dot.attr("fill", "#00aadd") | |||
if i == 0 | |||
path += "M#{point.x},#{point.y}" | |||
else | |||
[b1, b2] = get_control_points(points, i-1) | |||
path += "M#{points[i-1].x},#{points[i-1].y} C#{b1.x},#{b1.y} #{b2.x},#{b2.y} #{points[i].x},#{points[i].y}" | |||
|
|||
r.path(path) | |||
|
|||
draw_bars = (r, points) -> | |||
x = points[0].x | |||
for point, i in points | |||
rect = r.rect(x-15, point.y, 15, 300 - point.y) | |||
x += 16 | |||
|
|||
rect.attr({ | |||
"fill" : "#00aadd", | |||
"stroke" : "transparent", | |||
"stroke-width": "0" | |||
}) | |||
|
|||
|
|||
window.onload = () -> | |||
chart = document.getElementById('chart') | |||
chart2 = document.getElementById('chart2') | |||
points = create_random_points() | |||
r = Raphael(chart, 1000, 300) | |||
r2 = Raphael(chart2, 1000, 300) | |||
|
|||
draw_bezier_path(r, points) | |||
draw_bars(r2, points) | |||
|
|||
|
|||
|
|||
exports.create_random_points = create_random_points |
Large diffs are not rendered by default.
Oops, something went wrong.