I have create a chart to display the visits to a webpage. I have everything working, but I want to change the tooltip the appears when you mouse over one of the circles of data.
I am using Raphael JS and built it of of this: http://www.emirplicanic.com/php/php-visitor-tracking-script-with-jquery-and-raphael-javascript-library
If you click on the link above and scroll down to the bottom of the page this is how my chart works. Mouse over one of the circles and you will notice that it displays the data in a box. I want to add an arrow to the box like a bootstrap tooltip for example.
If you look here: http://raphaeljs.com/analytics.html and mouse over one of the circles you will see the difference. This is what I want.
To view the code plese click the first link and take a look at the PHP Class (class.logger.php) section and look for the function loadraphael in the code. This is what I assume I need to customize, but not sure what to change. Any help with examples would be greatly appreciated.
If you need more info from me, let me know.
EDIT: here is the code. You will notice I changed rect to path. Not sure what else I should change.
//raphael.path.methods.js
Raphael.el.isAbsolute = true;
Raphael.el.absolutely = function () {
this.isAbsolute = 1;
return this;
};
Raphael.el.relatively = function () {
this.isAbsolute = 0;
return this;
};
Raphael.el.moveTo = function (x, y) {
this._last = {x: x, y: y};
return this.attr({path: this.attrs.path + ["m", "M"][+this.isAbsolute] + parseFloat(x) + " " + parseFloat(y)});
};
Raphael.el.lineTo = function (x, y) {
this._last = {x: x, y: y};
return this.attr({path: this.attrs.path + ["l", "L"][+this.isAbsolute] + parseFloat(x) + " " + parseFloat(y)});
};
Raphael.el.arcTo = function (rx, ry, large_arc_flag, sweep_flag, x, y, angle) {
this._last = {x: x, y: y};
return this.attr({path: this.attrs.path + ["a", "A"][+this.isAbsolute] + [parseFloat(rx), parseFloat(ry), +angle, large_arc_flag, sweep_flag, parseFloat(x), parseFloat(y)].join(" ")});
};
Raphael.el.curveTo = function () {
var args = Array.prototype.splice.call(arguments, 0, arguments.length),
d = [0, 0, 0, 0, "s", 0, "c"][args.length] || "";
this.isAbsolute && (d = d.toUpperCase());
this._last = {x: args[args.length - 2], y: args[args.length - 1]};
return this.attr({path: this.attrs.path + d + args});
};
Raphael.el.cplineTo = function (x, y, w) {
this.attr({path: this.attrs.path + ["C", this._last.x + w, this._last.y, x - w, y, x, y]});
this._last = {x: x, y: y};
return this;
};
Raphael.el.qcurveTo = function () {
var d = [0, 1, "t", 3, "q"][arguments.length],
args = Array.prototype.splice.call(arguments, 0, arguments.length);
if (this.isAbsolute) {
d = d.toUpperCase();
}
this._last = {x: args[args.length - 2], y: args[args.length - 1]};
return this.attr({path: this.attrs.path + d + args});
};
Raphael.el.addRoundedCorner = function (r, dir) {
var rollback = this.isAbsolute;
rollback && this.relatively();
this._last = {x: r * (!!(dir.indexOf("r") + 1) * 2 - 1), y: r * (!!(dir.indexOf("d") + 1) * 2 - 1)};
this.arcTo(r, r, 0, {"lu": 1, "rd": 1, "ur": 1, "dl": 1}[dir] || 0, this._last.x, this._last.y);
rollback && this.absolutely();
return this;
};
Raphael.el.andClose = function () {
return this.attr({path: this.attrs.path + "z"});
};
//raphael analytics
Raphael.fn.drawGrid = function (x, y, w, h, wv, hv, color) {
color = color || "'.$fillcolor.'";
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 () {
$(".'.$tableid.'").css({
position: "absolute",
left: "-9999em",
top: "-9999em"
});
});
window.onload = function () {
// Grab the data
var labels = [],
data = [];
$(".'.$tableid.' tfoot th").each(function () {
labels.push($(this).html());
});
$(".'.$tableid.' tbody td").each(function () {
data.push($(this).html());
});
// Draw
var width = '.$width.',
height = '.$height.',
leftgutter = '.$leftgutter.',
bottomgutter = '.$bottomgutter.',
topgutter = '.$topgutter.',
colorhue = .6 || Math.random(),
color = "hsb(" + [colorhue, 1, .75] + ")",
r = Raphael("'.$div.'", width, height),
txt = {font: \'12px Fontin-Sans, Arial\', fill: "'.$fontcolor.'"},
txt1 = {font: \'10px Fontin-Sans, Arial\', fill: "'.$fontcolor.'"},
txt2 = {font: \'12px Fontin-Sans, Arial\', fill: "'.$fontcolor.'"},
X = (width - leftgutter) / labels.length,
max = Math.max.apply(Math, data),
Y = (height - bottomgutter - topgutter) / max;
r.drawGrid(leftgutter + X * .5, topgutter, width - leftgutter - X, height - topgutter - bottomgutter, 10, 10, "'.$gridcolor.'");
var path = r.path().attr({stroke: "'.$strokecolor.'", "stroke-width": 4, "stroke-linejoin": "round"}),
bgp = r.path().attr({stroke: "'.$strokecolor.'", opacity: .3, fill: "'.$fillcolor.'"}).moveTo(leftgutter + X * .5, height - bottomgutter),
frame = r.path("M25,15 q 0,-5 5,-5 l 90,0 q 5,0 5,5 l 0,30 q 0,5 -5,5 l -90,0 q -5,0 -5,-5 l 0,-5 -14.1,-10 14.1,-10z").attr({fill: "'.$datafillcolor.'", stroke: "'.$datastrokecolor.'", "stroke-width": 2}).hide(),
label = [],
is_label_visible = false,
leave_timer,
blanket = r.set();
label[0] = r.text(60, 10, "24 hits").attr(txt).hide();
label[1] = r.text(60, 40, "22 September 2008").attr(txt1).attr({fill: "'.$fontcolor.'"}).hide();
for (var i = 0, ii = labels.length; i < ii; i++) {
var y = Math.round(height - bottomgutter - Y * data[i]),
x = Math.round(leftgutter + X * (i + .5)),
t = r.text(x, height - 6, labels[i]).attr(txt).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: "'.$dotfillcolor.'", stroke: "'.$dotstrokecolor.'", "stroke-width": 2});
blanket.push(r.rect(leftgutter + X * i, 0, X, height - bottomgutter).attr({stroke: "none", fill: "'.$fontcolor.'", opacity: 0}));
var rect = blanket[blanket.length - 1];
(function (x, y, data, lbl, dot) {
var timer, i = 0;
$(rect.node).hover(function () {
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);
label[0].attr({text: data + " hit" + ((data % 10 == 1) ? "" : "s")}).show().animateWith(frame, {x: +newcoord.x + 50, y: +newcoord.y + 12}, 200 * is_label_visible);
label[1].attr({text: lbl + " '.$month_year.'"}).show().animateWith(frame, {x: +newcoord.x + 50, y: +newcoord.y + 27}, 200 * is_label_visible);
dot.attr("r", 7);
is_label_visible = true;
}, function () {
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);
}
bgp.lineTo(x, height - bottomgutter).andClose();
frame.toFront();
label[0].toFront();
label[1].toFront();
blanket.toFront();
};