From d21ecc58e48964faefc9d3d934b2bd76e7b37072 Mon Sep 17 00:00:00 2001 From: Vitor Baptista Date: Mon, 10 Mar 2014 12:15:44 -0300 Subject: [PATCH] Fix tooltip when displaying multiple series We replace the "%x" in the tooltip string with the corresponding item tick's label. We do so by looking at the item's index in the chart's data array (dataIndex), and getting the tick in the same index in the ticks' array. That works fine if you have a single series, but doesn't work with multiple ones. In that case, you have multiple data arrays, one for each series, but you still have a single ticks array. For example, if you have the plot's data as: [ { data: [ ["Foo", 5] ] }, { data: [ ["Bar", 10] ] } ] Both item's dataIndex will be 0, because each one is the first element on its series' data array. But the ticks array is something like: ["Foo", "Bar"] If you use only dataIndex, you'll get the tick "Foo" for both items. What we need is an offset which tells us which series the current item is in: that's seriesIndex. The ticks' index is then calculated as ```seriesIndex + dataIndex```. That solves our problem. In our example, even though the dataIndex for both items is 0, the seriesIndex for "Foo" is 0, and for "Bar" is 1. Everything works as expected. This fixes #65. --- js/jquery.flot.tooltip.js | 7 ++++--- js/jquery.flot.tooltip.min.js | 4 ++-- js/jquery.flot.tooltip.source.js | 5 +++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/js/jquery.flot.tooltip.js b/js/jquery.flot.tooltip.js index 1b05018..f1b3c33 100644 --- a/js/jquery.flot.tooltip.js +++ b/js/jquery.flot.tooltip.js @@ -6,7 +6,7 @@ * author: Krzysztof Urbas @krzysu [myviews.pl] * website: https://github.com/krzysu/flot.tooltip * - * build on 2014-02-10 + * build on 2014-03-10 * released under MIT License, 2012 */ (function ($) { @@ -224,8 +224,9 @@ // change x from number to given label, if given if(typeof item.series.xaxis.ticks !== 'undefined') { - if(item.series.xaxis.ticks.length > item.dataIndex && !this.isTimeMode('xaxis', item)) - content = content.replace(xPattern, item.series.xaxis.ticks[item.dataIndex].label); + var tickIndex = item.dataIndex + item.seriesIndex; + if(item.series.xaxis.ticks.length > tickIndex && !this.isTimeMode('xaxis', item)) + content = content.replace(xPattern, item.series.xaxis.ticks[tickIndex].label); } // change y from number to given label, if given diff --git a/js/jquery.flot.tooltip.min.js b/js/jquery.flot.tooltip.min.js index 052c35c..72255f3 100644 --- a/js/jquery.flot.tooltip.min.js +++ b/js/jquery.flot.tooltip.min.js @@ -6,7 +6,7 @@ * author: Krzysztof Urbas @krzysu [myviews.pl] * website: https://github.com/krzysu/flot.tooltip * - * build on 2014-02-10 + * build on 2014-03-10 * released under MIT License, 2012 */ -!function(a){var b={tooltip:!1,tooltipOpts:{content:"%s | X: %x | Y: %y",xDateFormat:null,yDateFormat:null,monthNames:null,dayNames:null,shifts:{x:10,y:20},defaultTheme:!0,onHover:function(){}}},c=function(a){this.tipPosition={x:0,y:0},this.init(a)};c.prototype.init=function(b){function c(a){var b={};b.x=a.pageX,b.y=a.pageY,e.updateTooltipPosition(b)}function d(a,b,c){var d=e.getDomElement();if(c){var f;f=e.stringFormat(e.tooltipOptions.content,c),d.html(f),e.updateTooltipPosition({x:b.pageX,y:b.pageY}),d.css({left:e.tipPosition.x+e.tooltipOptions.shifts.x,top:e.tipPosition.y+e.tooltipOptions.shifts.y}).show(),"function"==typeof e.tooltipOptions.onHover&&e.tooltipOptions.onHover(c,d)}else d.hide().html("")}var e=this;b.hooks.bindEvents.push(function(b,f){if(e.plotOptions=b.getOptions(),e.plotOptions.tooltip!==!1&&"undefined"!=typeof e.plotOptions.tooltip){e.tooltipOptions=e.plotOptions.tooltipOpts;{e.getDomElement()}a(b.getPlaceholder()).bind("plothover",d),a(f).bind("mousemove",c)}}),b.hooks.shutdown.push(function(b,e){a(b.getPlaceholder()).unbind("plothover",d),a(e).unbind("mousemove",c)})},c.prototype.getDomElement=function(){var b;return a("#flotTip").length>0?b=a("#flotTip"):(b=a("
").attr("id","flotTip"),b.appendTo("body").hide().css({position:"absolute"}),this.tooltipOptions.defaultTheme&&b.css({background:"#fff","z-index":"1040",padding:"0.4em 0.6em","border-radius":"0.5em","font-size":"0.8em",border:"1px solid #111",display:"none","white-space":"nowrap"})),b},c.prototype.updateTooltipPosition=function(b){var c=a("#flotTip").outerWidth()+this.tooltipOptions.shifts.x,d=a("#flotTip").outerHeight()+this.tooltipOptions.shifts.y;b.x-a(window).scrollLeft()>a(window).innerWidth()-c&&(b.x-=c),b.y-a(window).scrollTop()>a(window).innerHeight()-d&&(b.y-=d),this.tipPosition.x=b.x,this.tipPosition.y=b.y},c.prototype.stringFormat=function(a,b){var c,d,e=/%p\.{0,1}(\d{0,})/,f=/%s/,g=/%x\.{0,1}(\d{0,})/,h=/%y\.{0,1}(\d{0,})/,i="%x",j="%y";if("undefined"!=typeof b.series.threshold?(c=b.datapoint[0],d=b.datapoint[1]):(c=b.series.data[b.dataIndex][0],d=b.series.data[b.dataIndex][1]),null===b.series.label&&b.series.originSeries&&(b.series.label=b.series.originSeries.label),"function"==typeof a&&(a=a(b.series.label,c,d,b)),"undefined"!=typeof b.series.percent&&(a=this.adjustValPrecision(e,a,b.series.percent)),a="undefined"!=typeof b.series.label?a.replace(f,b.series.label):a.replace(f,""),this.isTimeMode("xaxis",b)&&this.isXDateFormat(b)&&(a=a.replace(g,this.timestampToDate(c,this.tooltipOptions.xDateFormat))),this.isTimeMode("yaxis",b)&&this.isYDateFormat(b)&&(a=a.replace(h,this.timestampToDate(d,this.tooltipOptions.yDateFormat))),"number"==typeof c&&(a=this.adjustValPrecision(g,a,c)),"number"==typeof d&&(a=this.adjustValPrecision(h,a,d)),"undefined"!=typeof b.series.xaxis.ticks&&b.series.xaxis.ticks.length>b.dataIndex&&!this.isTimeMode("xaxis",b)&&(a=a.replace(g,b.series.xaxis.ticks[b.dataIndex].label)),"undefined"!=typeof b.series.yaxis.ticks)for(var k in b.series.yaxis.ticks)if(b.series.yaxis.ticks.hasOwnProperty(k)){var l=this.isCategoriesMode("yaxis",b)?b.series.yaxis.ticks[k].label:b.series.yaxis.ticks[k].v;l===d&&(a=a.replace(h,b.series.yaxis.ticks[k].label))}return"undefined"!=typeof b.series.xaxis.tickFormatter&&(a=a.replace(i,b.series.xaxis.tickFormatter(c,b.series.xaxis).replace(/\$/g,"$$"))),"undefined"!=typeof b.series.yaxis.tickFormatter&&(a=a.replace(j,b.series.yaxis.tickFormatter(d,b.series.yaxis).replace(/\$/g,"$$"))),a},c.prototype.isTimeMode=function(a,b){return"undefined"!=typeof b.series[a].options.mode&&"time"===b.series[a].options.mode},c.prototype.isXDateFormat=function(){return"undefined"!=typeof this.tooltipOptions.xDateFormat&&null!==this.tooltipOptions.xDateFormat},c.prototype.isYDateFormat=function(){return"undefined"!=typeof this.tooltipOptions.yDateFormat&&null!==this.tooltipOptions.yDateFormat},c.prototype.isCategoriesMode=function(a,b){return"undefined"!=typeof b.series[a].options.mode&&"categories"===b.series[a].options.mode},c.prototype.timestampToDate=function(b,c){var d=new Date(1*b);return a.plot.formatDate(d,c,this.tooltipOptions.monthNames,this.tooltipOptions.dayNames)},c.prototype.adjustValPrecision=function(a,b,c){var d,e=b.match(a);return null!==e&&""!==RegExp.$1&&(d=RegExp.$1,c=c.toFixed(d),b=b.replace(a,c)),b};var d=function(a){new c(a)};a.plot.plugins.push({init:d,options:b,name:"tooltip",version:"0.6.6"})}(jQuery); \ No newline at end of file +!function(a){var b={tooltip:!1,tooltipOpts:{content:"%s | X: %x | Y: %y",xDateFormat:null,yDateFormat:null,monthNames:null,dayNames:null,shifts:{x:10,y:20},defaultTheme:!0,onHover:function(){}}},c=function(a){this.tipPosition={x:0,y:0},this.init(a)};c.prototype.init=function(b){function c(a){var b={};b.x=a.pageX,b.y=a.pageY,e.updateTooltipPosition(b)}function d(a,b,c){var d=e.getDomElement();if(c){var f;f=e.stringFormat(e.tooltipOptions.content,c),d.html(f),e.updateTooltipPosition({x:b.pageX,y:b.pageY}),d.css({left:e.tipPosition.x+e.tooltipOptions.shifts.x,top:e.tipPosition.y+e.tooltipOptions.shifts.y}).show(),"function"==typeof e.tooltipOptions.onHover&&e.tooltipOptions.onHover(c,d)}else d.hide().html("")}var e=this;b.hooks.bindEvents.push(function(b,f){if(e.plotOptions=b.getOptions(),e.plotOptions.tooltip!==!1&&"undefined"!=typeof e.plotOptions.tooltip){e.tooltipOptions=e.plotOptions.tooltipOpts;{e.getDomElement()}a(b.getPlaceholder()).bind("plothover",d),a(f).bind("mousemove",c)}}),b.hooks.shutdown.push(function(b,e){a(b.getPlaceholder()).unbind("plothover",d),a(e).unbind("mousemove",c)})},c.prototype.getDomElement=function(){var b;return a("#flotTip").length>0?b=a("#flotTip"):(b=a("
").attr("id","flotTip"),b.appendTo("body").hide().css({position:"absolute"}),this.tooltipOptions.defaultTheme&&b.css({background:"#fff","z-index":"1040",padding:"0.4em 0.6em","border-radius":"0.5em","font-size":"0.8em",border:"1px solid #111",display:"none","white-space":"nowrap"})),b},c.prototype.updateTooltipPosition=function(b){var c=a("#flotTip").outerWidth()+this.tooltipOptions.shifts.x,d=a("#flotTip").outerHeight()+this.tooltipOptions.shifts.y;b.x-a(window).scrollLeft()>a(window).innerWidth()-c&&(b.x-=c),b.y-a(window).scrollTop()>a(window).innerHeight()-d&&(b.y-=d),this.tipPosition.x=b.x,this.tipPosition.y=b.y},c.prototype.stringFormat=function(a,b){var c,d,e=/%p\.{0,1}(\d{0,})/,f=/%s/,g=/%x\.{0,1}(\d{0,})/,h=/%y\.{0,1}(\d{0,})/,i="%x",j="%y";if("undefined"!=typeof b.series.threshold?(c=b.datapoint[0],d=b.datapoint[1]):(c=b.series.data[b.dataIndex][0],d=b.series.data[b.dataIndex][1]),null===b.series.label&&b.series.originSeries&&(b.series.label=b.series.originSeries.label),"function"==typeof a&&(a=a(b.series.label,c,d,b)),"undefined"!=typeof b.series.percent&&(a=this.adjustValPrecision(e,a,b.series.percent)),a="undefined"!=typeof b.series.label?a.replace(f,b.series.label):a.replace(f,""),this.isTimeMode("xaxis",b)&&this.isXDateFormat(b)&&(a=a.replace(g,this.timestampToDate(c,this.tooltipOptions.xDateFormat))),this.isTimeMode("yaxis",b)&&this.isYDateFormat(b)&&(a=a.replace(h,this.timestampToDate(d,this.tooltipOptions.yDateFormat))),"number"==typeof c&&(a=this.adjustValPrecision(g,a,c)),"number"==typeof d&&(a=this.adjustValPrecision(h,a,d)),"undefined"!=typeof b.series.xaxis.ticks){var k=b.dataIndex+b.seriesIndex;b.series.xaxis.ticks.length>k&&!this.isTimeMode("xaxis",b)&&(a=a.replace(g,b.series.xaxis.ticks[k].label))}if("undefined"!=typeof b.series.yaxis.ticks)for(var l in b.series.yaxis.ticks)if(b.series.yaxis.ticks.hasOwnProperty(l)){var m=this.isCategoriesMode("yaxis",b)?b.series.yaxis.ticks[l].label:b.series.yaxis.ticks[l].v;m===d&&(a=a.replace(h,b.series.yaxis.ticks[l].label))}return"undefined"!=typeof b.series.xaxis.tickFormatter&&(a=a.replace(i,b.series.xaxis.tickFormatter(c,b.series.xaxis).replace(/\$/g,"$$"))),"undefined"!=typeof b.series.yaxis.tickFormatter&&(a=a.replace(j,b.series.yaxis.tickFormatter(d,b.series.yaxis).replace(/\$/g,"$$"))),a},c.prototype.isTimeMode=function(a,b){return"undefined"!=typeof b.series[a].options.mode&&"time"===b.series[a].options.mode},c.prototype.isXDateFormat=function(){return"undefined"!=typeof this.tooltipOptions.xDateFormat&&null!==this.tooltipOptions.xDateFormat},c.prototype.isYDateFormat=function(){return"undefined"!=typeof this.tooltipOptions.yDateFormat&&null!==this.tooltipOptions.yDateFormat},c.prototype.isCategoriesMode=function(a,b){return"undefined"!=typeof b.series[a].options.mode&&"categories"===b.series[a].options.mode},c.prototype.timestampToDate=function(b,c){var d=new Date(1*b);return a.plot.formatDate(d,c,this.tooltipOptions.monthNames,this.tooltipOptions.dayNames)},c.prototype.adjustValPrecision=function(a,b,c){var d,e=b.match(a);return null!==e&&""!==RegExp.$1&&(d=RegExp.$1,c=c.toFixed(d),b=b.replace(a,c)),b};var d=function(a){new c(a)};a.plot.plugins.push({init:d,options:b,name:"tooltip",version:"0.6.6"})}(jQuery); \ No newline at end of file diff --git a/js/jquery.flot.tooltip.source.js b/js/jquery.flot.tooltip.source.js index 4c90d3c..fad1ce1 100644 --- a/js/jquery.flot.tooltip.source.js +++ b/js/jquery.flot.tooltip.source.js @@ -213,8 +213,9 @@ // change x from number to given label, if given if(typeof item.series.xaxis.ticks !== 'undefined') { - if(item.series.xaxis.ticks.length > item.dataIndex && !this.isTimeMode('xaxis', item)) - content = content.replace(xPattern, item.series.xaxis.ticks[item.dataIndex].label); + var tickIndex = item.dataIndex + item.seriesIndex; + if(item.series.xaxis.ticks.length > tickIndex && !this.isTimeMode('xaxis', item)) + content = content.replace(xPattern, item.series.xaxis.ticks[tickIndex].label); } // change y from number to given label, if given