[ Index ] |
PHP Cross Reference of vtigercrm-6.1.0 |
[Summary view] [Print] [Text view]
1 /** 2 * jqPlot 3 * Pure JavaScript plotting plugin using jQuery 4 * 5 * Version: 1.0.2 6 * Revision: 1108 7 * 8 * Copyright (c) 2009-2011 Chris Leonello 9 * jqPlot is currently available for use in all personal or commercial projects 10 * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL 11 * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can 12 * choose the license that best suits your project and use it accordingly. 13 * 14 * Although not required, the author would appreciate an email letting him 15 * know of any substantial use of jqPlot. You can reach the author at: 16 * chris at jqplot dot com or see http://www.jqplot.com/info.php . 17 * 18 * If you are feeling kind and generous, consider supporting the project by 19 * making a donation at: http://www.jqplot.com/donate.php . 20 * 21 * sprintf functions contained in jqplot.sprintf.js by Ash Searle: 22 * 23 * version 2007.04.27 24 * author Ash Searle 25 * http://hexmen.com/blog/2007/03/printf-sprintf/ 26 * http://hexmen.com/js/sprintf.js 27 * The author (Ash Searle) has placed this code in the public domain: 28 * "This code is unrestricted: you are free to use it however you like." 29 * 30 */ 31 (function($) { 32 33 /** 34 * Class: $.jqplot.Cursor 35 * Plugin class representing the cursor as displayed on the plot. 36 */ 37 $.jqplot.Cursor = function(options) { 38 // Group: Properties 39 // 40 // prop: style 41 // CSS spec for cursor style 42 this.style = 'crosshair'; 43 this.previousCursor = 'auto'; 44 // prop: show 45 // wether to show the cursor or not. 46 this.show = $.jqplot.config.enablePlugins; 47 // prop: showTooltip 48 // show a cursor position tooltip. Location of the tooltip 49 // will be controlled by followMouse and tooltipLocation. 50 this.showTooltip = true; 51 // prop: followMouse 52 // Tooltip follows the mouse, it is not at a fixed location. 53 // Tooltip will show on the grid at the location given by 54 // tooltipLocation, offset from the grid edge by tooltipOffset. 55 this.followMouse = false; 56 // prop: tooltipLocation 57 // Where to position tooltip. If followMouse is true, this is 58 // relative to the cursor, otherwise, it is relative to the grid. 59 // One of 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw' 60 this.tooltipLocation = 'se'; 61 // prop: tooltipOffset 62 // Pixel offset of tooltip from the grid boudaries or cursor center. 63 this.tooltipOffset = 6; 64 // prop: showTooltipGridPosition 65 // show the grid pixel coordinates of the mouse. 66 this.showTooltipGridPosition = false; 67 // prop: showTooltipUnitPosition 68 // show the unit (data) coordinates of the mouse. 69 this.showTooltipUnitPosition = true; 70 // prop: showTooltipDataPosition 71 // Used with showVerticalLine to show intersecting data points in the tooltip. 72 this.showTooltipDataPosition = false; 73 // prop: tooltipFormatString 74 // sprintf format string for the tooltip. 75 // Uses Ash Searle's javascript sprintf implementation 76 // found here: http://hexmen.com/blog/2007/03/printf-sprintf/ 77 // See http://perldoc.perl.org/functions/sprintf.html for reference 78 // Note, if showTooltipDataPosition is true, the default tooltipFormatString 79 // will be set to the cursorLegendFormatString, not the default given here. 80 this.tooltipFormatString = '%.4P, %.4P'; 81 // prop: useAxesFormatters 82 // Use the x and y axes formatters to format the text in the tooltip. 83 this.useAxesFormatters = true; 84 // prop: tooltipAxisGroups 85 // Show position for the specified axes. 86 // This is an array like [['xaxis', 'yaxis'], ['xaxis', 'y2axis']] 87 // Default is to compute automatically for all visible axes. 88 this.tooltipAxisGroups = []; 89 // prop: zoom 90 // Enable plot zooming. 91 this.zoom = false; 92 // zoomProxy and zoomTarget properties are not directly set by user. 93 // They Will be set through call to zoomProxy method. 94 this.zoomProxy = false; 95 this.zoomTarget = false; 96 // prop: looseZoom 97 // Will expand zoom range to provide more rounded tick values. 98 // Works only with linear, log and date axes. 99 this.looseZoom = true; 100 // prop: clickReset 101 // Will reset plot zoom if single click on plot without drag. 102 this.clickReset = false; 103 // prop: dblClickReset 104 // Will reset plot zoom if double click on plot without drag. 105 this.dblClickReset = true; 106 // prop: showVerticalLine 107 // draw a vertical line across the plot which follows the cursor. 108 // When the line is near a data point, a special legend and/or tooltip can 109 // be updated with the data values. 110 this.showVerticalLine = false; 111 // prop: showHorizontalLine 112 // draw a horizontal line across the plot which follows the cursor. 113 this.showHorizontalLine = false; 114 // prop: constrainZoomTo 115 // 'none', 'x' or 'y' 116 this.constrainZoomTo = 'none'; 117 // // prop: autoscaleConstraint 118 // // when a constrained axis is specified, true will 119 // // auatoscale the adjacent axis. 120 // this.autoscaleConstraint = true; 121 this.shapeRenderer = new $.jqplot.ShapeRenderer(); 122 this._zoom = {start:[], end:[], started: false, zooming:false, isZoomed:false, axes:{start:{}, end:{}}, gridpos:{}, datapos:{}}; 123 this._tooltipElem; 124 this.zoomCanvas; 125 this.cursorCanvas; 126 // prop: intersectionThreshold 127 // pixel distance from data point or marker to consider cursor lines intersecting with point. 128 // If data point markers are not shown, this should be >= 1 or will often miss point intersections. 129 this.intersectionThreshold = 2; 130 // prop: showCursorLegend 131 // Replace the plot legend with an enhanced legend displaying intersection information. 132 this.showCursorLegend = false; 133 // prop: cursorLegendFormatString 134 // Format string used in the cursor legend. If showTooltipDataPosition is true, 135 // this will also be the default format string used by tooltipFormatString. 136 this.cursorLegendFormatString = $.jqplot.Cursor.cursorLegendFormatString; 137 // whether the cursor is over the grid or not. 138 this._oldHandlers = {onselectstart: null, ondrag: null, onmousedown: null}; 139 // prop: constrainOutsideZoom 140 // True to limit actual zoom area to edges of grid, even when zooming 141 // outside of plot area. That is, can't zoom out by mousing outside plot. 142 this.constrainOutsideZoom = true; 143 // prop: showTooltipOutsideZoom 144 // True will keep updating the tooltip when zooming of the grid. 145 this.showTooltipOutsideZoom = false; 146 // true if mouse is over grid, false if not. 147 this.onGrid = false; 148 $.extend(true, this, options); 149 }; 150 151 $.jqplot.Cursor.cursorLegendFormatString = '%s x:%s, y:%s'; 152 153 // called with scope of plot 154 $.jqplot.Cursor.init = function (target, data, opts){ 155 // add a cursor attribute to the plot 156 var options = opts || {}; 157 this.plugins.cursor = new $.jqplot.Cursor(options.cursor); 158 var c = this.plugins.cursor; 159 160 if (c.show) { 161 $.jqplot.eventListenerHooks.push(['jqplotMouseEnter', handleMouseEnter]); 162 $.jqplot.eventListenerHooks.push(['jqplotMouseLeave', handleMouseLeave]); 163 $.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMouseMove]); 164 165 if (c.showCursorLegend) { 166 opts.legend = opts.legend || {}; 167 opts.legend.renderer = $.jqplot.CursorLegendRenderer; 168 opts.legend.formatString = this.plugins.cursor.cursorLegendFormatString; 169 opts.legend.show = true; 170 } 171 172 if (c.zoom) { 173 $.jqplot.eventListenerHooks.push(['jqplotMouseDown', handleMouseDown]); 174 175 if (c.clickReset) { 176 $.jqplot.eventListenerHooks.push(['jqplotClick', handleClick]); 177 } 178 179 if (c.dblClickReset) { 180 $.jqplot.eventListenerHooks.push(['jqplotDblClick', handleDblClick]); 181 } 182 } 183 184 this.resetZoom = function() { 185 var axes = this.axes; 186 if (!c.zoomProxy) { 187 for (var ax in axes) { 188 axes[ax].reset(); 189 axes[ax]._ticks = []; 190 // fake out tick creation algorithm to make sure original auto 191 // computed format string is used if _overrideFormatString is true 192 if (c._zoom.axes[ax] !== undefined) { 193 axes[ax]._autoFormatString = c._zoom.axes[ax].tickFormatString; 194 } 195 } 196 this.redraw(); 197 } 198 else { 199 var ctx = this.plugins.cursor.zoomCanvas._ctx; 200 ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); 201 ctx = null; 202 } 203 this.plugins.cursor._zoom.isZoomed = false; 204 this.target.trigger('jqplotResetZoom', [this, this.plugins.cursor]); 205 }; 206 207 208 if (c.showTooltipDataPosition) { 209 c.showTooltipUnitPosition = false; 210 c.showTooltipGridPosition = false; 211 if (options.cursor.tooltipFormatString == undefined) { 212 c.tooltipFormatString = $.jqplot.Cursor.cursorLegendFormatString; 213 } 214 } 215 } 216 }; 217 218 // called with context of plot 219 $.jqplot.Cursor.postDraw = function() { 220 var c = this.plugins.cursor; 221 222 // Memory Leaks patch 223 if (c.zoomCanvas) { 224 c.zoomCanvas.resetCanvas(); 225 c.zoomCanvas = null; 226 } 227 228 if (c.cursorCanvas) { 229 c.cursorCanvas.resetCanvas(); 230 c.cursorCanvas = null; 231 } 232 233 if (c._tooltipElem) { 234 c._tooltipElem.emptyForce(); 235 c._tooltipElem = null; 236 } 237 238 239 if (c.zoom) { 240 c.zoomCanvas = new $.jqplot.GenericCanvas(); 241 this.eventCanvas._elem.before(c.zoomCanvas.createElement(this._gridPadding, 'jqplot-zoom-canvas', this._plotDimensions, this)); 242 c.zoomCanvas.setContext(); 243 } 244 245 var elem = document.createElement('div'); 246 c._tooltipElem = $(elem); 247 elem = null; 248 c._tooltipElem.addClass('jqplot-cursor-tooltip'); 249 c._tooltipElem.css({position:'absolute', display:'none'}); 250 251 252 if (c.zoomCanvas) { 253 c.zoomCanvas._elem.before(c._tooltipElem); 254 } 255 256 else { 257 this.eventCanvas._elem.before(c._tooltipElem); 258 } 259 260 if (c.showVerticalLine || c.showHorizontalLine) { 261 c.cursorCanvas = new $.jqplot.GenericCanvas(); 262 this.eventCanvas._elem.before(c.cursorCanvas.createElement(this._gridPadding, 'jqplot-cursor-canvas', this._plotDimensions, this)); 263 c.cursorCanvas.setContext(); 264 } 265 266 // if we are showing the positions in unit coordinates, and no axes groups 267 // were specified, create a default set. 268 if (c.showTooltipUnitPosition){ 269 if (c.tooltipAxisGroups.length === 0) { 270 var series = this.series; 271 var s; 272 var temp = []; 273 for (var i=0; i<series.length; i++) { 274 s = series[i]; 275 var ax = s.xaxis+','+s.yaxis; 276 if ($.inArray(ax, temp) == -1) { 277 temp.push(ax); 278 } 279 } 280 for (var i=0; i<temp.length; i++) { 281 c.tooltipAxisGroups.push(temp[i].split(',')); 282 } 283 } 284 } 285 }; 286 287 // Group: methods 288 // 289 // method: $.jqplot.Cursor.zoomProxy 290 // links targetPlot to controllerPlot so that plot zooming of 291 // targetPlot will be controlled by zooming on the controllerPlot. 292 // controllerPlot will not actually zoom, but acts as an 293 // overview plot. Note, the zoom options must be set to true for 294 // zoomProxy to work. 295 $.jqplot.Cursor.zoomProxy = function(targetPlot, controllerPlot) { 296 var tc = targetPlot.plugins.cursor; 297 var cc = controllerPlot.plugins.cursor; 298 tc.zoomTarget = true; 299 tc.zoom = true; 300 tc.style = 'auto'; 301 tc.dblClickReset = false; 302 cc.zoom = true; 303 cc.zoomProxy = true; 304 305 controllerPlot.target.bind('jqplotZoom', plotZoom); 306 controllerPlot.target.bind('jqplotResetZoom', plotReset); 307 308 function plotZoom(ev, gridpos, datapos, plot, cursor) { 309 tc.doZoom(gridpos, datapos, targetPlot, cursor); 310 } 311 312 function plotReset(ev, plot, cursor) { 313 targetPlot.resetZoom(); 314 } 315 }; 316 317 $.jqplot.Cursor.prototype.resetZoom = function(plot, cursor) { 318 var axes = plot.axes; 319 var cax = cursor._zoom.axes; 320 if (!plot.plugins.cursor.zoomProxy && cursor._zoom.isZoomed) { 321 for (var ax in axes) { 322 // axes[ax]._ticks = []; 323 // axes[ax].min = cax[ax].min; 324 // axes[ax].max = cax[ax].max; 325 // axes[ax].numberTicks = cax[ax].numberTicks; 326 // axes[ax].tickInterval = cax[ax].tickInterval; 327 // // for date axes 328 // axes[ax].daTickInterval = cax[ax].daTickInterval; 329 axes[ax].reset(); 330 axes[ax]._ticks = []; 331 // fake out tick creation algorithm to make sure original auto 332 // computed format string is used if _overrideFormatString is true 333 axes[ax]._autoFormatString = cax[ax].tickFormatString; 334 } 335 plot.redraw(); 336 cursor._zoom.isZoomed = false; 337 } 338 else { 339 var ctx = cursor.zoomCanvas._ctx; 340 ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); 341 ctx = null; 342 } 343 plot.target.trigger('jqplotResetZoom', [plot, cursor]); 344 }; 345 346 $.jqplot.Cursor.resetZoom = function(plot) { 347 plot.resetZoom(); 348 }; 349 350 $.jqplot.Cursor.prototype.doZoom = function (gridpos, datapos, plot, cursor) { 351 var c = cursor; 352 var axes = plot.axes; 353 var zaxes = c._zoom.axes; 354 var start = zaxes.start; 355 var end = zaxes.end; 356 var min, max, dp, span, 357 newmin, newmax, curax, _numberTicks, ret; 358 var ctx = plot.plugins.cursor.zoomCanvas._ctx; 359 // don't zoom if zoom area is too small (in pixels) 360 if ((c.constrainZoomTo == 'none' && Math.abs(gridpos.x - c._zoom.start[0]) > 6 && Math.abs(gridpos.y - c._zoom.start[1]) > 6) || (c.constrainZoomTo == 'x' && Math.abs(gridpos.x - c._zoom.start[0]) > 6) || (c.constrainZoomTo == 'y' && Math.abs(gridpos.y - c._zoom.start[1]) > 6)) { 361 if (!plot.plugins.cursor.zoomProxy) { 362 for (var ax in datapos) { 363 // make a copy of the original axes to revert back. 364 if (c._zoom.axes[ax] == undefined) { 365 c._zoom.axes[ax] = {}; 366 c._zoom.axes[ax].numberTicks = axes[ax].numberTicks; 367 c._zoom.axes[ax].tickInterval = axes[ax].tickInterval; 368 // for date axes... 369 c._zoom.axes[ax].daTickInterval = axes[ax].daTickInterval; 370 c._zoom.axes[ax].min = axes[ax].min; 371 c._zoom.axes[ax].max = axes[ax].max; 372 c._zoom.axes[ax].tickFormatString = (axes[ax].tickOptions != null) ? axes[ax].tickOptions.formatString : ''; 373 } 374 375 376 if ((c.constrainZoomTo == 'none') || (c.constrainZoomTo == 'x' && ax.charAt(0) == 'x') || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'y')) { 377 dp = datapos[ax]; 378 if (dp != null) { 379 if (dp > start[ax]) { 380 newmin = start[ax]; 381 newmax = dp; 382 } 383 else { 384 span = start[ax] - dp; 385 newmin = dp; 386 newmax = start[ax]; 387 } 388 389 curax = axes[ax]; 390 391 _numberTicks = null; 392 393 // if aligning this axis, use number of ticks from previous axis. 394 // Do I need to reset somehow if alignTicks is changed and then graph is replotted?? 395 if (curax.alignTicks) { 396 if (curax.name === 'x2axis' && plot.axes.xaxis.show) { 397 _numberTicks = plot.axes.xaxis.numberTicks; 398 } 399 else if (curax.name.charAt(0) === 'y' && curax.name !== 'yaxis' && curax.name !== 'yMidAxis' && plot.axes.yaxis.show) { 400 _numberTicks = plot.axes.yaxis.numberTicks; 401 } 402 } 403 404 if (this.looseZoom && (axes[ax].renderer.constructor === $.jqplot.LinearAxisRenderer || axes[ax].renderer.constructor === $.jqplot.LogAxisRenderer )) { //} || axes[ax].renderer.constructor === $.jqplot.DateAxisRenderer)) { 405 406 ret = $.jqplot.LinearTickGenerator(newmin, newmax, curax._scalefact, _numberTicks); 407 408 // if new minimum is less than "true" minimum of axis display, adjust it 409 if (axes[ax].tickInset && ret[0] < axes[ax].min + axes[ax].tickInset * axes[ax].tickInterval) { 410 ret[0] += ret[4]; 411 ret[2] -= 1; 412 } 413 414 // if new maximum is greater than "true" max of axis display, adjust it 415 if (axes[ax].tickInset && ret[1] > axes[ax].max - axes[ax].tickInset * axes[ax].tickInterval) { 416 ret[1] -= ret[4]; 417 ret[2] -= 1; 418 } 419 420 // for log axes, don't fall below current minimum, this will look bad and can't have 0 in range anyway. 421 if (axes[ax].renderer.constructor === $.jqplot.LogAxisRenderer && ret[0] < axes[ax].min) { 422 // remove a tick and shift min up 423 ret[0] += ret[4]; 424 ret[2] -= 1; 425 } 426 427 axes[ax].min = ret[0]; 428 axes[ax].max = ret[1]; 429 axes[ax]._autoFormatString = ret[3]; 430 axes[ax].numberTicks = ret[2]; 431 axes[ax].tickInterval = ret[4]; 432 // for date axes... 433 axes[ax].daTickInterval = [ret[4]/1000, 'seconds']; 434 } 435 else { 436 axes[ax].min = newmin; 437 axes[ax].max = newmax; 438 axes[ax].tickInterval = null; 439 axes[ax].numberTicks = null; 440 // for date axes... 441 axes[ax].daTickInterval = null; 442 } 443 444 axes[ax]._ticks = []; 445 } 446 } 447 448 // if ((c.constrainZoomTo == 'x' && ax.charAt(0) == 'y' && c.autoscaleConstraint) || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'x' && c.autoscaleConstraint)) { 449 // dp = datapos[ax]; 450 // if (dp != null) { 451 // axes[ax].max == null; 452 // axes[ax].min = null; 453 // } 454 // } 455 } 456 ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); 457 plot.redraw(); 458 c._zoom.isZoomed = true; 459 ctx = null; 460 } 461 plot.target.trigger('jqplotZoom', [gridpos, datapos, plot, cursor]); 462 } 463 }; 464 465 $.jqplot.preInitHooks.push($.jqplot.Cursor.init); 466 $.jqplot.postDrawHooks.push($.jqplot.Cursor.postDraw); 467 468 function updateTooltip(gridpos, datapos, plot) { 469 var c = plot.plugins.cursor; 470 var s = ''; 471 var addbr = false; 472 if (c.showTooltipGridPosition) { 473 s = gridpos.x+', '+gridpos.y; 474 addbr = true; 475 } 476 if (c.showTooltipUnitPosition) { 477 var g; 478 for (var i=0; i<c.tooltipAxisGroups.length; i++) { 479 g = c.tooltipAxisGroups[i]; 480 if (addbr) { 481 s += '<br />'; 482 } 483 if (c.useAxesFormatters) { 484 for (var j=0; j<g.length; j++) { 485 if (j) { 486 s += ', '; 487 } 488 var af = plot.axes[g[j]]._ticks[0].formatter; 489 var afstr = plot.axes[g[j]]._ticks[0].formatString; 490 s += af(afstr, datapos[g[j]]); 491 } 492 } 493 else { 494 s += $.jqplot.sprintf(c.tooltipFormatString, datapos[g[0]], datapos[g[1]]); 495 } 496 addbr = true; 497 } 498 } 499 500 if (c.showTooltipDataPosition) { 501 var series = plot.series; 502 var ret = getIntersectingPoints(plot, gridpos.x, gridpos.y); 503 var addbr = false; 504 505 for (var i = 0; i< series.length; i++) { 506 if (series[i].show) { 507 var idx = series[i].index; 508 var label = series[i].label.toString(); 509 var cellid = $.inArray(idx, ret.indices); 510 var sx = undefined; 511 var sy = undefined; 512 if (cellid != -1) { 513 var data = ret.data[cellid].data; 514 if (c.useAxesFormatters) { 515 var xf = series[i]._xaxis._ticks[0].formatter; 516 var yf = series[i]._yaxis._ticks[0].formatter; 517 var xfstr = series[i]._xaxis._ticks[0].formatString; 518 var yfstr = series[i]._yaxis._ticks[0].formatString; 519 sx = xf(xfstr, data[0]); 520 sy = yf(yfstr, data[1]); 521 } 522 else { 523 sx = data[0]; 524 sy = data[1]; 525 } 526 if (addbr) { 527 s += '<br />'; 528 } 529 s += $.jqplot.sprintf(c.tooltipFormatString, label, sx, sy); 530 addbr = true; 531 } 532 } 533 } 534 535 } 536 c._tooltipElem.html(s); 537 } 538 539 function moveLine(gridpos, plot) { 540 var c = plot.plugins.cursor; 541 var ctx = c.cursorCanvas._ctx; 542 ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); 543 if (c.showVerticalLine) { 544 c.shapeRenderer.draw(ctx, [[gridpos.x, 0], [gridpos.x, ctx.canvas.height]]); 545 } 546 if (c.showHorizontalLine) { 547 c.shapeRenderer.draw(ctx, [[0, gridpos.y], [ctx.canvas.width, gridpos.y]]); 548 } 549 var ret = getIntersectingPoints(plot, gridpos.x, gridpos.y); 550 if (c.showCursorLegend) { 551 var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label'); 552 for (var i=0; i<cells.length; i++) { 553 var idx = $(cells[i]).data('seriesIndex'); 554 var series = plot.series[idx]; 555 var label = series.label.toString(); 556 var cellid = $.inArray(idx, ret.indices); 557 var sx = undefined; 558 var sy = undefined; 559 if (cellid != -1) { 560 var data = ret.data[cellid].data; 561 if (c.useAxesFormatters) { 562 var xf = series._xaxis._ticks[0].formatter; 563 var yf = series._yaxis._ticks[0].formatter; 564 var xfstr = series._xaxis._ticks[0].formatString; 565 var yfstr = series._yaxis._ticks[0].formatString; 566 sx = xf(xfstr, data[0]); 567 sy = yf(yfstr, data[1]); 568 } 569 else { 570 sx = data[0]; 571 sy = data[1]; 572 } 573 } 574 if (plot.legend.escapeHtml) { 575 $(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, sx, sy)); 576 } 577 else { 578 $(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, sx, sy)); 579 } 580 } 581 } 582 ctx = null; 583 } 584 585 function getIntersectingPoints(plot, x, y) { 586 var ret = {indices:[], data:[]}; 587 var s, i, d0, d, j, r, p; 588 var threshold; 589 var c = plot.plugins.cursor; 590 for (var i=0; i<plot.series.length; i++) { 591 s = plot.series[i]; 592 r = s.renderer; 593 if (s.show) { 594 threshold = c.intersectionThreshold; 595 if (s.showMarker) { 596 threshold += s.markerRenderer.size/2; 597 } 598 for (var j=0; j<s.gridData.length; j++) { 599 p = s.gridData[j]; 600 // check vertical line 601 if (c.showVerticalLine) { 602 if (Math.abs(x-p[0]) <= threshold) { 603 ret.indices.push(i); 604 ret.data.push({seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}); 605 } 606 } 607 } 608 } 609 } 610 return ret; 611 } 612 613 function moveTooltip(gridpos, plot) { 614 var c = plot.plugins.cursor; 615 var elem = c._tooltipElem; 616 switch (c.tooltipLocation) { 617 case 'nw': 618 var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset; 619 var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true); 620 break; 621 case 'n': 622 var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2; 623 var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true); 624 break; 625 case 'ne': 626 var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset; 627 var y = gridpos.y + plot._gridPadding.top - c.tooltipOffset - elem.outerHeight(true); 628 break; 629 case 'e': 630 var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset; 631 var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2; 632 break; 633 case 'se': 634 var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset; 635 var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset; 636 break; 637 case 's': 638 var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2; 639 var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset; 640 break; 641 case 'sw': 642 var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset; 643 var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset; 644 break; 645 case 'w': 646 var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - c.tooltipOffset; 647 var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2; 648 break; 649 default: 650 var x = gridpos.x + plot._gridPadding.left + c.tooltipOffset; 651 var y = gridpos.y + plot._gridPadding.top + c.tooltipOffset; 652 break; 653 } 654 655 elem.css('left', x); 656 elem.css('top', y); 657 elem = null; 658 } 659 660 function positionTooltip(plot) { 661 // fake a grid for positioning 662 var grid = plot._gridPadding; 663 var c = plot.plugins.cursor; 664 var elem = c._tooltipElem; 665 switch (c.tooltipLocation) { 666 case 'nw': 667 var a = grid.left + c.tooltipOffset; 668 var b = grid.top + c.tooltipOffset; 669 elem.css('left', a); 670 elem.css('top', b); 671 break; 672 case 'n': 673 var a = (grid.left + (plot._plotDimensions.width - grid.right))/2 - elem.outerWidth(true)/2; 674 var b = grid.top + c.tooltipOffset; 675 elem.css('left', a); 676 elem.css('top', b); 677 break; 678 case 'ne': 679 var a = grid.right + c.tooltipOffset; 680 var b = grid.top + c.tooltipOffset; 681 elem.css({right:a, top:b}); 682 break; 683 case 'e': 684 var a = grid.right + c.tooltipOffset; 685 var b = (grid.top + (plot._plotDimensions.height - grid.bottom))/2 - elem.outerHeight(true)/2; 686 elem.css({right:a, top:b}); 687 break; 688 case 'se': 689 var a = grid.right + c.tooltipOffset; 690 var b = grid.bottom + c.tooltipOffset; 691 elem.css({right:a, bottom:b}); 692 break; 693 case 's': 694 var a = (grid.left + (plot._plotDimensions.width - grid.right))/2 - elem.outerWidth(true)/2; 695 var b = grid.bottom + c.tooltipOffset; 696 elem.css({left:a, bottom:b}); 697 break; 698 case 'sw': 699 var a = grid.left + c.tooltipOffset; 700 var b = grid.bottom + c.tooltipOffset; 701 elem.css({left:a, bottom:b}); 702 break; 703 case 'w': 704 var a = grid.left + c.tooltipOffset; 705 var b = (grid.top + (plot._plotDimensions.height - grid.bottom))/2 - elem.outerHeight(true)/2; 706 elem.css({left:a, top:b}); 707 break; 708 default: // same as 'se' 709 var a = grid.right - c.tooltipOffset; 710 var b = grid.bottom + c.tooltipOffset; 711 elem.css({right:a, bottom:b}); 712 break; 713 } 714 elem = null; 715 } 716 717 function handleClick (ev, gridpos, datapos, neighbor, plot) { 718 ev.preventDefault(); 719 ev.stopImmediatePropagation(); 720 var c = plot.plugins.cursor; 721 if (c.clickReset) { 722 c.resetZoom(plot, c); 723 } 724 var sel = window.getSelection; 725 if (document.selection && document.selection.empty) 726 { 727 document.selection.empty(); 728 } 729 else if (sel && !sel().isCollapsed) { 730 sel().collapse(); 731 } 732 return false; 733 } 734 735 function handleDblClick (ev, gridpos, datapos, neighbor, plot) { 736 ev.preventDefault(); 737 ev.stopImmediatePropagation(); 738 var c = plot.plugins.cursor; 739 if (c.dblClickReset) { 740 c.resetZoom(plot, c); 741 } 742 var sel = window.getSelection; 743 if (document.selection && document.selection.empty) 744 { 745 document.selection.empty(); 746 } 747 else if (sel && !sel().isCollapsed) { 748 sel().collapse(); 749 } 750 return false; 751 } 752 753 function handleMouseLeave(ev, gridpos, datapos, neighbor, plot) { 754 var c = plot.plugins.cursor; 755 c.onGrid = false; 756 if (c.show) { 757 $(ev.target).css('cursor', c.previousCursor); 758 if (c.showTooltip && !(c._zoom.zooming && c.showTooltipOutsideZoom && !c.constrainOutsideZoom)) { 759 c._tooltipElem.empty(); 760 c._tooltipElem.hide(); 761 } 762 if (c.zoom) { 763 c._zoom.gridpos = gridpos; 764 c._zoom.datapos = datapos; 765 } 766 if (c.showVerticalLine || c.showHorizontalLine) { 767 var ctx = c.cursorCanvas._ctx; 768 ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); 769 ctx = null; 770 } 771 if (c.showCursorLegend) { 772 var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label'); 773 for (var i=0; i<cells.length; i++) { 774 var idx = $(cells[i]).data('seriesIndex'); 775 var series = plot.series[idx]; 776 var label = series.label.toString(); 777 if (plot.legend.escapeHtml) { 778 $(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined)); 779 } 780 else { 781 $(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined)); 782 } 783 784 } 785 } 786 } 787 } 788 789 function handleMouseEnter(ev, gridpos, datapos, neighbor, plot) { 790 var c = plot.plugins.cursor; 791 c.onGrid = true; 792 if (c.show) { 793 c.previousCursor = ev.target.style.cursor; 794 ev.target.style.cursor = c.style; 795 if (c.showTooltip) { 796 updateTooltip(gridpos, datapos, plot); 797 if (c.followMouse) { 798 moveTooltip(gridpos, plot); 799 } 800 else { 801 positionTooltip(plot); 802 } 803 c._tooltipElem.show(); 804 } 805 if (c.showVerticalLine || c.showHorizontalLine) { 806 moveLine(gridpos, plot); 807 } 808 } 809 810 } 811 812 function handleMouseMove(ev, gridpos, datapos, neighbor, plot) { 813 var c = plot.plugins.cursor; 814 if (c.show) { 815 if (c.showTooltip) { 816 updateTooltip(gridpos, datapos, plot); 817 if (c.followMouse) { 818 moveTooltip(gridpos, plot); 819 } 820 } 821 if (c.showVerticalLine || c.showHorizontalLine) { 822 moveLine(gridpos, plot); 823 } 824 } 825 } 826 827 function getEventPosition(ev) { 828 var plot = ev.data.plot; 829 var go = plot.eventCanvas._elem.offset(); 830 var gridPos = {x:ev.pageX - go.left, y:ev.pageY - go.top}; 831 ////// 832 // TO DO: handle yMidAxis 833 ////// 834 var dataPos = {xaxis:null, yaxis:null, x2axis:null, y2axis:null, y3axis:null, y4axis:null, y5axis:null, y6axis:null, y7axis:null, y8axis:null, y9axis:null, yMidAxis:null}; 835 var an = ['xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis', 'yMidAxis']; 836 var ax = plot.axes; 837 var n, axis; 838 for (n=11; n>0; n--) { 839 axis = an[n-1]; 840 if (ax[axis].show) { 841 dataPos[axis] = ax[axis].series_p2u(gridPos[axis.charAt(0)]); 842 } 843 } 844 845 return {offsets:go, gridPos:gridPos, dataPos:dataPos}; 846 } 847 848 function handleZoomMove(ev) { 849 var plot = ev.data.plot; 850 var c = plot.plugins.cursor; 851 // don't do anything if not on grid. 852 if (c.show && c.zoom && c._zoom.started && !c.zoomTarget) { 853 ev.preventDefault(); 854 var ctx = c.zoomCanvas._ctx; 855 var positions = getEventPosition(ev); 856 var gridpos = positions.gridPos; 857 var datapos = positions.dataPos; 858 c._zoom.gridpos = gridpos; 859 c._zoom.datapos = datapos; 860 c._zoom.zooming = true; 861 var xpos = gridpos.x; 862 var ypos = gridpos.y; 863 var height = ctx.canvas.height; 864 var width = ctx.canvas.width; 865 if (c.showTooltip && !c.onGrid && c.showTooltipOutsideZoom) { 866 updateTooltip(gridpos, datapos, plot); 867 if (c.followMouse) { 868 moveTooltip(gridpos, plot); 869 } 870 } 871 if (c.constrainZoomTo == 'x') { 872 c._zoom.end = [xpos, height]; 873 } 874 else if (c.constrainZoomTo == 'y') { 875 c._zoom.end = [width, ypos]; 876 } 877 else { 878 c._zoom.end = [xpos, ypos]; 879 } 880 var sel = window.getSelection; 881 if (document.selection && document.selection.empty) 882 { 883 document.selection.empty(); 884 } 885 else if (sel && !sel().isCollapsed) { 886 sel().collapse(); 887 } 888 drawZoomBox.call(c); 889 ctx = null; 890 } 891 } 892 893 function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { 894 var c = plot.plugins.cursor; 895 if(plot.plugins.mobile){ 896 $(document).one('vmouseup.jqplot_cursor', {plot:plot}, handleMouseUp); 897 } else { 898 $(document).one('mouseup.jqplot_cursor', {plot:plot}, handleMouseUp); 899 } 900 var axes = plot.axes; 901 if (document.onselectstart != undefined) { 902 c._oldHandlers.onselectstart = document.onselectstart; 903 document.onselectstart = function () { return false; }; 904 } 905 if (document.ondrag != undefined) { 906 c._oldHandlers.ondrag = document.ondrag; 907 document.ondrag = function () { return false; }; 908 } 909 if (document.onmousedown != undefined) { 910 c._oldHandlers.onmousedown = document.onmousedown; 911 document.onmousedown = function () { return false; }; 912 } 913 if (c.zoom) { 914 if (!c.zoomProxy) { 915 var ctx = c.zoomCanvas._ctx; 916 ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); 917 ctx = null; 918 } 919 if (c.constrainZoomTo == 'x') { 920 c._zoom.start = [gridpos.x, 0]; 921 } 922 else if (c.constrainZoomTo == 'y') { 923 c._zoom.start = [0, gridpos.y]; 924 } 925 else { 926 c._zoom.start = [gridpos.x, gridpos.y]; 927 } 928 c._zoom.started = true; 929 for (var ax in datapos) { 930 // get zoom starting position. 931 c._zoom.axes.start[ax] = datapos[ax]; 932 } 933 if(plot.plugins.mobile){ 934 $(document).bind('vmousemove.jqplotCursor', {plot:plot}, handleZoomMove); 935 } else { 936 $(document).bind('mousemove.jqplotCursor', {plot:plot}, handleZoomMove); 937 } 938 939 } 940 } 941 942 function handleMouseUp(ev) { 943 var plot = ev.data.plot; 944 var c = plot.plugins.cursor; 945 if (c.zoom && c._zoom.zooming && !c.zoomTarget) { 946 var xpos = c._zoom.gridpos.x; 947 var ypos = c._zoom.gridpos.y; 948 var datapos = c._zoom.datapos; 949 var height = c.zoomCanvas._ctx.canvas.height; 950 var width = c.zoomCanvas._ctx.canvas.width; 951 var axes = plot.axes; 952 953 if (c.constrainOutsideZoom && !c.onGrid) { 954 if (xpos < 0) { xpos = 0; } 955 else if (xpos > width) { xpos = width; } 956 if (ypos < 0) { ypos = 0; } 957 else if (ypos > height) { ypos = height; } 958 959 for (var axis in datapos) { 960 if (datapos[axis]) { 961 if (axis.charAt(0) == 'x') { 962 datapos[axis] = axes[axis].series_p2u(xpos); 963 } 964 else { 965 datapos[axis] = axes[axis].series_p2u(ypos); 966 } 967 } 968 } 969 } 970 971 if (c.constrainZoomTo == 'x') { 972 ypos = height; 973 } 974 else if (c.constrainZoomTo == 'y') { 975 xpos = width; 976 } 977 c._zoom.end = [xpos, ypos]; 978 c._zoom.gridpos = {x:xpos, y:ypos}; 979 980 c.doZoom(c._zoom.gridpos, datapos, plot, c); 981 } 982 c._zoom.started = false; 983 c._zoom.zooming = false; 984 985 $(document).unbind('mousemove.jqplotCursor', handleZoomMove); 986 987 if (document.onselectstart != undefined && c._oldHandlers.onselectstart != null){ 988 document.onselectstart = c._oldHandlers.onselectstart; 989 c._oldHandlers.onselectstart = null; 990 } 991 if (document.ondrag != undefined && c._oldHandlers.ondrag != null){ 992 document.ondrag = c._oldHandlers.ondrag; 993 c._oldHandlers.ondrag = null; 994 } 995 if (document.onmousedown != undefined && c._oldHandlers.onmousedown != null){ 996 document.onmousedown = c._oldHandlers.onmousedown; 997 c._oldHandlers.onmousedown = null; 998 } 999 1000 } 1001 1002 function drawZoomBox() { 1003 var start = this._zoom.start; 1004 var end = this._zoom.end; 1005 var ctx = this.zoomCanvas._ctx; 1006 var l, t, h, w; 1007 if (end[0] > start[0]) { 1008 l = start[0]; 1009 w = end[0] - start[0]; 1010 } 1011 else { 1012 l = end[0]; 1013 w = start[0] - end[0]; 1014 } 1015 if (end[1] > start[1]) { 1016 t = start[1]; 1017 h = end[1] - start[1]; 1018 } 1019 else { 1020 t = end[1]; 1021 h = start[1] - end[1]; 1022 } 1023 ctx.fillStyle = 'rgba(0,0,0,0.2)'; 1024 ctx.strokeStyle = '#999999'; 1025 ctx.lineWidth = 1.0; 1026 ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); 1027 ctx.fillRect(0,0,ctx.canvas.width, ctx.canvas.height); 1028 ctx.clearRect(l, t, w, h); 1029 // IE won't show transparent fill rect, so stroke a rect also. 1030 ctx.strokeRect(l,t,w,h); 1031 ctx = null; 1032 } 1033 1034 $.jqplot.CursorLegendRenderer = function(options) { 1035 $.jqplot.TableLegendRenderer.call(this, options); 1036 this.formatString = '%s'; 1037 }; 1038 1039 $.jqplot.CursorLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); 1040 $.jqplot.CursorLegendRenderer.prototype.constructor = $.jqplot.CursorLegendRenderer; 1041 1042 // called in context of a Legend 1043 $.jqplot.CursorLegendRenderer.prototype.draw = function() { 1044 if (this._elem) { 1045 this._elem.emptyForce(); 1046 this._elem = null; 1047 } 1048 if (this.show) { 1049 var series = this._series, s; 1050 // make a table. one line label per row. 1051 var elem = document.createElement('div'); 1052 this._elem = $(elem); 1053 elem = null; 1054 this._elem.addClass('jqplot-legend jqplot-cursor-legend'); 1055 this._elem.css('position', 'absolute'); 1056 1057 var pad = false; 1058 for (var i = 0; i< series.length; i++) { 1059 s = series[i]; 1060 if (s.show && s.showLabel) { 1061 var lt = $.jqplot.sprintf(this.formatString, s.label.toString()); 1062 if (lt) { 1063 var color = s.color; 1064 if (s._stack && !s.fill) { 1065 color = ''; 1066 } 1067 addrow.call(this, lt, color, pad, i); 1068 pad = true; 1069 } 1070 // let plugins add more rows to legend. Used by trend line plugin. 1071 for (var j=0; j<$.jqplot.addLegendRowHooks.length; j++) { 1072 var item = $.jqplot.addLegendRowHooks[j].call(this, s); 1073 if (item) { 1074 addrow.call(this, item.label, item.color, pad); 1075 pad = true; 1076 } 1077 } 1078 } 1079 } 1080 series = s = null; 1081 delete series; 1082 delete s; 1083 } 1084 1085 function addrow(label, color, pad, idx) { 1086 var rs = (pad) ? this.rowSpacing : '0'; 1087 var tr = $('<tr class="jqplot-legend jqplot-cursor-legend"></tr>').appendTo(this._elem); 1088 tr.data('seriesIndex', idx); 1089 $('<td class="jqplot-legend jqplot-cursor-legend-swatch" style="padding-top:'+rs+';">'+ 1090 '<div style="border:1px solid #cccccc;padding:0.2em;">'+ 1091 '<div class="jqplot-cursor-legend-swatch" style="background-color:'+color+';"></div>'+ 1092 '</div></td>').appendTo(tr); 1093 var td = $('<td class="jqplot-legend jqplot-cursor-legend-label" style="vertical-align:middle;padding-top:'+rs+';"></td>'); 1094 td.appendTo(tr); 1095 td.data('seriesIndex', idx); 1096 if (this.escapeHtml) { 1097 td.text(label); 1098 } 1099 else { 1100 td.html(label); 1101 } 1102 tr = null; 1103 td = null; 1104 } 1105 return this._elem; 1106 }; 1107 1108 })(jQuery);
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:08:37 2014 | Cross-referenced by PHPXref 0.7.1 |