对jqplot的CategoryAxisRenderer插件进行扩展,底部Tick在鼠标在上时浮动显示名称。
在前一篇文章中介绍了如何让jqplot的柱形图tick下标出现省略号,参考:《对jqplot的CategoryAxisRenderer插件进行扩展,让文字出现省略号》
http://xianbin.iteye.com/blog/1701667
下面介绍如何扩展jqplot,让其实现鼠标移动到下标tick的时候出现浮动提示框,显示完整的tick名称。
文件命名为:jqplot.categoryAxisRenderer.extend.js
在引入jqplot.categoryAxisRenderer.js之后,再引入该js,以便覆盖原有的实现。下面代码已经实现了将tick下标显示为带省略号的文字并出现浮动提示框。
http://dl.iteye.com/upload/attachment/0077/2418/8fa14d80-a1d2-3e15-9740-eea0eee87c48.jpg
/** * 本扩展插件是对jqplot插件jqplot.categoryAxisRenderer的扩展,主要修改了显示图形下标Tick的处理, * 在显示Tick之前,判断Tick标签的长度,当标题长度超过tickMaxLength定义的长度时,截获前 * tickMaxLength - 1个字符,然后加上省略号。 ** 作者:suxianbin */(function($) { $.jqplot.CategoryAxisRenderer.prototype.createTicks = function() { // we're are operating on an axis here var ticks = this._ticks; var userTicks = this.ticks; var name = this.name; // databounds were set on axis initialization. var db = this._dataBounds; var dim, interval; var min, max; var pos1, pos2; var tt, i; // X轴的标题文字最大长度 var tickMaxLength = this.tickMaxLength; // if we already have ticks, use them. if (userTicks.length) { // adjust with blanks if we have groups if (this.groups > 1 && !this._grouped) { var l = userTicks.length; var skip = parseInt(l/this.groups, 10); var count = 0; for (var i=skip; i<l; i+=skip) { userTicks.splice(i+count, 0, ' '); count++; } this._grouped = true; } this.min = 0.5; this.max = userTicks.length + 0.5; var range = this.max - this.min; this.numberTicks = 2*userTicks.length + 1; for (i=0; i<userTicks.length; i++){ tt = this.min + 2 * i * range / (this.numberTicks-1); // need a marker before and after the tick var t = new this.tickRenderer(this.tickOptions); t.showLabel = false; // t.showMark = true; t.setTick(tt, this.name); this._ticks.push(t); var t = new this.tickRenderer(this.tickOptions); // 当标题长度超过tickMaxLength定义的长度时,截获前tickMaxLength - 1个字符, // 然后加上省略号。if (tickMaxLength) {var userTick = userTicks.length <= tickMaxLength ? userTicks: userTicks.substring(0, (tickMaxLength - 1)) + '...';t.label = userTick;t.userTick = userTicks;} else {t.label = userTicks;} // t.showLabel = true; t.showMark = false; t.showGridline = false; t.setTick(tt+0.5, this.name); this._ticks.push(t); } // now add the last tick at the end var t = new this.tickRenderer(this.tickOptions); t.showLabel = false; // t.showMark = true; t.setTick(tt+1, this.name); this._ticks.push(t); } // we don't have any ticks yet, let's make some! else { if (name == 'xaxis' || name == 'x2axis') { dim = this._plotDimensions.width; } else { dim = this._plotDimensions.height; } // if min, max and number of ticks specified, user can't specify interval. if (this.min != null && this.max != null && this.numberTicks != null) { this.tickInterval = null; } // if max, min, and interval specified and interval won't fit, ignore interval. if (this.min != null && this.max != null && this.tickInterval != null) { if (parseInt((this.max-this.min)/this.tickInterval, 10) != (this.max-this.min)/this.tickInterval) { this.tickInterval = null; } } // find out how many categories are in the lines and collect labels var labels = []; var numcats = 0; var min = 0.5; var max, val; var isMerged = false; for (var i=0; i<this._series.length; i++) { var s = this._series; for (var j=0; j<s.data.length; j++) { if (this.name == 'xaxis' || this.name == 'x2axis') { val = s.data; } else { val = s.data; } if ($.inArray(val, labels) == -1) { isMerged = true; numcats += 1; labels.push(val); } } } if (isMerged && this.sortMergedLabels) { labels.sort(function(a,b) { return a - b; }); } // keep a reference to these tick labels to use for redrawing plot (see bug #57) this.ticks = labels; // now bin the data values to the right lables. for (var i=0; i<this._series.length; i++) { var s = this._series; for (var j=0; j<s.data.length; j++) { if (this.name == 'xaxis' || this.name == 'x2axis') { val = s.data; } else { val = s.data; } // for category axis, force the values into category bins. // we should have the value in the label array now. var idx = $.inArray(val, labels)+1; if (this.name == 'xaxis' || this.name == 'x2axis') { s.data = idx; } else { s.data = idx; } } } // adjust with blanks if we have groups if (this.groups > 1 && !this._grouped) { var l = labels.length; var skip = parseInt(l/this.groups, 10); var count = 0; for (var i=skip; i<l; i+=skip+1) { labels = ' '; } this._grouped = true; } max = numcats + 0.5; if (this.numberTicks == null) { this.numberTicks = 2*numcats + 1; } var range = max - min; this.min = min; this.max = max; var track = 0; // todo: adjust this so more ticks displayed. var maxVisibleTicks = parseInt(3+dim/10, 10); var skip = parseInt(numcats/maxVisibleTicks, 10); if (this.tickInterval == null) { this.tickInterval = range / (this.numberTicks-1); } // if tickInterval is specified, we will ignore any computed maximum. for (var i=0; i<this.numberTicks; i++){ tt = this.min + i * this.tickInterval; var t = new this.tickRenderer(this.tickOptions); // if even tick, it isn't a category, it's a divider if (i/2 == parseInt(i/2, 10)) { t.showLabel = false; t.showMark = true; } else { if (skip>0 && track<skip) { t.showLabel = false; track += 1; } else { t.showLabel = true; track = 0; } t.label = t.formatter(t.formatString, labels[(i-1)/2]); t.showMark = false; t.showGridline = false; } t.setTick(tt, this.name); this._ticks.push(t); } } }; // called with scope of axis $.jqplot.CategoryAxisRenderer.prototype.pack = function(pos, offsets) { var ticks = this._ticks; var max = this.max; var min = this.min; var offmax = offsets.max; var offmin = offsets.min; var lshow = (this._label == null) ? false : this._label.show; var i; for (var p in pos) { this._elem.css(p, pos); } this._offsets = offsets; // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left. var pixellength = offmax - offmin; var unitlength = max - min; // point to unit and unit to point conversions references to Plot DOM element top left corner. this.p2u = function(p){ return (p - offmin) * unitlength / pixellength + min; }; this.u2p = function(u){ return (u - min) * pixellength / unitlength + offmin; }; if (this.name == 'xaxis' || this.name == 'x2axis'){ this.series_u2p = function(u){ return (u - min) * pixellength / unitlength; }; this.series_p2u = function(p){ return p * unitlength / pixellength + min; }; } else { this.series_u2p = function(u){ return (u - max) * pixellength / unitlength; }; this.series_p2u = function(p){ return p * unitlength / pixellength + max; }; } if (this.show) { if (this.name == 'xaxis' || this.name == 'x2axis') { for (i=0; i<ticks.length; i++) { var t = ticks; if (t.show && t.showLabel) { var shim; if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { // will need to adjust auto positioning based on which axis this is. var temp = (this.name == 'xaxis') ? 1 : -1; switch (t.labelPosition) { case 'auto': // position at end if (temp * t.angle < 0) { shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; } // position at start else { shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; } break; case 'end': shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; break; case 'start': shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; break; case 'middle': shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; break; default: shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; break; } } else { shim = -t.getWidth()/2; } var val = this.u2p(t.value) + shim + 'px'; t._elem.css('left', val); t.pack(); /* * 增加X轴Tick的弹出提醒框,内容为下标的全称。 */ t._elem.css('cursor', 'default'); t._elem.css('z-index', 888); t._elem.attr('userTick', t.userTick); t._elem.mouseover(function (e) { var userTick = $(this).attr('usertick'); _showUserTickTip(userTick, e); }); t._elem.mouseout(function () { _hideUserTickTip(); }); } } var labeledge=['bottom', 0]; if (lshow) { var w = this._label._elem.outerWidth(true); this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px'); if (this.name == 'xaxis') { this._label._elem.css('bottom', '0px'); labeledge = ['bottom', this._label._elem.outerHeight(true)]; } else { this._label._elem.css('top', '0px'); labeledge = ['top', this._label._elem.outerHeight(true)]; } this._label.pack(); } // draw the group labels var step = parseInt(this._ticks.length/this.groups, 10); for (i=0; i<this._groupLabels.length; i++) { var mid = 0; var count = 0; for (var j=i*step; j<=(i+1)*step; j++) { if (this._ticks._elem && this._ticks.label != " ") { var t = this._ticks._elem; var p = t.position(); mid += p.left + t.outerWidth(true)/2; count++; } } mid = mid/count; this._groupLabels.css({'left':(mid - this._groupLabels.outerWidth(true)/2)}); this._groupLabels.css(labeledge, labeledge); } } else { for (i=0; i<ticks.length; i++) { var t = ticks; if (t.show && t.showLabel) { var shim; if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { // will need to adjust auto positioning based on which axis this is. var temp = (this.name == 'yaxis') ? 1 : -1; switch (t.labelPosition) { case 'auto': // position at end case 'end': if (temp * t.angle < 0) { shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; } else { shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; } break; case 'start': if (t.angle > 0) { shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; } else { shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; } break; case 'middle': // if (t.angle > 0) { // shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; // } // else { // shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; // } shim = -t.getHeight()/2; break; default: shim = -t.getHeight()/2; break; } } else { shim = -t.getHeight()/2; } var val = this.u2p(t.value) + shim + 'px'; t._elem.css('top', val); t.pack(); } } var labeledge=['left', 0]; if (lshow) { var h = this._label._elem.outerHeight(true); this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px'); if (this.name == 'yaxis') { this._label._elem.css('left', '0px'); labeledge = ['left', this._label._elem.outerWidth(true)]; } else { this._label._elem.css('right', '0px'); labeledge = ['right', this._label._elem.outerWidth(true)]; } this._label.pack(); } // draw the group labels, position top here, do left after label position. var step = parseInt(this._ticks.length/this.groups, 10); for (i=0; i<this._groupLabels.length; i++) { var mid = 0; var count = 0; for (var j=i*step; j<=(i+1)*step; j++) { if (this._ticks._elem && this._ticks.label != " ") { var t = this._ticks._elem; var p = t.position(); mid += p.top + t.outerHeight()/2; count++; } } mid = mid/count; this._groupLabels.css({'top':mid - this._groupLabels.outerHeight()/2}); this._groupLabels.css(labeledge, labeledge); } } } }; // 显示Tick下标全称的提示框 function _showUserTickTip(userTick, event) {var containerId = 'userTickTipDiv';var container = $('#' + containerId);if (container == undefined || container == null || container.length == 0) {container = $('<div class="jqplot-cursor-tooltip chartDetailDiv"></div>');container.attr('id', containerId);var table = '<table class="jqplot-highlighter">'+ '<tr><td><span id="userTickValue"></span></td></tr>'+ '</table>';$(table).appendTo(container);container.appendTo('body');}$('#userTickValue').text(userTick);// 计算显示框的位置,如果超过右边边界则在左边显示var left = event.pageX;var detailPopDivWidth = container.width();var docWidth = $(window).width();var leftX = left + detailPopDivWidth + 10; // 10 表示与边界的间隔if (leftX > docWidth) {left = event.pageX - detailPopDivWidth;}container.css({display : 'block',left : left,top : event.pageY - 25});} // 隐藏Tick下标全称的提示框 function _hideUserTickTip() {$('#userTickTipDiv').css({display : 'none'}); }})(jQuery);
页:
[1]