summaryrefslogtreecommitdiff
path: root/jquery.flot.tooltip.js
diff options
context:
space:
mode:
Diffstat (limited to 'jquery.flot.tooltip.js')
-rw-r--r--jquery.flot.tooltip.js397
1 files changed, 251 insertions, 146 deletions
diff --git a/jquery.flot.tooltip.js b/jquery.flot.tooltip.js
index 0fea51b..486b657 100644
--- a/jquery.flot.tooltip.js
+++ b/jquery.flot.tooltip.js
@@ -1,154 +1,259 @@
/*
* jquery.flot.tooltip
- *
- * desc: create tooltip with values of hovered point on the graph,
- support many series, time mode, stacking and pie charts
- you can set custom tip content (also with use of HTML tags) and precision of values
- * version: 0.4.4
- * author: Krzysztof Urbas @krzysu [myviews.pl] with help of @ismyrnow
- * website: https://github.com/krzysu/flot.tooltip
*
+ * description: easy-to-use tooltips for Flot charts
+ * version: 0.6.2
+ * author: Krzysztof Urbas @krzysu [myviews.pl]
+ * website: https://github.com/krzysu/flot.tooltip
+ *
+ * build on 2013-09-30
* released under MIT License, 2012
-*/
-
+*/
(function ($) {
- var options = {
- tooltip: false, //boolean
- tooltipOpts: {
- content: "%s | X: %x | Y: %y.2", //%s -> series label, %x -> X value, %y -> Y value, %x.2 -> precision of X value, %p -> percent
- dateFormat: "%y-%0m-%0d",
- shifts: {
- x: 10,
- y: 20
- },
- defaultTheme: true
- }
- };
-
- var init = function(plot) {
-
- var tipPosition = {x: 0, y: 0};
- var opts = plot.getOptions();
-
- var updateTooltipPosition = function(pos) {
- tipPosition.x = pos.x;
- tipPosition.y = pos.y;
- };
-
- var onMouseMove = function(e) {
-
- var pos = {x: 0, y: 0};
-
- pos.x = e.pageX;
- pos.y = e.pageY;
-
- updateTooltipPosition(pos);
- };
-
- var timestampToDate = function(tmst) {
-
- var theDate = new Date(tmst);
-
- return $.plot.formatDate(theDate, opts.tooltipOpts.dateFormat);
- };
-
- plot.hooks.bindEvents.push(function (plot, eventHolder) {
-
- var to = opts.tooltipOpts;
- var placeholder = plot.getPlaceholder();
- var $tip;
-
- if (opts.tooltip === false) return;
-
- if( $('#flotTip').length > 0 ){
- $tip = $('#flotTip');
- }
- else {
- $tip = $('<div />').attr('id', 'flotTip');
- $tip.appendTo('body').hide().css({position: 'absolute'});
-
- if(to.defaultTheme) {
- $tip.css({
- 'background': '#fff',
- 'z-index': '100',
- 'padding': '0.4em 0.6em',
- 'border-radius': '0.5em',
- 'font-size': '0.8em',
- 'border': '1px solid #111'
- });
- }
- }
-
- $(placeholder).bind("plothover", function (event, pos, item) {
- if (item) {
- var tipText;
-
- if(opts.xaxis.mode === "time" || opts.xaxes[0].mode === "time") {
- tipText = stringFormat(to.content, item, timestampToDate);
- }
- else {
- tipText = stringFormat(to.content, item);
- }
-
- $tip.html( tipText ).css({left: tipPosition.x + to.shifts.x, top: tipPosition.y + to.shifts.y}).show();
- }
- else {
- $tip.hide().html('');
- }
- });
+
+ // plugin options, default values
+ var defaultOptions = {
+ tooltip: false,
+ tooltipOpts: {
+ content: "%s | X: %x | Y: %y",
+ // allowed templates are:
+ // %s -> series label,
+ // %x -> X value,
+ // %y -> Y value,
+ // %x.2 -> precision of X value,
+ // %p -> percent
+ xDateFormat: null,
+ yDateFormat: null,
+ shifts: {
+ x: 10,
+ y: 20
+ },
+ defaultTheme: true,
+
+ // callbacks
+ onHover: function(flotItem, $tooltipEl) {}
+ }
+ };
+
+ // object
+ var FlotTooltip = function(plot) {
+
+ // variables
+ this.tipPosition = {x: 0, y: 0};
+
+ this.init(plot);
+ };
+
+ // main plugin function
+ FlotTooltip.prototype.init = function(plot) {
+
+ var that = this;
+
+ plot.hooks.bindEvents.push(function (plot, eventHolder) {
+
+ // get plot options
+ that.plotOptions = plot.getOptions();
+
+ // if not enabled return
+ if (that.plotOptions.tooltip === false || typeof that.plotOptions.tooltip === 'undefined') return;
+
+ // shortcut to access tooltip options
+ that.tooltipOptions = that.plotOptions.tooltipOpts;
+
+ // create tooltip DOM element
+ var $tip = that.getDomElement();
+
+ // bind event
+ $( plot.getPlaceholder() ).bind("plothover", plothover);
- eventHolder.mousemove(onMouseMove);
+ $(eventHolder).bind('mousemove', mouseMove);
+
+ });
+ plot.hooks.shutdown.push(function (plot, eventHolder){
+ $(plot.getPlaceholder()).unbind("plothover", plothover);
+ $(eventHolder).unbind("mousemove", mouseMove);
});
-
- var stringFormat = function(content, item, fnct) {
-
- var percentPattern = /%p\.{0,1}(\d{0,})/;
- var seriesPattern = /%s/;
- var xPattern = /%x\.{0,1}(\d{0,})/;
- var yPattern = /%y\.{0,1}(\d{0,})/;
-
- //percent match
- if( typeof (item.series.percent) !== 'undefined' ) {
- content = adjustValPrecision(percentPattern, content, item.series.percent);
- }
- //series match
- if( typeof(item.series.label) !== 'undefined' ) {
- content = content.replace(seriesPattern, item.series.label);
- }
- // xVal match
- if( typeof(fnct) === 'function' ) {
- content = content.replace(xPattern, fnct(item.series.data[item.dataIndex][0]) );
- }
- else if( typeof item.series.data[item.dataIndex][0] === 'number' ) {
- content = adjustValPrecision(xPattern, content, item.series.data[item.dataIndex][0]);
- }
- // yVal match
- if( typeof item.series.data[item.dataIndex][1] === 'number' ) {
- content = adjustValPrecision(yPattern, content, item.series.data[item.dataIndex][1]);
- }
-
- return content;
- };
-
- var adjustValPrecision = function(pattern, content, value) {
-
- var precision;
- if( content.match(pattern) !== 'null' ) {
- if(RegExp.$1 !== '') {
- precision = RegExp.$1;
- value = value.toFixed(precision)
- }
- content = content.replace(pattern, value);
- }
-
- return content;
- };
- }
-
- $.plot.plugins.push({
- init: init,
- options: options,
- name: 'tooltip',
- version: '0.4.4'
- });
+ function mouseMove(e){
+ var pos = {};
+ pos.x = e.pageX;
+ pos.y = e.pageY;
+ that.updateTooltipPosition(pos);
+ }
+ function plothover(event, pos, item) {
+ var $tip = that.getDomElement();
+ if (item) {
+ var tipText;
+
+ // convert tooltip content template to real tipText
+ tipText = that.stringFormat(that.tooltipOptions.content, item);
+
+ $tip.html( tipText );
+ that.updateTooltipPosition({ x: pos.pageX, y: pos.pageY });
+ $tip.css({
+ left: that.tipPosition.x + that.tooltipOptions.shifts.x,
+ top: that.tipPosition.y + that.tooltipOptions.shifts.y
+ })
+ .show();
+
+ // run callback
+ if(typeof that.tooltipOptions.onHover === 'function') {
+ that.tooltipOptions.onHover(item, $tip);
+ }
+ }
+ else {
+ $tip.hide().html('');
+ }
+ }
+ };
+
+ /**
+ * get or create tooltip DOM element
+ * @return jQuery object
+ */
+ FlotTooltip.prototype.getDomElement = function() {
+ var $tip;
+
+ if( $('#flotTip').length > 0 ){
+ $tip = $('#flotTip');
+ }
+ else {
+ $tip = $('<div />').attr('id', 'flotTip');
+ $tip.appendTo('body').hide().css({position: 'absolute'});
+
+ if(this.tooltipOptions.defaultTheme) {
+ $tip.css({
+ 'background': '#fff',
+ 'z-index': '100',
+ 'padding': '0.4em 0.6em',
+ 'border-radius': '0.5em',
+ 'font-size': '0.8em',
+ 'border': '1px solid #111',
+ 'display': 'none',
+ 'white-space': 'nowrap'
+ });
+ }
+ }
+
+ return $tip;
+ };
+
+ // as the name says
+ FlotTooltip.prototype.updateTooltipPosition = function(pos) {
+ var totalTipWidth = $("#flotTip").outerWidth() + this.tooltipOptions.shifts.x;
+ var totalTipHeight = $("#flotTip").outerHeight() + this.tooltipOptions.shifts.y;
+ if ((pos.x - $(window).scrollLeft()) > ($(window).innerWidth() - totalTipWidth)) {
+ pos.x -= totalTipWidth;
+ }
+ if ((pos.y - $(window).scrollTop()) > ($(window).innerHeight() - totalTipHeight)) {
+ pos.y -= totalTipHeight;
+ }
+ this.tipPosition.x = pos.x;
+ this.tipPosition.y = pos.y;
+ };
+
+ /**
+ * core function, create tooltip content
+ * @param {string} content - template with tooltip content
+ * @param {object} item - Flot item
+ * @return {string} real tooltip content for current item
+ */
+ FlotTooltip.prototype.stringFormat = function(content, item) {
+
+ var percentPattern = /%p\.{0,1}(\d{0,})/;
+ var seriesPattern = /%s/;
+ var xPattern = /%x\.{0,1}(?:\d{0,})/;
+ var yPattern = /%y\.{0,1}(?:\d{0,})/;
+
+ // if it is a function callback get the content string
+ if( typeof(content) === 'function' ) {
+ content = content(item.series.label, item.series.data[item.dataIndex][0], item.series.data[item.dataIndex][1], item);
+ }
+
+ // percent match for pie charts
+ if( typeof (item.series.percent) !== 'undefined' ) {
+ content = this.adjustValPrecision(percentPattern, content, item.series.percent);
+ }
+
+ // series match
+ if( typeof(item.series.label) !== 'undefined' ) {
+ content = content.replace(seriesPattern, item.series.label);
+ }
+
+ // time mode axes with custom dateFormat
+ if(this.isTimeMode('xaxis', item) && this.isXDateFormat(item)) {
+ content = content.replace(xPattern, this.timestampToDate(item.series.data[item.dataIndex][0], this.tooltipOptions.xDateFormat));
+ }
+
+ if(this.isTimeMode('yaxis', item) && this.isYDateFormat(item)) {
+ content = content.replace(yPattern, this.timestampToDate(item.series.data[item.dataIndex][1], this.tooltipOptions.yDateFormat));
+ }
+
+ // set precision if defined
+ if( typeof item.series.data[item.dataIndex][0] === 'number' ) {
+ content = this.adjustValPrecision(xPattern, content, item.series.data[item.dataIndex][0]);
+ }
+ if( typeof item.series.data[item.dataIndex][1] === 'number' ) {
+ content = this.adjustValPrecision(yPattern, content, item.series.data[item.dataIndex][1]);
+ }
+
+ // if no value customization, use tickFormatter by default
+ if(typeof item.series.xaxis.tickFormatter !== 'undefined') {
+ content = content.replace(xPattern, item.series.xaxis.tickFormatter(item.series.data[item.dataIndex][0], item.series.xaxis));
+ }
+ if(typeof item.series.yaxis.tickFormatter !== 'undefined') {
+ content = content.replace(yPattern, item.series.yaxis.tickFormatter(item.series.data[item.dataIndex][1], item.series.yaxis));
+ }
+
+ return content;
+ };
+
+ // helpers just for readability
+ FlotTooltip.prototype.isTimeMode = function(axisName, item) {
+ return (typeof item.series[axisName].options.mode !== 'undefined' && item.series[axisName].options.mode === 'time');
+ };
+
+ FlotTooltip.prototype.isXDateFormat = function(item) {
+ return (typeof this.tooltipOptions.xDateFormat !== 'undefined' && this.tooltipOptions.xDateFormat !== null);
+ };
+
+ FlotTooltip.prototype.isYDateFormat = function(item) {
+ return (typeof this.tooltipOptions.yDateFormat !== 'undefined' && this.tooltipOptions.yDateFormat !== null);
+ };
+
+ //
+ FlotTooltip.prototype.timestampToDate = function(tmst, dateFormat) {
+ var theDate = new Date(tmst);
+ return $.plot.formatDate(theDate, dateFormat);
+ };
+
+ //
+ FlotTooltip.prototype.adjustValPrecision = function(pattern, content, value) {
+
+ var precision;
+ var matchResult = content.match(pattern);
+ if( matchResult !== null ) {
+ if(RegExp.$1 !== '') {
+ precision = RegExp.$1;
+ value = value.toFixed(precision);
+
+ // only replace content if precision exists, in other case use thickformater
+ content = content.replace(pattern, value);
+ }
+ }
+ return content;
+ };
+
+ //
+ var init = function(plot) {
+ new FlotTooltip(plot);
+ };
+
+ // define Flot plugin
+ $.plot.plugins.push({
+ init: init,
+ options: defaultOptions,
+ name: 'tooltip',
+ version: '0.6.1'
+ });
+
})(jQuery);