[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 YUI.add('yui2-profilerviewer', function(Y) { 2 var YAHOO = Y.YUI2; 3 /* 4 Copyright (c) 2011, Yahoo! Inc. All rights reserved. 5 Code licensed under the BSD License: 6 http://developer.yahoo.com/yui/license.html 7 version: 2.9.0 8 */ 9 (function() { 10 11 /** 12 * The ProfilerViewer module provides a graphical display for viewing 13 * the output of the YUI Profiler <http://developer.yahoo.com/yui/profiler>. 14 * @module profilerviewer 15 * @requires yahoo, dom, event, element, profiler, yuiloader 16 */ 17 18 /** 19 * A widget to view YUI Profiler output. 20 * @namespace YAHOO.widget 21 * @class ProfilerViewer 22 * @extends YAHOO.util.Element 23 * @constructor 24 * @param {HTMLElement | String | Object} el(optional) The html 25 * element into which the ProfileViewer should be rendered. 26 * An element will be created if none provided. 27 * @param {Object} attr (optional) A key map of the ProfilerViewer's 28 * initial attributes. Ignored if first arg is an attributes object. 29 */ 30 YAHOO.widget.ProfilerViewer = function(el, attr) { 31 attr = attr || {}; 32 if (arguments.length == 1 && !YAHOO.lang.isString(el) && !el.nodeName) { 33 attr = el; 34 el = attr.element || null; 35 } 36 if (!el && !attr.element) { 37 el = this._createProfilerViewerElement(); 38 } 39 40 YAHOO.widget.ProfilerViewer.superclass.constructor.call(this, el, attr); 41 42 this._init(); 43 44 }; 45 46 YAHOO.extend(YAHOO.widget.ProfilerViewer, YAHOO.util.Element); 47 48 // Static members of YAHOO.widget.ProfilerViewer: 49 YAHOO.lang.augmentObject(YAHOO.widget.ProfilerViewer, { 50 /** 51 * Classname for ProfilerViewer containing element. 52 * @static 53 * @property CLASS 54 * @type string 55 * @public 56 * @default "yui-pv" 57 */ 58 CLASS: 'yui-pv', 59 60 /** 61 * Classname for ProfilerViewer button dashboard. 62 * @static 63 * @property CLASS_DASHBOARD 64 * @type string 65 * @public 66 * @default "yui-pv-dashboard" 67 */ 68 CLASS_DASHBOARD: 'yui-pv-dashboard', 69 70 /** 71 * Classname for the "refresh data" button. 72 * @static 73 * @property CLASS_REFRESH 74 * @type string 75 * @public 76 * @default "yui-pv-refresh" 77 */ 78 CLASS_REFRESH: 'yui-pv-refresh', 79 80 /** 81 * Classname for busy indicator in the dashboard. 82 * @static 83 * @property CLASS_BUSY 84 * @type string 85 * @public 86 * @default "yui-pv-busy" 87 */ 88 CLASS_BUSY: 'yui-pv-busy', 89 90 /** 91 * Classname for element containing the chart and chart 92 * legend elements. 93 * @static 94 * @property CLASS_CHART_CONTAINER 95 * @type string 96 * @public 97 * @default "yui-pv-chartcontainer" 98 */ 99 CLASS_CHART_CONTAINER: 'yui-pv-chartcontainer', 100 101 /** 102 * Classname for element containing the chart. 103 * @static 104 * @property CLASS_CHART 105 * @type string 106 * @public 107 * @default "yui-pv-chart" 108 */ 109 CLASS_CHART: 'yui-pv-chart', 110 111 /** 112 * Classname for element containing the chart's legend. 113 * @static 114 * @property CLASS_CHART_LEGEND 115 * @type string 116 * @public 117 * @default "yui-pv-chartlegend" 118 */ 119 CLASS_CHART_LEGEND: 'yui-pv-chartlegend', 120 121 /** 122 * Classname for element containing the datatable. 123 * @static 124 * @property CLASS_TABLE 125 * @type string 126 * @public 127 * @default "yui-pv-table" 128 */ 129 CLASS_TABLE: 'yui-pv-table', 130 131 /** 132 * HTML strings used in the UI. Values will be inserted into DOM with innerHTML. 133 * @static 134 * @property STRINGS 135 * @object 136 * @public 137 * @default English language strings for UI. 138 */ 139 STRINGS: { 140 title: "YUI ProfilerViewer", 141 buttons: { 142 viewprofiler: "View Profiler Data", 143 hideprofiler: "Hide Profiler Report", 144 showchart: "Show Chart", 145 hidechart: "Hide Chart", 146 refreshdata: "Refresh Data" 147 }, 148 colHeads: { 149 //key: [column head label, width in pixels] 150 fn: ["Function/Method", null], //must auto-size 151 calls: ["Calls", 40], 152 avg: ["Average", 80], 153 min: ["Shortest", 70], 154 max: ["Longest", 70], 155 total: ["Total Time", 70], 156 pct: ["Percent", 70] 157 }, 158 millisecondsAbbrev: "ms", 159 initMessage: "initialiazing chart...", 160 installFlashMessage: "Unable to load Flash content. The YUI Charts Control requires Flash Player 9.0.45 or higher. You can download the latest version of Flash Player from the <a href='http://www.adobe.com/go/getflashplayer'>Adobe Flash Player Download Center</a>." 161 }, 162 163 /** 164 * Function used to format numbers in milliseconds 165 * for chart; must be publicly accessible, per Charts spec. 166 * @static 167 * @property timeAxisLabelFunction 168 * @type function 169 * @private 170 */ 171 timeAxisLabelFunction: function(n) { 172 var a = (n === Math.floor(n)) ? n : (Math.round(n*1000))/1000; 173 return (a + " " + YAHOO.widget.ProfilerViewer.STRINGS.millisecondsAbbrev); 174 }, 175 176 /** 177 * Function used to format percent numbers for chart; must 178 * be publicly accessible, per Charts spec. 179 * @static 180 * @property percentAxisLabelFunction 181 * @type function 182 * @private 183 */ 184 percentAxisLabelFunction: function(n) { 185 var a = (n === Math.floor(n)) ? n : (Math.round(n*100))/100; 186 return (a + "%"); 187 } 188 189 190 },true); 191 192 193 // 194 // STANDARD SHORTCUTS 195 // 196 var Dom = YAHOO.util.Dom; 197 var Event = YAHOO.util.Event; 198 var Profiler = YAHOO.tool.Profiler; 199 var PV = YAHOO.widget.ProfilerViewer; 200 var proto = PV.prototype; 201 202 203 // 204 // PUBLIC METHODS 205 // 206 207 /** 208 * Refreshes the data displayed in the ProfilerViewer. When called, 209 * this will invoke a refresh of the DataTable and (if displayed) 210 * the Chart. 211 * @method refreshData 212 * @return void 213 * @public 214 */ 215 proto.refreshData = function() { 216 this.fireEvent("dataRefreshEvent"); 217 }; 218 219 /** 220 * Returns the element containing the console's header. 221 * @method getHeadEl 222 * @return HTMLElement 223 * @public 224 */ 225 proto.getHeadEl = function() { 226 return (this._headEl) ? Dom.get(this._headEl) : false; 227 }; 228 229 /** 230 * Returns the element containing the console's body, including 231 * the chart and the datatable.. 232 * @method getBodyEl 233 * @return HTMLElement 234 * @public 235 */ 236 proto.getBodyEl = function() { 237 return (this._bodyEl) ? Dom.get(this._bodyEl) : false; 238 }; 239 240 /** 241 * Returns the element containing the console's chart. 242 * @method getChartEl 243 * @return HTMLElement 244 * @public 245 */ 246 proto.getChartEl = function() { 247 return (this._chartEl) ? Dom.get(this._chartEl) : false; 248 }; 249 250 /** 251 * Returns the element containing the console's dataTable. 252 * @method getTableEl 253 * @return HTMLElement 254 * @public 255 */ 256 proto.getTableEl = function() { 257 return (this._tableEl) ? Dom.get(this._tableEl) : false; 258 }; 259 260 /** 261 * Returns the element containing the console's DataTable 262 * instance. 263 * @method getDataTable 264 * @return YAHOO.widget.DataTable 265 * @public 266 */ 267 proto.getDataTable = function() { 268 return this._dataTable; 269 }; 270 271 /** 272 * Returns the element containing the console's Chart instance. 273 * @method getChart 274 * @return YAHOO.widget.BarChart 275 * @public 276 */ 277 proto.getChart = function() { 278 return this._chart; 279 }; 280 281 282 // 283 // PRIVATE PROPERTIES 284 // 285 proto._rendered = false; 286 proto._headEl = null; 287 proto._bodyEl = null; 288 proto._toggleVisibleEl = null; 289 proto._busyEl = null; 290 proto._busy = false; 291 292 proto._tableEl = null; 293 proto._dataTable = null; 294 295 proto._chartEl = null; 296 proto._chartLegendEl = null; 297 proto._chartElHeight = 250; 298 proto._chart = null; 299 proto._chartInitialized = false; 300 301 // 302 // PRIVATE METHODS 303 // 304 305 proto._init = function() { 306 /** 307 * CUSTOM EVENTS 308 **/ 309 310 /** 311 * Fired when a data refresh is requested. No arguments are passed 312 * with this event. 313 * 314 * @event refreshDataEvent 315 */ 316 this.createEvent("dataRefreshEvent"); 317 318 /** 319 * Fired when the viewer canvas first renders. No arguments are passed 320 * with this event. 321 * 322 * @event renderEvent 323 */ 324 this.createEvent("renderEvent"); 325 326 this.on("dataRefreshEvent", this._refreshDataTable, this, true); 327 328 this._initLauncherDOM(); 329 330 if(this.get("showChart")) { 331 this.on("sortedByChange", this._refreshChart); 332 } 333 334 }; 335 336 /** 337 * If no element is passed in, create it as the first element 338 * in the document. 339 * @method _createProfilerViewerElement 340 * @return HTMLElement 341 * @private 342 */ 343 proto._createProfilerViewerElement = function() { 344 345 var el = document.createElement("div"); 346 document.body.insertBefore(el, document.body.firstChild); 347 Dom.addClass(el, this.SKIN_CLASS); 348 Dom.addClass(el, PV.CLASS); 349 return el; 350 }; 351 352 /** 353 * Provides a readable name for the ProfilerViewer instance. 354 * @method toString 355 * @return String 356 * @private 357 */ 358 proto.toString = function() { 359 return "ProfilerViewer " + (this.get('id') || this.get('tagName')); 360 }; 361 362 /** 363 * Toggles visibility of the viewer canvas. 364 * @method _toggleVisible 365 * @return void 366 * @private 367 */ 368 proto._toggleVisible = function() { 369 370 var newVis = (this.get("visible")) ? false : true; 371 this.set("visible", newVis); 372 }; 373 374 /** 375 * Shows the viewer canvas. 376 * @method show 377 * @return void 378 * @private 379 */ 380 proto._show = function() { 381 if(!this._busy) { 382 this._setBusyState(true); 383 if(!this._rendered) { 384 var loader = new YAHOO.util.YUILoader(); 385 if (this.get("base")) { 386 loader.base = this.get("base"); 387 } 388 389 var modules = ["datatable"]; 390 if(this.get("showChart")) { 391 modules.push("charts"); 392 } 393 394 loader.insert({ require: modules, 395 onSuccess: function() { 396 this._render(); 397 }, 398 scope: this}); 399 } else { 400 var el = this.get("element"); 401 Dom.removeClass(el, "yui-pv-minimized"); 402 this._toggleVisibleEl.innerHTML = PV.STRINGS.buttons.hideprofiler; 403 404 //The Flash Charts component can't be set to display:none, 405 //and even after positioning it offscreen the screen 406 //may fail to repaint in some browsers. Adding an empty 407 //style rule to the console body can help force a repaint: 408 Dom.addClass(el, "yui-pv-null"); 409 Dom.removeClass(el, "yui-pv-null"); 410 411 //Always refresh data when changing to visible: 412 this.refreshData(); 413 } 414 } 415 }; 416 417 /** 418 * Hides the viewer canvas. 419 * @method hide 420 * @return void 421 * @private 422 */ 423 proto._hide = function() { 424 this._toggleVisibleEl.innerHTML = PV.STRINGS.buttons.viewprofiler; 425 Dom.addClass(this.get("element"), "yui-pv-minimized"); 426 }; 427 428 /** 429 * Render the viewer canvas 430 * @method _render 431 * @return void 432 * @private 433 */ 434 proto._render = function() { 435 436 Dom.removeClass(this.get("element"), "yui-pv-minimized"); 437 438 this._initViewerDOM(); 439 this._initDataTable(); 440 if(this.get("showChart")) { 441 this._initChartDOM(); 442 this._initChart(); 443 } 444 this._rendered = true; 445 this._toggleVisibleEl.innerHTML = PV.STRINGS.buttons.hideprofiler; 446 447 this.fireEvent("renderEvent"); 448 449 }; 450 451 /** 452 * Set up the DOM structure for the ProfilerViewer launcher. 453 * @method _initLauncherDOM 454 * @private 455 */ 456 proto._initLauncherDOM = function() { 457 458 var el = this.get("element"); 459 Dom.addClass(el, PV.CLASS); 460 Dom.addClass(el, "yui-pv-minimized"); 461 462 this._headEl = document.createElement("div"); 463 Dom.addClass(this._headEl, "hd"); 464 465 var s = PV.STRINGS.buttons; 466 var b = (this.get("visible")) ? s.hideprofiler : s.viewprofiler; 467 468 this._toggleVisibleEl = this._createButton(b, this._headEl); 469 470 this._refreshEl = this._createButton(s.refreshdata, this._headEl); 471 Dom.addClass(this._refreshEl, PV.CLASS_REFRESH); 472 473 this._busyEl = document.createElement("span"); 474 this._headEl.appendChild(this._busyEl); 475 476 var title = document.createElement("h4"); 477 title.innerHTML = PV.STRINGS.title; 478 this._headEl.appendChild(title); 479 480 el.appendChild(this._headEl); 481 482 Event.on(this._toggleVisibleEl, "click", this._toggleVisible, this, true); 483 Event.on(this._refreshEl, "click", function() { 484 if(!this._busy) { 485 this._setBusyState(true); 486 this.fireEvent("dataRefreshEvent"); 487 } 488 }, this, true); 489 }; 490 491 /** 492 * Set up the DOM structure for the ProfilerViewer canvas, 493 * including the holder for the DataTable. 494 * @method _initViewerDOM 495 * @private 496 */ 497 proto._initViewerDOM = function() { 498 499 var el = this.get("element"); 500 this._bodyEl = document.createElement("div"); 501 Dom.addClass(this._bodyEl, "bd"); 502 this._tableEl = document.createElement("div"); 503 Dom.addClass(this._tableEl, PV.CLASS_TABLE); 504 this._bodyEl.appendChild(this._tableEl); 505 el.appendChild(this._bodyEl); 506 }; 507 508 /** 509 * Set up the DOM structure for the ProfilerViewer canvas. 510 * @method _initChartDOM 511 * @private 512 */ 513 proto._initChartDOM = function() { 514 515 this._chartContainer = document.createElement("div"); 516 Dom.addClass(this._chartContainer, PV.CLASS_CHART_CONTAINER); 517 518 var chl = document.createElement("div"); 519 Dom.addClass(chl, PV.CLASS_CHART_LEGEND); 520 521 var chw = document.createElement("div"); 522 523 this._chartLegendEl = document.createElement("dl"); 524 this._chartLegendEl.innerHTML = "<dd>" + PV.STRINGS.initMessage + "</dd>"; 525 526 this._chartEl = document.createElement("div"); 527 Dom.addClass(this._chartEl, PV.CLASS_CHART); 528 529 var msg = document.createElement("p"); 530 msg.innerHTML = PV.STRINGS.installFlashMessage; 531 this._chartEl.appendChild(msg); 532 533 this._chartContainer.appendChild(chl); 534 chl.appendChild(chw); 535 chw.appendChild(this._chartLegendEl); 536 this._chartContainer.appendChild(this._chartEl); 537 this._bodyEl.insertBefore(this._chartContainer,this._tableEl); 538 }; 539 540 541 /** 542 * Create anchor elements for use as buttons. Args: label 543 * is text to appear on the face of the button, parentEl 544 * is the el to which the anchor will be attached, position 545 * is true for inserting as the first node and false for 546 * inserting as the last node of the parentEl. 547 * @method _createButton 548 * @private 549 */ 550 proto._createButton = function(label, parentEl, position) { 551 var b = document.createElement("a"); 552 b.innerHTML = b.title = label; 553 if(parentEl) { 554 if(!position) { 555 parentEl.appendChild(b); 556 } else { 557 parentEl.insertBefore(b, parentEl.firstChild); 558 } 559 } 560 return b; 561 }; 562 563 /** 564 * Set's console busy state. 565 * @method _setBusyState 566 * @private 567 **/ 568 proto._setBusyState = function(b) { 569 if(b) { 570 Dom.addClass(this._busyEl, PV.CLASS_BUSY); 571 this._busy = true; 572 } else { 573 Dom.removeClass(this._busyEl, PV.CLASS_BUSY); 574 this._busy = false; 575 } 576 }; 577 578 /** 579 * Generages a sorting function based on current sortedBy 580 * values. 581 * @method _createProfilerViewerElement 582 * @private 583 **/ 584 proto._genSortFunction = function(key, dir) { 585 var by = key; 586 var direction = dir; 587 return function(a, b) { 588 if (direction == YAHOO.widget.DataTable.CLASS_ASC) { 589 return a[by] - b[by]; 590 } else { 591 return ((a[by] - b[by]) * -1); 592 } 593 }; 594 }; 595 596 /** 597 * Utility function for array sums. 598 * @method _arraySum 599 * @private 600 **/ 601 var _arraySum = function(arr){ 602 var ct = 0; 603 for(var i = 0; i < arr.length; ct+=arr[i++]){} 604 return ct; 605 }; 606 607 /** 608 * Retrieves data from Profiler, filtering and sorting as needed 609 * based on current widget state. Adds calculated percentage 610 * column and function name to data returned by Profiler. 611 * @method _getProfilerData 612 * @private 613 **/ 614 proto._getProfilerData = function() { 615 616 var obj = Profiler.getFullReport(); 617 var arr = []; 618 var totalTime = 0; 619 for (name in obj) { 620 if (YAHOO.lang.hasOwnProperty(obj, name)) { 621 var r = obj[name]; 622 var o = {}; 623 o.fn = name; //add function name to record 624 o.points = r.points.slice(); //copy live array 625 o.calls = r.calls; 626 o.min = r.min; 627 o.max = r.max; 628 o.avg = r.avg; 629 o.total = _arraySum(o.points); 630 o.points = r.points; 631 var f = this.get("filter"); 632 if((!f) || (f(o))) { 633 arr.push(o); 634 totalTime += o.total; 635 } 636 } 637 } 638 639 //add calculated percentage column 640 for (var i = 0, j = arr.length; i < j; i++) { 641 arr[i].pct = (totalTime) ? (arr[i].total * 100) / totalTime : 0; 642 } 643 644 var sortedBy = this.get("sortedBy"); 645 var key = sortedBy.key; 646 var dir = sortedBy.dir; 647 648 arr.sort(this._genSortFunction(key, dir)); 649 650 651 return arr; 652 }; 653 654 /** 655 * Set up the DataTable. 656 * @method _initDataTable 657 * @private 658 */ 659 proto._initDataTable = function() { 660 661 var self = this; 662 663 //Set up the JS Function DataSource, pulling data from 664 //the Profiler. 665 this._dataSource = new YAHOO.util.DataSource( 666 function() { 667 return self._getProfilerData.call(self); 668 }, 669 { 670 responseType: YAHOO.util.DataSource.TYPE_JSARRAY, 671 maxCacheEntries: 0 672 } 673 ); 674 var ds = this._dataSource; 675 676 ds.responseSchema = 677 { 678 fields: [ "fn", "avg", "calls", "max", "min", "total", "pct", "points"] 679 }; 680 681 //Set up the DataTable. 682 var formatTimeValue = function(elCell, oRecord, oColumn, oData) { 683 var a = (oData === Math.floor(oData)) ? oData : (Math.round(oData*1000))/1000; 684 elCell.innerHTML = a + " " + PV.STRINGS.millisecondsAbbrev; 685 }; 686 687 var formatPercent = function(elCell, oRecord, oColumn, oData) { 688 var a = (oData === Math.floor(oData)) ? oData : (Math.round(oData*100))/100; 689 elCell.innerHTML = a + "%"; 690 }; 691 692 var a = YAHOO.widget.DataTable.CLASS_ASC; 693 var d = YAHOO.widget.DataTable.CLASS_DESC; 694 var c = PV.STRINGS.colHeads; 695 var f = formatTimeValue; 696 697 var cols = [ 698 {key:"fn", sortable:true, label: c.fn[0], 699 sortOptions: {defaultDir:a}, 700 resizeable: (YAHOO.util.DragDrop) ? true : false, 701 minWidth:c.fn[1]}, 702 {key:"calls", sortable:true, label: c.calls[0], 703 sortOptions: {defaultDir:d}, 704 width:c.calls[1]}, 705 {key:"avg", sortable:true, label: c.avg[0], 706 sortOptions: {defaultDir:d}, 707 formatter:f, 708 width:c.avg[1]}, 709 {key:"min", sortable:true, label: c.min[0], 710 sortOptions: {defaultDir:a}, 711 formatter:f, 712 width:c.min[1]}, 713 {key:"max", sortable:true, label: c.max[0], 714 sortOptions: {defaultDir:d}, 715 formatter:f, 716 width:c.max[1]}, 717 {key:"total", sortable:true, label: c.total[0], 718 sortOptions: {defaultDir:d}, 719 formatter:f, 720 width:c.total[1]}, 721 {key:"pct", sortable:true, label: c.pct[0], 722 sortOptions: {defaultDir:d}, 723 formatter:formatPercent, 724 width:c.pct[1]} 725 ]; 726 727 this._dataTable = new YAHOO.widget.DataTable(this._tableEl, cols, ds, { 728 scrollable:true, 729 height:this.get("tableHeight"), 730 initialRequest:null, 731 sortedBy: { 732 key: "total", 733 dir: YAHOO.widget.DataTable.CLASS_DESC 734 } 735 }); 736 var dt = this._dataTable; 737 738 //Wire up DataTable events to drive the rest of the UI. 739 dt.subscribe("sortedByChange", this._sortedByChange, this, true); 740 dt.subscribe("renderEvent", this._dataTableRenderHandler, this, true); 741 dt.subscribe("initEvent", this._dataTableRenderHandler, this, true); 742 Event.on(this._tableEl.getElementsByTagName("th"), "click", this._thClickHandler, this, true); 743 }; 744 745 /** 746 * Proxy the sort event in DataTable into the ProfilerViewer 747 * attribute. 748 * @method _sortedByChange 749 * @private 750 **/ 751 proto._sortedByChange = function(o) { 752 if(o.newValue && o.newValue.key) { 753 this.set("sortedBy", {key: o.newValue.key, dir:o.newValue.dir}); 754 } 755 }; 756 757 /** 758 * Proxy the render event in DataTable into the ProfilerViewer 759 * attribute. 760 * @method _dataTableRenderHandler 761 * @private 762 **/ 763 proto._dataTableRenderHandler = function(o) { 764 this._setBusyState(false); 765 }; 766 767 /** 768 * Event handler for clicks on the DataTable's sortable column 769 * heads. 770 * @method _thClickHandler 771 * @private 772 **/ 773 proto._thClickHandler = function(o) { 774 this._setBusyState(true); 775 }; 776 777 /** 778 * Refresh DataTable, getting new data from Profiler. 779 * @method _refreshDataTable 780 * @private 781 **/ 782 proto._refreshDataTable = function(args) { 783 var dt = this._dataTable; 784 dt.getDataSource().sendRequest("", dt.onDataReturnInitializeTable, dt); 785 }; 786 787 /** 788 * Refresh chart, getting new data from table. 789 * @method _refreshChart 790 * @private 791 **/ 792 proto._refreshChart = function() { 793 794 switch (this.get("sortedBy").key) { 795 case "fn": 796 /*Keep the same data on the chart, but force update to 797 reflect new sort order on function/method name: */ 798 this._chart.set("dataSource", this._chart.get("dataSource")); 799 /*no further action necessary; chart redraws*/ 800 return; 801 case "calls": 802 /*Null out the xAxis formatting before redrawing chart.*/ 803 this._chart.set("xAxis", this._chartAxisDefinitionPlain); 804 break; 805 case "pct": 806 this._chart.set("xAxis", this._chartAxisDefinitionPercent); 807 break; 808 default: 809 /*Set the default xAxis; redraw legend; set the new series definition.*/ 810 this._chart.set("xAxis", this._chartAxisDefinitionTime); 811 break; 812 } 813 814 this._drawChartLegend(); 815 this._chart.set("series", this._getSeriesDef(this.get("sortedBy").key)); 816 817 }; 818 819 /** 820 * Get data for the Chart from DataTable recordset 821 * @method _getChartData 822 * @private 823 */ 824 proto._getChartData = function() { 825 //var records = this._getProfilerData(); 826 var records = this._dataTable.getRecordSet().getRecords(0, this.get("maxChartFunctions")); 827 var arr = []; 828 for (var i = 0, j = records.length; i<j; i++) { 829 arr.push(records[i].getData()); 830 } 831 return arr; 832 }; 833 834 /** 835 * Build series definition based on current configuration attributes. 836 * @method _getSeriesDef 837 * @private 838 */ 839 proto._getSeriesDef = function(field) { 840 var sd = this.get("chartSeriesDefinitions")[field]; 841 var arr = []; 842 for(var i = 0, j = sd.group.length; i<j; i++) { 843 var c = this.get("chartSeriesDefinitions")[sd.group[i]]; 844 arr.push( 845 {displayName:c.displayName, 846 xField:c.xField, 847 style: {color:c.style.color, size:c.style.size} 848 } 849 ); 850 } 851 852 return arr; 853 }; 854 855 /** 856 * Set up the Chart. 857 * @method _initChart 858 * @private 859 */ 860 proto._initChart = function() { 861 862 this._sizeChartCanvas(); 863 864 YAHOO.widget.Chart.SWFURL = this.get("swfUrl"); 865 866 var self = this; 867 868 //Create DataSource based on records currently displayed 869 //at the top of the sort list in the DataTable. 870 var ds = new YAHOO.util.DataSource( 871 //force the jsfunction DataSource to run in the scope of 872 //the ProfilerViewer, not in the YAHOO.util.DataSource scope: 873 function() { 874 return self._getChartData.call(self); 875 }, 876 { 877 responseType: YAHOO.util.DataSource.TYPE_JSARRAY, 878 maxCacheEntries: 0 879 } 880 ); 881 882 ds.responseSchema = 883 { 884 fields: [ "fn", "avg", "calls", "max", "min", "total", "pct" ] 885 }; 886 887 ds.subscribe('responseEvent', this._sizeChartCanvas, this, true); 888 889 //Set up the chart itself. 890 this._chartAxisDefinitionTime = new YAHOO.widget.NumericAxis(); 891 this._chartAxisDefinitionTime.labelFunction = "YAHOO.widget.ProfilerViewer.timeAxisLabelFunction"; 892 893 this._chartAxisDefinitionPercent = new YAHOO.widget.NumericAxis(); 894 this._chartAxisDefinitionPercent.labelFunction = "YAHOO.widget.ProfilerViewer.percentAxisLabelFunction"; 895 896 this._chartAxisDefinitionPlain = new YAHOO.widget.NumericAxis(); 897 898 this._chart = new YAHOO.widget.BarChart( this._chartEl, ds, 899 { 900 yField: "fn", 901 series: this._getSeriesDef(this.get("sortedBy").key), 902 style: this.get("chartStyle"), 903 xAxis: this._chartAxisDefinitionTime 904 } ); 905 906 this._drawChartLegend(); 907 this._chartInitialized = true; 908 this._dataTable.unsubscribe("initEvent", this._initChart, this); 909 this._dataTable.subscribe("initEvent", this._refreshChart, this, true); 910 911 }; 912 913 /** 914 * Set up the Chart's legend 915 * @method _drawChartLegend 916 * @private 917 **/ 918 proto._drawChartLegend = function() { 919 var seriesDefs = this.get("chartSeriesDefinitions"); 920 var currentDef = seriesDefs[this.get("sortedBy").key]; 921 var l = this._chartLegendEl; 922 l.innerHTML = ""; 923 for(var i = 0, j = currentDef.group.length; i<j; i++) { 924 var c = seriesDefs[currentDef.group[i]]; 925 var dt = document.createElement("dt"); 926 Dom.setStyle(dt, "backgroundColor", "#" + c.style.color); 927 var dd = document.createElement("dd"); 928 dd.innerHTML = c.displayName; 929 l.appendChild(dt); 930 l.appendChild(dd); 931 } 932 }; 933 934 /** 935 * Resize the chart's canvas if based on number of records 936 * returned from the chart's datasource. 937 * @method _sizeChartCanvas 938 * @private 939 **/ 940 proto._sizeChartCanvas = function(o) { 941 var bars = (o) ? o.response.length : this.get("maxChartFunctions"); 942 var s = (bars * 36) + 34; 943 if (s != parseInt(this._chartElHeight, 10)) { 944 this._chartElHeight = s; 945 Dom.setStyle(this._chartEl, "height", s + "px"); 946 } 947 }; 948 949 /** 950 * setAttributeConfigs TabView specific properties. 951 * @method initAttributes 952 * @param {Object} attr Hash of initial attributes 953 * @method initAttributes 954 * @private 955 */ 956 proto.initAttributes = function(attr) { 957 YAHOO.widget.ProfilerViewer.superclass.initAttributes.call(this, attr); 958 /** 959 * The YUI Loader base path from which to pull YUI files needed 960 * in the rendering of the ProfilerViewer canvas. Passed directly 961 * to YUI Loader. Leave blank to draw files from 962 * yui.yahooapis.com. 963 * @attribute base 964 * @type string 965 * @default "" 966 */ 967 this.setAttributeConfig('base', { 968 value: attr.base 969 }); 970 971 /** 972 * The height of the DataTable. The table will scroll 973 * vertically if the content overflows the specified 974 * height. 975 * @attribute tableHeight 976 * @type string 977 * @default "15em" 978 */ 979 this.setAttributeConfig('tableHeight', { 980 value: attr.tableHeight || "15em", 981 method: function(s) { 982 if(this._dataTable) { 983 this._dataTable.set("height", s); 984 } 985 } 986 }); 987 988 /** 989 * The default column key to sort by. Valid keys are: fn, calls, 990 * avg, min, max, total. Valid dir values are: 991 * YAHOO.widget.DataTable.CLASS_ASC and 992 * YAHOO.widget.DataTable.CLASS_DESC (or their 993 * string equivalents). 994 * @attribute sortedBy 995 * @type string 996 * @default {key:"total", dir:"yui-dt-desc"} 997 */ 998 this.setAttributeConfig('sortedBy', { 999 value: attr.sortedBy || {key:"total", dir:"yui-dt-desc"} 1000 }); 1001 1002 /** 1003 * A filter function to use in selecting functions that will 1004 * appear in the ProfilerViewer report. The function is passed 1005 * a function report object and should return a boolean indicating 1006 * whether that function should be included in the ProfilerViewer 1007 * display. The argument is structured as follows: 1008 * 1009 * { 1010 * fn: <str function name>, 1011 * calls : <n number of calls>, 1012 * avg : <n average call duration>, 1013 * max: <n duration of longest call>, 1014 * min: <n duration of shortest call>, 1015 * total: <n total time of all calls> 1016 * points : <array time in ms of each call> 1017 * } 1018 * 1019 * For example, you would use the follwing filter function to 1020 * return only functions that have been called at least once: 1021 * 1022 * function(o) { 1023 * return (o.calls > 0); 1024 * } 1025 * 1026 * @attribute filter 1027 * @type function 1028 * @default null 1029 */ 1030 this.setAttributeConfig('filter', { 1031 value: attr.filter || null, 1032 validator: YAHOO.lang.isFunction 1033 }); 1034 1035 /** 1036 * The path to the YUI Charts swf file; must be a full URI 1037 * or a path relative to the page being profiled. Changes at runtime 1038 * not supported; pass this value in at instantiation. 1039 * @attribute swfUrl 1040 * @type string 1041 * @default "http://yui.yahooapis.com/2.5.0/build/charts/assets/charts.swf" 1042 */ 1043 this.setAttributeConfig('swfUrl', { 1044 value: attr.swfUrl || "http://yui.yahooapis.com/2.5.0/build/charts/assets/charts.swf" 1045 }); 1046 1047 /** 1048 * The maximum number of functions to profile in the chart. The 1049 * greater the number of functions, the greater the height of the 1050 * chart canvas. 1051 * height. 1052 * @attribute maxChartFunctions 1053 * @type int 1054 * @default 6 1055 */ 1056 this.setAttributeConfig('maxChartFunctions', { 1057 value: attr.maxChartFunctions || 6, 1058 method: function(s) { 1059 if(this._rendered) { 1060 this._sizeChartCanvas(); 1061 } 1062 }, 1063 validator: YAHOO.lang.isNumber 1064 }); 1065 1066 /** 1067 * The style object that defines the chart's visual presentation. 1068 * Conforms to the style attribute passed to the Charts Control 1069 * constructor. See Charts Control User's Guide for more information 1070 * on how to format this object. 1071 * @attribute chartStyle 1072 * @type obj 1073 * @default See JS source for default definitions. 1074 */ 1075 this.setAttributeConfig('chartStyle', { 1076 value: attr.chartStyle || { 1077 font: 1078 { 1079 name: "Arial", 1080 color: 0xeeee5c, 1081 size: 12 1082 }, 1083 background: 1084 { 1085 color: "6e6e63" 1086 } 1087 }, 1088 method: function() { 1089 if(this._rendered && this.get("showChart")) { 1090 this._refreshChart(); 1091 } 1092 } 1093 }); 1094 1095 /** 1096 * The series definition information to use when charting 1097 * specific fields on the chart. "displayName", "xField", 1098 * and "style" members are used to construct the series 1099 * definition; the "group" member is the array of fields 1100 * that should be charted when the table is sorted by a 1101 * given field. The "displayName" string value will be 1102 * treated as markup and inserted into the DOM with innerHTML. 1103 * @attribute chartSeriesDefinitions 1104 * @type obj 1105 * @default See JS source for full default definitions. 1106 */ 1107 this.setAttributeConfig('chartSeriesDefinitions', { 1108 value: attr.chartSeriesDefinitions || { 1109 total: { 1110 displayName: PV.STRINGS.colHeads.total[0], 1111 xField: "total", 1112 style: {color:"4d95dd", size:20}, 1113 group: ["total"] 1114 }, 1115 calls: { 1116 displayName: PV.STRINGS.colHeads.calls[0], 1117 xField: "calls", 1118 style: {color:"edff9f", size:20}, 1119 group: ["calls"] 1120 }, 1121 avg: { 1122 displayName: PV.STRINGS.colHeads.avg[0], 1123 xField: "avg", 1124 style: {color:"209daf", size:9}, 1125 group: ["avg", "min", "max"] 1126 }, 1127 min: { 1128 displayName: PV.STRINGS.colHeads.min[0], 1129 xField: "min", 1130 style: {color:"b6ecf4", size:9}, 1131 group: ["avg", "min", "max"] 1132 }, 1133 max: { 1134 displayName: PV.STRINGS.colHeads.max[0], 1135 xField: "max", 1136 style: {color:"29c7de", size:9}, 1137 group: ["avg", "min", "max"] 1138 }, 1139 pct: { 1140 displayName: PV.STRINGS.colHeads.pct[0], 1141 xField: "pct", 1142 style: {color:"C96EDB", size:20}, 1143 group: ["pct"] 1144 } 1145 }, 1146 method: function() { 1147 if(this._rendered && this.get("showChart")) { 1148 this._refreshChart(); 1149 } 1150 } 1151 }); 1152 1153 /** 1154 * The default visibility setting for the viewer canvas. If true, 1155 * the viewer will load all necessary files and render itself 1156 * immediately upon instantiation; otherwise, the viewer will 1157 * load only minimal resources until the user toggles visibility 1158 * via the UI. 1159 * @attribute visible 1160 * @type boolean 1161 * @default false 1162 */ 1163 this.setAttributeConfig('visible', { 1164 value: attr.visible || false, 1165 validator: YAHOO.lang.isBoolean, 1166 method: function(b) { 1167 if(b) { 1168 this._show(); 1169 } else { 1170 if (this._rendered) { 1171 this._hide(); 1172 } 1173 } 1174 } 1175 }); 1176 1177 /** 1178 * The default visibility setting for the chart. 1179 * @attribute showChart 1180 * @type boolean 1181 * @default true 1182 */ 1183 this.setAttributeConfig('showChart', { 1184 value: attr.showChart || true, 1185 validator: YAHOO.lang.isBoolean, 1186 writeOnce: true 1187 1188 }); 1189 1190 YAHOO.widget.ProfilerViewer.superclass.initAttributes.call(this, attr); 1191 1192 }; 1193 1194 })(); 1195 1196 YAHOO.register("profilerviewer", YAHOO.widget.ProfilerViewer, {version: "2.9.0", build: "2800"}); 1197 1198 }, '2.9.0' ,{"requires": ["yui2-skin-sam-profilerviewer", "yui2-yuiloader", "yui2-dom", "yui2-event", "yui2-element", "yui2-profiler"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |