Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

first commit

  • Loading branch information...
commit 57755b11ff29f9416ff39b5dd2bffe9599ddeef1 0 parents
Alex Young authored
0  README.textile
Source Rendered
No changes.
251 ico.js
... ... @@ -0,0 +1,251 @@
  1 +/* Returns a suitable set of labels for given data points on the Y axis */
  2 +function labelStep(data) {
  3 + var min = data.min(),
  4 + max = data.max(),
  5 + range = max - min,
  6 + step = 0;
  7 +
  8 + if (range < 2) {
  9 + step = 0.1;
  10 + } else if (range < 5) {
  11 + step = 1;
  12 + } else if (range < 50) {
  13 + step = 5;
  14 + } else if (range < 100) {
  15 + step = 10;
  16 + } else {
  17 + step = Math.pow(10, (Math.log(range) / Math.LN10).round() - 1);
  18 + }
  19 +
  20 + return step;
  21 +}
  22 +
  23 +var Sparkline = Class.create({
  24 + initialize: function(element, data) {
  25 + this.element = element;
  26 + this.data = data;
  27 + this.width = 30;
  28 + this.height = 12;
  29 + this.step = this.calculateStep();
  30 + this.paper = Raphael(this.element, this.width, this.height);
  31 + this.background = this.paper.rect(0, 0, this.width, this.height);
  32 + this.background.attr({fill: "#ccc", stroke: null });
  33 + this.draw();
  34 + },
  35 +
  36 + calculateStep: function() {
  37 + return this.width / (this.data.length - 1);
  38 + },
  39 +
  40 + normalisedData: function() {
  41 + return $A(this.data).collect(function(value) {
  42 + return this.normalise(value);
  43 + }.bind(this))
  44 + },
  45 +
  46 + normalise: function(value) {
  47 + return (this.height / this.data.max()) * value;
  48 + },
  49 +
  50 + draw: function() {
  51 + var data = this.normalisedData();
  52 + var line = this.paper.path({stroke: "#036"}).moveTo(0, this.height - data.first());
  53 + var x = 0;
  54 + $A(data.slice(1)).each(function(value) {
  55 + x = x + this.step;
  56 + line.lineTo(x, this.height - value);
  57 + }.bind(this))
  58 + }
  59 +});
  60 +
  61 +
  62 +var LineGraph = Class.create({
  63 + initialize: function(element, data, colours) {
  64 + this.element = element;
  65 +
  66 + this.dataSets = Object.isArray(data) ? new Hash({ one: data }) : $H(data);
  67 + this.flatData = this.dataSets.collect(function(dataSet) { return dataSet[1] }).flatten();
  68 + this.range = this.calculateRange();
  69 + this.dataSize = this.longestDataSetLength();
  70 + this.showHorizontalLabels = true;
  71 + this.showVerticalLabels = true;
  72 +
  73 + this.labels = $A($R(1, this.dataSize));
  74 +
  75 + this.width = parseInt(element.getStyle('width'));
  76 + this.height = parseInt(element.getStyle('height'));
  77 +
  78 + /* Sets how curvy lines are */
  79 + this.curve_amount = 10;
  80 +
  81 + /* Padding for the chart lines */
  82 + this.plot_padding = 10;
  83 +
  84 + /* Label font size */
  85 + this.fontSize = 10;
  86 +
  87 + /* Line colours */
  88 + this.colours = colours ? colours : this.makeRandomColours();
  89 +
  90 + /* Padding around the graph area to make room for labels */
  91 + this.x_padding_left = 10 + this.paddingLeftOffset();
  92 + this.x_padding_right = 20;
  93 + this.x_padding = this.x_padding_left + this.x_padding_right;
  94 + this.y_padding_top = 20;
  95 + this.y_padding_bottom = 20 + this.paddingBottomOffset();
  96 + this.y_padding = this.y_padding_top + this.y_padding_bottom;
  97 +
  98 + this.label_colour = '#666';
  99 +
  100 + this.graph_width = this.width - (this.x_padding);
  101 + this.graph_height = this.height - (this.y_padding);
  102 +
  103 + this.step = this.calculateStep();
  104 + this.paper = Raphael(this.element, this.width, this.height);
  105 + this.background = this.paper.rect(this.x_padding_left, this.y_padding_top, this.graph_width, this.graph_height);
  106 + this.background.attr({fill: "#fff", stroke: null });
  107 + this.draw();
  108 + },
  109 +
  110 + makeRandomColours: function(number) {
  111 + var colours = {};
  112 + this.dataSets.each(function(data) {
  113 + colours[data[0]] = Raphael.hsb2rgb(Math.random(), 1, .75).hex;
  114 + });
  115 + return colours;
  116 + },
  117 +
  118 + longestDataSetLength: function() {
  119 + var length = 0;
  120 + this.dataSets.each(function(dataSet) {
  121 + length = dataSet[1].length > length ? dataSet[1].length : length;
  122 + });
  123 + return length;
  124 + },
  125 +
  126 + roundValue: function(value, length) {
  127 + var multiplier = Math.pow(10, length);
  128 + value *= multiplier;
  129 + value = Math.round(value) / multiplier;
  130 + return value;
  131 + },
  132 +
  133 + roundValues: function(data, length) {
  134 + return $A(data).collect(function(value) { return this.roundValue(value, length) }.bind(this));
  135 + },
  136 +
  137 + paddingLeftOffset: function() {
  138 + /* Find the longest label and multiply it by the font size */
  139 + var data = this.flatData;
  140 + if (this.range < 2) {
  141 + // Round values
  142 + data = this.roundValues(data, 2);
  143 + }
  144 +
  145 + var longest_label_length = $A(data).sort(function(a, b) { return a.toString().length < b.toString().length }).first().toString().length;
  146 + longest_label_length = longest_label_length > 2 ? longest_label_length - 1 : longest_label_length;
  147 + return longest_label_length * this.fontSize;
  148 + },
  149 +
  150 + paddingBottomOffset: function() {
  151 + /* Find the longest label and multiply it by the font size */
  152 + return this.fontSize;
  153 + },
  154 +
  155 + calculateStep: function() {
  156 + return (this.graph_width - (this.plot_padding * 2)) / (this.dataSize - 1);
  157 + },
  158 +
  159 + /* Subtract the largest and smallest values from the data sets */
  160 + calculateRange: function() {
  161 + var ranges = this.dataSets.collect(function(data) {
  162 + return [data[1].max(), data[1].min()];
  163 + });
  164 + this.max = ranges.sort(function(a, b) { return a[0] > b[0] }).first().first();
  165 + this.min = ranges.sort(function(a, b) { return a[1] < b[1] }).first().last();
  166 +
  167 + return this.max - this.min;
  168 + },
  169 +
  170 + normaliseData: function(data) {
  171 + return $A(data).collect(function(value) {
  172 + return this.normalise(value);
  173 + }.bind(this))
  174 + },
  175 +
  176 + normalise: function(value) {
  177 + if (this.range < 5) {
  178 + return (this.graph_height - this.plot_padding) * value;
  179 + } else {
  180 + return ((this.graph_height - this.plot_padding) / this.max) * value;
  181 + }
  182 + },
  183 +
  184 + draw: function() {
  185 + this.dataSets.each(function(data, index) {
  186 + this.drawLines(data[0], this.colours[data[0]], this.normaliseData(data[1]));
  187 + }.bind(this));
  188 +
  189 + if (this.showVerticalLabels) {
  190 + this.drawVerticalLabels();
  191 + }
  192 +
  193 + if (this.showHorizontalLabels) {
  194 + this.drawHorizontalLabels();
  195 + }
  196 + },
  197 +
  198 + drawLines: function(label, colour, data) {
  199 + var x = this.x_padding_left + this.plot_padding;
  200 + var cursor = this.paper.path({stroke: colour, 'stroke-width': '3px'}).moveTo(x, this.height - data.first() - this.y_padding_bottom);
  201 +
  202 + $A(data.slice(1)).each(function(value) {
  203 + x = x + this.step;
  204 + if (this.curve_amount) {
  205 + cursor.cplineTo(x, this.height - value - this.y_padding_bottom, this.curve_amount);
  206 + } else {
  207 + cursor.lineTo(x, this.height - value - this.y_padding_bottom);
  208 + }
  209 + }.bind(this))
  210 + },
  211 +
  212 + drawVerticalLabels: function() {
  213 + var step = labelStep(this.flatData),
  214 + normalised_step = this.normalise(step),
  215 + x = this.x_padding_left - 1,
  216 + y = this.height - this.y_padding_bottom,
  217 + top = this.y_padding_top + normalised_step,
  218 + label = 0;
  219 + var cursor = this.paper.path({stroke: this.label_colour});
  220 +
  221 + cursor.moveTo(x, y + 1);
  222 + cursor.lineTo(x, this.y_padding_top);
  223 +
  224 + while (y > top) {
  225 + y = y - normalised_step;
  226 + label = this.roundValue((label + step), 2);
  227 + var textOffset = (this.paddingLeftOffset()) - (label.toString().length * (this.fontSize / 4).round());
  228 +
  229 + cursor.moveTo(x, y);
  230 + cursor.lineTo(x - 5, y);
  231 + this.paper.text(textOffset, y + 2, label).attr({"font": this.fontSize + 'px "Arial"', stroke: "none", fill: "#000"}).toBack();
  232 + }
  233 + },
  234 +
  235 + drawHorizontalLabels: function() {
  236 + var limit = this.graph_width + this.x_padding_left,
  237 + x = this.x_padding_left + this.plot_padding,
  238 + y = this.height - this.y_padding_bottom + 1;
  239 + var cursor = this.paper.path({stroke: this.label_colour});
  240 +
  241 + cursor.moveTo(this.x_padding_left - 2, y);
  242 + cursor.lineTo(this.graph_width + this.x_padding_left, y);
  243 +
  244 + for (var i = 0; x < limit; i++) {
  245 + cursor.moveTo(x, y);
  246 + cursor.lineTo(x, y + 5);
  247 + this.paper.text(x, y + this.fontSize + 7, this.labels[i]).attr({"font": this.fontSize + 'px "Arial"', stroke: "none", fill: "#000"}).toBack();
  248 + x = x + this.step;
  249 + }
  250 + }
  251 +});
45 index.html
... ... @@ -0,0 +1,45 @@
  1 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  2 + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  3 +<html>
  4 + <head>
  5 + <title>Raphael Ico</title>
  6 + <script src="prototype.js" type="text/javascript" charset="utf-8"></script>
  7 + <script src="raphael.js" type="text/javascript" charset="utf-8"></script>
  8 + <script src="ico.js" type="text/javascript" charset="utf-8"></script>
  9 + <style type="text/css" media="screen">
  10 +/* Reset */
  11 +html, body, div, ul, ol, li, dl, dt, dd, h1, h2, h3, h4, h5, h6, pre, form, p, blockquote, fieldset, input { margin: 0; padding: 0; }
  12 +h1, h2, h3, h4, h5, h6, pre, code, address, caption, cite, code, em, strong, th { font-size: 1em; font-weight: normal; font-style: normal; }
  13 +fieldset, img { border: none; }
  14 +
  15 +body { font-family: "Lucida Grande", Helvetica, sans-serif; font-size: 12px; background-color: #fff; padding: 0; margin: 10px 5%; color: #000 }
  16 +h1, h2 { font-size: 2em; margin: 0.5em 0; }
  17 +
  18 +.sparkline { width: 30px; height: 14px }
  19 +.linegraph { width: 600px; height: 300px; background-color: #fff; margin-bottom: 20px; }
  20 +
  21 + </style>
  22 + </head>
  23 + <body>
  24 + <h2>Sparklines</h2>
  25 + <p>Sparklines are tiny graphs <span id="sparkline" class="sparkline"></span> that you can use inline. You can use more than one <span id="sparkline_2" class="sparkline"></span> in a document.</p>
  26 +
  27 + <h2>Simple Line Graph</h2>
  28 + <div id="linegraph_4" class="linegraph"></div>
  29 + <div id="linegraph" class="linegraph"></div>
  30 + <div id="linegraph_2" class="linegraph"></div>
  31 + <div id="linegraph_3" class="linegraph"></div>
  32 +
  33 + <script type="text/javascript">
  34 +/* $R(1, 25).collect(function() { return (Math.random() * 100).round() } ) */
  35 +/* [21,41,72,98,67,25,8,31,73,0,91,19,28,81,12,68,88,25,98,51,15,10,96,15,93] */
  36 +var sparkline = new Sparkline($('sparkline'), [21, 41, 32, 1, 10, 5, 32, 10, 23]);
  37 +var sparkline_2 = new Sparkline($('sparkline_2'), [2, 32, 5, 1, 1, 33, 32, 9, 1]);
  38 +
  39 +var linegraph_4 = new LineGraph($('linegraph_4'), $R(1, 25).collect(function() { return (Math.random()) } ));
  40 +var linegraph = new LineGraph($('linegraph'), { one: [2, 5, 1, 10, 15, 33, 20, 25, 1], two: [10, 9, 3, 30, 1, 10, 5, 33, 33], three: [3, 4, 10, 1, 30, 11, 33, 12, 22]}, { one: '#990000', two: '#009900', three: '#000099' });
  41 +var linegraph_2 = new LineGraph($('linegraph_2'), $R(1, 25).collect(function() { return (Math.random() * 100).round() } ));
  42 +var linegraph_3 = new LineGraph($('linegraph_3'), $R(1, 25).collect(function() { return (Math.random() * 10000).round() } ));
  43 + </script>
  44 + </body>
  45 +</html>
4,225 prototype.js
4,225 additions, 0 deletions not shown
2,190 raphael.js
2,190 additions, 0 deletions not shown

0 comments on commit 57755b1

Please sign in to comment.
Something went wrong with that request. Please try again.