I've been playing with Raphael trying to create a combination of two of his example charts. The first being http://raphaeljs.com/analytics.html which I have working properly, now I'm adding in some elements from http://raphaeljs.com/chart.html as my chart will be a monthly report. I have the forward/back buttons drawing correctly at the top but am having trouble with the click events, if you look at his code in the second example you will see the following:
document.onclicks = function() {
var path = r.parsePathString(values[now]);
var x = path[1][5] - 30;
var y = path[1][6];
path = r.pathToRelative(path);
path[1][0] = "m";
path[1].space(1, 5, 0);
var newvalue = Math.round(Math.random() * 200) - 100;
path = path.join(",") + "c10, 0 10," + newvalue + "20,"+ newvalue;
c.animate({path: path}, 2000);
r.safari();
};
First off, I had to change it to "document.onclick" as nothing happens for me with the plural form (not even sure how it works on his page). Now it fires but gives me the following javascript error:
Error: r.parsePathString is not a function
Which points to the second line in the above code block. I updated my version of raphael.js as I was using an old version (0.7 ish) and am now using the same one as what's in his example (1.4.7). My google-fu skills have turned up nothing.
Here is my HTML for the page, I stripped out some irrelevant stuff and all the corporate identity stuff:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Demo Graph</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico">
<script type="text/javascript"
src="scripts/dojo/dojo.js"
djConfig="parseOnLoad:true,
locale:'en-us',
extraLocale:['en-us']"
>
</script>
<style type="text/css" media="screen" title="main">
@import url(styles/main.css);
</style>
<style type="text/css" media="screen">
@import url(styles/menu.css);
</style>
<link id="themeStyles" rel="stylesheet" href="scripts/dijit/themes/soria/soria.css">
<script language="javascript" type="text/javascript" src="scripts/submenu.js"></script>
<script type="text/javascript" src="scripts/common.js"></script>
<!--[if IE 6]>
<style type="text/css" media="screen">
@import url(styles/ie6.css);
</style>
<![endif]-->
<!--[if IE 7]>
<style type="text/css" media="screen">
@import url(styles/ie7.css);
</style>
<![endif]-->
<!--[if IE 8]>
<style type="text/css" media="screen">
@import url(styles/ie8.css);
</style>
<![endif]-->
</head>
<body class="soria">
<div id="container">
<div id="header">
<a href="/" class="header_image"><img src="images/header.jpg" class="header_image" border="0" /></a>
</div>
<div class="menu">
<ul>
<li><a href="?action=home" class="menu_loner" onMouseOver="submenu_display('home');" onMouseOut="submenu_clear();">Home</a></li>
<li><a href="?action=accounts" class="menu_loner" onMouseOver="submenu_display('accounts');" onMouseOut="submenu_clear();">Accounts</a></li>
<li><a href="?action=download" class="menu_loner" onMouseOver="submenu_display('download');" onMouseOut="submenu_clear();">Download</a></li>
</ul>
</div>
<div id="submenu">
</div>
<div id="content">
<h1>
<a href="?action=help#reports"><img src="images/icon_help.jpg" title="Help" alt="Help" id="help" /></a>
Month Graph
</h1>
<!-- Raphael Stuff starts here -->
<script src="/scripts/raphael.js" type="text/javascript"></script>
<script src="/scripts/plugins/raphael.path.methods.js" type="text/javascript"></script> <!-- not sure where I found this, it's not on either example but my page wont work without it-->
<script src="/scripts/jquery.js" type="text/javascript"></script>
<script src="/scripts/analytics.js" type="text/javascript"></script>
<table id="data" style="width:700px;visibility:hidden;opacity:0;color:#000000;">
<tfoot>
<tr>
<th>1</th>
<th>2</th>
<th>3</th>
<th>4</th>
<th>5</th>
<th>6</th>
<th>7</th>
<th>8</th>
<th>9</th>
<th>10</th>
<th>11</th>
<th>12</th>
<th>13</th>
<th>14</th>
<th>15</th>
<th>16</th>
<th>17</th>
<th>18</th>
<th>19</th>
<th>19</th>
<th>20</th>
<th>22</th>
<th>23</th>
<th>24</th>
<th>25</th>
<th>26</th>
<th>27</th>
<th>28</th>
<th>29</th>
<th>30</th>
<th>31</th>
</tr>
</tfoot>
<tbody>
<tr>
<td>8</td>
<td>25</td>
<td>27</td>
<td>25</td>
<td>54</td>
<td>59</td>
<td>79</td>
<td>47</td>
<td>27</td>
<td>44</td>
<td>44</td>
<td>51</td>
<td>56</td>
<td>8</td>
<td>12</td>
<td>9</td>
<td>25</td>
<td>12</td>
<td>20</td>
<td>8</td>
<td>60</td>
<td>29</td>
<td>7</td>
<td>33</td>
<td>56</td>
<td>25</td>
<td>11</td>
<td>78</td>
<td>70</td>
<td>68</td>
<td>26</td>
</tr>
</tbody>
</table>
<div id="holder"></div>
</div>
<!-- End Raphael Stuff -->
<div id="footer">
<img src="images/footer.jpg" />
</div>
</div>
</body>
</html>
And here is my JavaScript for analytics.js, which is what drives this chart:
Raphael.fn.drawGrid = function (x, y, w, h, wv, hv, color) {
color = color || "#000";
var path = ["M", x, y, "L", x + w, y, x + w, y + h, x, y + h, x, y],
rowHeight = h / hv,
columnWidth = w / wv;
for (var i = 1; i < hv; i++) {
path = path.concat(["M", x, y + i * rowHeight, "L", x + w, y + i * rowHeight]);
}
for (var i = 1; i < wv; i++) {
path = path.concat(["M", x + i * columnWidth, y, "L", x + i * columnWidth, y + h]);
}
return this.path(path.join(",")).attr({stroke: color});
};
$(function () {
$("#data").css({
position: "absolute",
left: "-9999em",
top: "-9999em"
});
});
window.onload = function () {
// Grab the data
var labels = [];
var data = [];
var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
// Build Legend Data
$("#data tfoot th").each(function () {
labels.push($(this).html());
});
// Build Chart Data
$("#data tbody td").each(function () {
data.push($(this).html());
});
// Draw
var width = 700;
var height = 250;
var leftgutter = 10;
var bottomgutter = 20;
var topgutter = 20;
var colorhue = .6 || Math.random();
var color = "hsb(" + [colorhue, 1, .75] + ")"; // shading colour
var r = Raphael("holder", width, height);
var legend_style = {font: '12px Fontin-Sans, Arial', fill: "#000000", 'font-weight' : "bold"};
var label_top_color = {font: '12px Fontin-Sans, Arial', fill: "#FFFFFF"};
var label_bottom_color = {font: '10px Fontin-Sans, Arial', fill: "#FFFFFF"};
X = (width - leftgutter) / labels.length;
max = Math.max.apply(Math, data);
Y = (height - bottomgutter - topgutter) / max;
// Draw Grid Pattern
//r.drawGrid(leftgutter + X * .5, topgutter, width - leftgutter - X, height - topgutter - bottomgutter, 10, 10, "#333");
var path = r.path().attr({stroke: color, "stroke-width": 4, "stroke-linejoin": "round"});
var bgp = r.path().attr({stroke: "none", opacity: .3, fill: color}).moveTo(leftgutter + X * .5, height - bottomgutter);
var frame = r.rect(10, 10, 100, 40, 5).attr({fill: "#000", stroke: "#474747", "stroke-width": 2}).hide();
var label = [];
var is_label_visible = false;
var leave_timer;
var blanket = r.set();
// Set default text for Hover Overs
label[0] = r.text(60, 10, "24 baskets").attr(label_top_color).hide();
label[1] = r.text(60, 40, "22 September 2008").attr(label_bottom_color).attr({fill: color}).hide();
// Draw nodes on graph
for (var i = 0, ii = labels.length; i < ii; i++) {
var y = Math.round(height - bottomgutter - Y * data[i]);
var x = Math.round(leftgutter + X * (i + .5));
var t = r.text(x, height - 6, labels[i]).attr(legend_style).toBack();
bgp[i == 0 ? "lineTo" : "cplineTo"](x, y, 10);
path[i == 0 ? "moveTo" : "cplineTo"](x, y, 10);
var dot = r.circle(x, y, 5).attr({fill: color, stroke: "#000"});
blanket.push(r.rect(leftgutter + X * i, 0, X, height - bottomgutter).attr({stroke: "none", fill: "#fff", opacity: 0}));
var rect = blanket[blanket.length - 1];
// Node Hovering
(function (x, y, data, lbl, dot) {
var timer, i = 0;
$(rect.node).hover(function () { // Hover ON
clearTimeout(leave_timer);
var newcoord = {x: +x + 7.5, y: y - 19};
if (newcoord.x + 100 > width) {
newcoord.x -= 114;
}
frame.show().animate({x: newcoord.x, y: newcoord.y}, 200 * is_label_visible);
// Define popup info for node
label[0].attr({text: data + " baskets" + ((data % 10 == 1) ? "" : "s")}).show().animateWith(frame, {x: +newcoord.x + 50, y: +newcoord.y + 12}, 200 * is_label_visible);
label[1].attr({text: lbl + " September 2010"}).show().animateWith(frame, {x: +newcoord.x + 50, y: +newcoord.y + 27}, 200 * is_label_visible);
dot.attr("r", 7);
is_label_visible = true;
}, function () { // Hover OFF
dot.attr("r", 5);
leave_timer = setTimeout(function () {
frame.hide();
label[0].hide();
label[1].hide();
is_label_visible = false;
// r.safari();
}, 1);
});
})(x, y, data[i], labels[i], dot);
}
// Build Month Selector
var current_date = new Date();
var now = current_date.getMonth();
var month_bg = r.rect(283, 14, 134, 26, 13).attr({fill: '#AAC0E3', 'stroke': 'none'});
var left_circle = r.circle(296, 27, 10).attr({'fill' : '#004CBF', 'stroke' : 'none'});
var left_triangle = r.path("M300, 22l-10,5 10, 5z").attr({'fill' : '#FFF'});
var right_circle = r.circle(404, 27, 10).attr({'fill' : '#004CBF', 'stroke' : 'none'});
var right_triangle = r.path("M400, 22l10,5 -10, 5z").attr({'fill' : '#FFF'});
var c = r.path("M0, 0").attr({'fill' : 'none', 'stroke-width' : 3}); // ?
var bg = r.path("M0, 0").attr({'stroke' : 'none', 'opacity' : .3}); // ?
var dotsy = []; // ?
var clr = [];
var month = r.text(350, 27, months[now]).attr({
'fill' : '#000000',
'stroke' : 'none',
'font' : '100 18px "Helvetica Neue", Helvetica, "Arial Unicode MS", Arial, sans-serif'
});
// Build fake data for months
// TODO populate via AJAX
function randomPath(length, j) {
var path = "";
var x = 10;
var y = 0;
dotsy[j] = dotsy[j] || []; // as a side question, anyone know wtf this does?
for(var i = 0; i < length; i++) {
dotsy[j][i] = Math.round(Math.random() * 200);
if(i) {
path += "C" + [x + 10, y, (x += 20) - 10, (y = 240 - dotsy[j][i]), x, y];
} else {
path += "M" + [10, (y = 240 - dotsy[j][i])];
}
}
return path;
}
for(var i = 0; i < 12; i++) {
//data[i] = randomPath(30, i); // fake data
data[i] = 0;
clr[i] = Raphael.getColor(1);
}
c.attr({path: data[0], stroke: clr[0]});
bg.attr({path: data[0] + "L590,250 10, 250z", fill: clr[0]});
var animation = function() {
var time = 500;
if(now == 12) {
now = 0;
}
if(now == 0) {
now = 12;
}
c.animate({path: data[now],stroke: clr[now]}, time, "<>");
bg.animate({ path: data[now] = "L590, 250 10, 250z", fill: clr[now]}, time, "<>");
month.attr({text: months[now]});
};
// Clicked Previous Month
left_circle.node.onclick = left_triangle.node.onclick = function() {
alert('Clicked the circle');
now--;
animation();
};
// Clicked Next Month
right_circle.node.onclick = right_triangle.node.onclick = function() {
alert('Clicked the triangle');
now++;
animation();
};
// Capture Clicks
document.onclick = function() {
var path = r.parsePathString(data[now]);
var x = path[1][5] - 30;
var y = path[1][6];
path = r.pathToRelative(path);
path[1][0] = "m";
path[1].space(1, 5, 0);
var newvalue = Math.round(Math.random() * 200) - 100;
path = path.join(",") + "c10, 0 10," + newvalue + "20,"+ newvalue;
c.animate({path: path}, 2000);
r.safari();
};
bgp.lineTo(x, height - bottomgutter).andClose();
frame.toFront();
label[0].toFront();
label[1].toFront();
blanket.toFront();
};
Thanks in advance for any help!