[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/2in3/2.9.0/build/yui2-profilerviewer/ -> yui2-profilerviewer.js (source)

   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"]});


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1