home *** CD-ROM | disk | FTP | other *** search
/ Computer Active Guide 2009 July / CAG7.ISO / Internetas / SafariSetup.exe / AppleApplicationSupport.msi / WebKit.resources_inspector_SummaryBar.js < prev    next >
Encoding:
JavaScript  |  2010-06-03  |  12.0 KB  |  364 lines

  1. /*
  2.  * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
  3.  * Copyright (C) 2008, 2009 Anthony Ricaud <rik@webkit.org>
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * 1.  Redistributions of source code must retain the above copyright
  10.  *     notice, this list of conditions and the following disclaimer. 
  11.  * 2.  Redistributions in binary form must reproduce the above copyright
  12.  *     notice, this list of conditions and the following disclaimer in the
  13.  *     documentation and/or other materials provided with the distribution. 
  14.  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
  15.  *     its contributors may be used to endorse or promote products derived
  16.  *     from this software without specific prior written permission. 
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  19.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21.  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  22.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28.  */
  29.  
  30. WebInspector.SummaryBar = function(categories)
  31. {
  32.     this.categories = categories;
  33.  
  34.     this.element = document.createElement("div");
  35.     this.element.className = "summary-bar";
  36.  
  37.     this.graphElement = document.createElement("canvas");
  38.     this.graphElement.setAttribute("width", "450");
  39.     this.graphElement.setAttribute("height", "38");
  40.     this.graphElement.className = "summary-graph";
  41.     this.element.appendChild(this.graphElement);
  42.  
  43.     this.legendElement = document.createElement("div");
  44.     this.legendElement.className = "summary-graph-legend";
  45.     this.element.appendChild(this.legendElement);
  46. }
  47.  
  48. WebInspector.SummaryBar.prototype = {
  49.  
  50.     get calculator() {
  51.         return this._calculator;
  52.     },
  53.  
  54.     set calculator(x) {
  55.         this._calculator = x;
  56.     },
  57.  
  58.     reset: function()
  59.     {
  60.         this.legendElement.removeChildren();
  61.         this._drawSummaryGraph();
  62.     },
  63.  
  64.     update: function(data)
  65.     {
  66.         var graphInfo = this.calculator.computeSummaryValues(data);
  67.  
  68.         var fillSegments = [];
  69.  
  70.         this.legendElement.removeChildren();
  71.  
  72.         for (var category in this.categories) {
  73.             var size = graphInfo.categoryValues[category];
  74.             if (!size)
  75.                 continue;
  76.  
  77.             var colorString = this.categories[category].color;
  78.  
  79.             var fillSegment = {color: colorString, value: size};
  80.             fillSegments.push(fillSegment);
  81.  
  82.             var legendLabel = this._makeLegendElement(this.categories[category].title, this.calculator.formatValue(size), colorString);
  83.             this.legendElement.appendChild(legendLabel);
  84.         }
  85.  
  86.         if (graphInfo.total) {
  87.             var totalLegendLabel = this._makeLegendElement(WebInspector.UIString("Total"), this.calculator.formatValue(graphInfo.total));
  88.             totalLegendLabel.addStyleClass("total");
  89.             this.legendElement.appendChild(totalLegendLabel);
  90.         }
  91.  
  92.         this._drawSummaryGraph(fillSegments);
  93.     },
  94.  
  95.     _drawSwatch: function(canvas, color)
  96.     {
  97.         var ctx = canvas.getContext("2d");
  98.  
  99.         function drawSwatchSquare() {
  100.             ctx.fillStyle = color;
  101.             ctx.fillRect(0, 0, 13, 13);
  102.  
  103.             var gradient = ctx.createLinearGradient(0, 0, 13, 13);
  104.             gradient.addColorStop(0.0, "rgba(255, 255, 255, 0.2)");
  105.             gradient.addColorStop(1.0, "rgba(255, 255, 255, 0.0)");
  106.  
  107.             ctx.fillStyle = gradient;
  108.             ctx.fillRect(0, 0, 13, 13);
  109.  
  110.             gradient = ctx.createLinearGradient(13, 13, 0, 0);
  111.             gradient.addColorStop(0.0, "rgba(0, 0, 0, 0.2)");
  112.             gradient.addColorStop(1.0, "rgba(0, 0, 0, 0.0)");
  113.  
  114.             ctx.fillStyle = gradient;
  115.             ctx.fillRect(0, 0, 13, 13);
  116.  
  117.             ctx.strokeStyle = "rgba(0, 0, 0, 0.6)";
  118.             ctx.strokeRect(0.5, 0.5, 12, 12);
  119.         }
  120.  
  121.         ctx.clearRect(0, 0, 13, 24);
  122.  
  123.         drawSwatchSquare();
  124.  
  125.         ctx.save();
  126.  
  127.         ctx.translate(0, 25);
  128.         ctx.scale(1, -1);
  129.  
  130.         drawSwatchSquare();
  131.  
  132.         ctx.restore();
  133.  
  134.         this._fadeOutRect(ctx, 0, 13, 13, 13, 0.5, 0.0);
  135.     },
  136.  
  137.     _drawSummaryGraph: function(segments)
  138.     {
  139.         if (!segments || !segments.length) {
  140.             segments = [{color: "white", value: 1}];
  141.             this._showingEmptySummaryGraph = true;
  142.         } else
  143.             delete this._showingEmptySummaryGraph;
  144.  
  145.         // Calculate the total of all segments.
  146.         var total = 0;
  147.         for (var i = 0; i < segments.length; ++i)
  148.             total += segments[i].value;
  149.  
  150.         // Calculate the percentage of each segment, rounded to the nearest percent.
  151.         var percents = segments.map(function(s) { return Math.max(Math.round(100 * s.value / total), 1) });
  152.  
  153.         // Calculate the total percentage.
  154.         var percentTotal = 0;
  155.         for (var i = 0; i < percents.length; ++i)
  156.             percentTotal += percents[i];
  157.  
  158.         // Make sure our percentage total is not greater-than 100, it can be greater
  159.         // if we rounded up for a few segments.
  160.         while (percentTotal > 100) {
  161.             for (var i = 0; i < percents.length && percentTotal > 100; ++i) {
  162.                 if (percents[i] > 1) {
  163.                     --percents[i];
  164.                     --percentTotal;
  165.                 }
  166.             }
  167.         }
  168.  
  169.         // Make sure our percentage total is not less-than 100, it can be less
  170.         // if we rounded down for a few segments.
  171.         while (percentTotal < 100) {
  172.             for (var i = 0; i < percents.length && percentTotal < 100; ++i) {
  173.                 ++percents[i];
  174.                 ++percentTotal;
  175.             }
  176.         }
  177.  
  178.         var ctx = this.graphElement.getContext("2d");
  179.  
  180.         var x = 0;
  181.         var y = 0;
  182.         var w = 450;
  183.         var h = 19;
  184.         var r = (h / 2);
  185.  
  186.         function drawPillShadow()
  187.         {
  188.             // This draws a line with a shadow that is offset away from the line. The line is stroked
  189.             // twice with different X shadow offsets to give more feathered edges. Later we erase the
  190.             // line with destination-out 100% transparent black, leaving only the shadow. This only
  191.             // works if nothing has been drawn into the canvas yet.
  192.  
  193.             ctx.beginPath();
  194.             ctx.moveTo(x + 4, y + h - 3 - 0.5);
  195.             ctx.lineTo(x + w - 4, y + h - 3 - 0.5);
  196.             ctx.closePath();
  197.  
  198.             ctx.save();
  199.  
  200.             ctx.shadowBlur = 2;
  201.             ctx.shadowColor = "rgba(0, 0, 0, 0.5)";
  202.             ctx.shadowOffsetX = 3;
  203.             ctx.shadowOffsetY = 5;
  204.  
  205.             ctx.strokeStyle = "white";
  206.             ctx.lineWidth = 1;
  207.  
  208.             ctx.stroke();
  209.  
  210.             ctx.shadowOffsetX = -3;
  211.  
  212.             ctx.stroke();
  213.  
  214.             ctx.restore();
  215.  
  216.             ctx.save();
  217.  
  218.             ctx.globalCompositeOperation = "destination-out";
  219.             ctx.strokeStyle = "rgba(0, 0, 0, 1)";
  220.             ctx.lineWidth = 1;
  221.  
  222.             ctx.stroke();
  223.  
  224.             ctx.restore();
  225.         }
  226.  
  227.         function drawPill()
  228.         {
  229.             // Make a rounded rect path.
  230.             ctx.beginPath();
  231.             ctx.moveTo(x, y + r);
  232.             ctx.lineTo(x, y + h - r);
  233.             ctx.arc(x + r, y + h - r, r, Math.PI, Math.PI / 2, true);
  234.             ctx.lineTo(x + w - r, y + h);
  235.             ctx.arc(x + w - r, y + h - r, r, Math.PI / 2, 0, true);
  236.             ctx.lineTo(x + w, y + r);
  237.             ctx.arc(x + w - r, y + r, r, 0, 3 * Math.PI / 2, true);
  238.             ctx.lineTo(x + r, y);
  239.             ctx.arc(x + r, y + r, r, Math.PI / 2, Math.PI, true);
  240.             ctx.closePath();
  241.  
  242.             // Clip to the rounded rect path.
  243.             ctx.save();
  244.             ctx.clip();
  245.  
  246.             // Fill the segments with the associated color.
  247.             var previousSegmentsWidth = 0;
  248.             for (var i = 0; i < segments.length; ++i) {
  249.                 var segmentWidth = Math.round(w * percents[i] / 100);
  250.                 ctx.fillStyle = segments[i].color;
  251.                 ctx.fillRect(x + previousSegmentsWidth, y, segmentWidth, h);
  252.                 previousSegmentsWidth += segmentWidth;
  253.             }
  254.  
  255.             // Draw the segment divider lines.
  256.             ctx.lineWidth = 1;
  257.             for (var i = 1; i < 20; ++i) {
  258.                 ctx.beginPath();
  259.                 ctx.moveTo(x + (i * Math.round(w / 20)) + 0.5, y);
  260.                 ctx.lineTo(x + (i * Math.round(w / 20)) + 0.5, y + h);
  261.                 ctx.closePath();
  262.  
  263.                 ctx.strokeStyle = "rgba(0, 0, 0, 0.2)";
  264.                 ctx.stroke();
  265.  
  266.                 ctx.beginPath();
  267.                 ctx.moveTo(x + (i * Math.round(w / 20)) + 1.5, y);
  268.                 ctx.lineTo(x + (i * Math.round(w / 20)) + 1.5, y + h);
  269.                 ctx.closePath();
  270.  
  271.                 ctx.strokeStyle = "rgba(255, 255, 255, 0.2)";
  272.                 ctx.stroke();
  273.             }
  274.  
  275.             // Draw the pill shading.
  276.             var lightGradient = ctx.createLinearGradient(x, y, x, y + (h / 1.5));
  277.             lightGradient.addColorStop(0.0, "rgba(220, 220, 220, 0.6)");
  278.             lightGradient.addColorStop(0.4, "rgba(220, 220, 220, 0.2)");
  279.             lightGradient.addColorStop(1.0, "rgba(255, 255, 255, 0.0)");
  280.  
  281.             var darkGradient = ctx.createLinearGradient(x, y + (h / 3), x, y + h);
  282.             darkGradient.addColorStop(0.0, "rgba(0, 0, 0, 0.0)");
  283.             darkGradient.addColorStop(0.8, "rgba(0, 0, 0, 0.2)");
  284.             darkGradient.addColorStop(1.0, "rgba(0, 0, 0, 0.5)");
  285.  
  286.             ctx.fillStyle = darkGradient;
  287.             ctx.fillRect(x, y, w, h);
  288.  
  289.             ctx.fillStyle = lightGradient;
  290.             ctx.fillRect(x, y, w, h);
  291.  
  292.             ctx.restore();
  293.         }
  294.  
  295.         ctx.clearRect(x, y, w, (h * 2));
  296.  
  297.         drawPillShadow();
  298.         drawPill();
  299.  
  300.         ctx.save();
  301.  
  302.         ctx.translate(0, (h * 2) + 1);
  303.         ctx.scale(1, -1);
  304.  
  305.         drawPill();
  306.  
  307.         ctx.restore();
  308.  
  309.         this._fadeOutRect(ctx, x, y + h + 1, w, h, 0.5, 0.0);
  310.     },
  311.  
  312.     _fadeOutRect: function(ctx, x, y, w, h, a1, a2)
  313.     {
  314.         ctx.save();
  315.  
  316.         var gradient = ctx.createLinearGradient(x, y, x, y + h);
  317.         gradient.addColorStop(0.0, "rgba(0, 0, 0, " + (1.0 - a1) + ")");
  318.         gradient.addColorStop(0.8, "rgba(0, 0, 0, " + (1.0 - a2) + ")");
  319.         gradient.addColorStop(1.0, "rgba(0, 0, 0, 1.0)");
  320.  
  321.         ctx.globalCompositeOperation = "destination-out";
  322.  
  323.         ctx.fillStyle = gradient;
  324.         ctx.fillRect(x, y, w, h);
  325.  
  326.         ctx.restore();
  327.     },
  328.  
  329.     _makeLegendElement: function(label, value, color)
  330.     {
  331.         var legendElement = document.createElement("label");
  332.         legendElement.className = "summary-graph-legend-item";
  333.  
  334.         if (color) {
  335.             var swatch = document.createElement("canvas");
  336.             swatch.className = "summary-graph-legend-swatch";
  337.             swatch.setAttribute("width", "13");
  338.             swatch.setAttribute("height", "24");
  339.  
  340.             legendElement.appendChild(swatch);
  341.  
  342.             this._drawSwatch(swatch, color);
  343.         }
  344.  
  345.         var labelElement = document.createElement("div");
  346.         labelElement.className = "summary-graph-legend-label";
  347.         legendElement.appendChild(labelElement);
  348.  
  349.         var headerElement = document.createElement("div");
  350.         headerElement.className = "summary-graph-legend-header";
  351.         headerElement.textContent = label;
  352.         labelElement.appendChild(headerElement);
  353.  
  354.         var valueElement = document.createElement("div");
  355.         valueElement.className = "summary-graph-legend-value";
  356.         valueElement.textContent = value;
  357.         labelElement.appendChild(valueElement);
  358.  
  359.         return legendElement;
  360.     }
  361. }
  362.  
  363. WebInspector.SummaryBar.prototype.__proto__ = WebInspector.Object.prototype;
  364.