Home | History | Annotate | Download | only in js
      1 /*
      2   Copyright (c) 2012 The Chromium Authors. All rights reserved.
      3   Use of this source code is governed by a BSD-style license that can be
      4   found in the LICENSE file.
      5 */
      6 
      7 /**
      8  * @fileoverview Class and functions to handle positioning of plot data points.
      9  */
     10 
     11 /**
     12  * Class that handles plot data positioning.
     13  * @constructor
     14  *
     15  * @param {Array} plotData Data that will be plotted.  It is an array of lines,
     16  *     where each line is an array of points, and each point is a length-2 array
     17  *     representing an (x, y) pair.
     18  */
     19 function Coordinates(plotData) {
     20   this.plotData = plotData;
     21 
     22   height = window.innerHeight - 16;
     23   width = window.innerWidth - 16;
     24 
     25   this.widthMax = width;
     26   this.heightMax = Math.min(400, height - 85);
     27 
     28   this.processValues_('x');
     29   this.processValues_('y');
     30 }
     31 
     32 /**
     33  * Determines the min/max x or y values in the plot, accounting for some extra
     34  * buffer space.
     35  *
     36  * @param {string} type The type of value to process, either 'x' or 'y'.
     37  */
     38 Coordinates.prototype.processValues_ = function (type) {
     39   var merged = [];
     40   for (var i = 0; i < this.plotData.length; i++)
     41     for (var j = 0; j < this.plotData[i].length; j++) {
     42       if (type == 'x')
     43         merged.push(parseFloat(this.plotData[i][j][0]));  // Index 0 is x value.
     44       else
     45         merged.push(parseFloat(this.plotData[i][j][1]));  // Index 1 is y value.
     46     }
     47 
     48   min = merged[0];
     49   max = merged[0];
     50   for (var i = 1; i < merged.length; ++i) {
     51     if (isNaN(min) || merged[i] < min)
     52       min = merged[i];
     53     if (isNaN(max) || merged[i] > max)
     54       max = merged[i];
     55   }
     56 
     57   var bufferSpace = 0.02 * (max - min);
     58 
     59   if (type == 'x') {
     60     this.xBufferSpace_ = bufferSpace;
     61     this.xMinValue_ = min;
     62     this.xMaxValue_ = max;
     63   } else {
     64     this.yBufferSpace_ = bufferSpace;
     65     this.yMinValue_ = min;
     66     this.yMaxValue_ = max;
     67   }
     68 };
     69 
     70 /**
     71  * Difference between horizontal upper and lower limit values.
     72  *
     73  * @return {number} The x value range.
     74  */
     75 Coordinates.prototype.xValueRange = function() {
     76   return this.xUpperLimitValue() - this.xLowerLimitValue();
     77 };
     78 
     79 /**
     80  * Difference between vertical upper and lower limit values.
     81  *
     82  * @return {number} The y value range.
     83  */
     84 Coordinates.prototype.yValueRange = function() {
     85   return this.yUpperLimitValue() - this.yLowerLimitValue();
     86 };
     87 
     88 /**
     89  * Converts horizontal data value to pixel value on canvas.
     90  *
     91  * @param {number} value The x data value.
     92  * @return {number} The corresponding x pixel value on the canvas.
     93  */
     94 Coordinates.prototype.xPixel = function(value) {
     95   return this.widthMax *
     96       ((value - this.xLowerLimitValue()) / this.xValueRange());
     97 };
     98 
     99 /**
    100  * Converts vertical data value to pixel value on canvas.
    101  *
    102  * @param {number} value The y data value.
    103  * @return {number} The corresponding y pixel value on the canvas.
    104  */
    105 Coordinates.prototype.yPixel = function(value) {
    106   if (this.yValueRange() == 0) {
    107     // Completely horizontal lines should be centered horizontally.
    108     return this.heightMax / 2;
    109   } else {
    110     return this.heightMax -
    111         (this.heightMax *
    112          (value - this.yLowerLimitValue()) / this.yValueRange());
    113   }
    114 };
    115 
    116 /**
    117  * Converts x point on canvas to data value it represents.
    118  *
    119  * @param {number} position The x pixel value on the canvas.
    120  * @return {number} The corresponding x data value.
    121  */
    122 Coordinates.prototype.xValue = function(position) {
    123   return this.xLowerLimitValue() +
    124       (position / this.widthMax * this.xValueRange());
    125 };
    126 
    127 /**
    128  * Converts y point on canvas to data value it represents.
    129  *
    130  * @param {number} position The y pixel value on the canvas.
    131  * @return {number} The corresponding y data value.
    132  */
    133 Coordinates.prototype.yValue = function(position) {
    134   var ratio = this.heightMax / (this.heightMax - position);
    135   return this.yLowerLimitValue() + (this.yValueRange() / ratio);
    136 };
    137 
    138 /**
    139  * Returns the minimum x value of all the data points.
    140  *
    141  * @return {number} The minimum x value of all the data points.
    142  */
    143 Coordinates.prototype.xMinValue = function() {
    144   return this.xMinValue_;
    145 };
    146 
    147 /**
    148  * Returns the maximum x value of all the data points.
    149  *
    150  * @return {number} The maximum x value of all the data points.
    151  */
    152 Coordinates.prototype.xMaxValue = function() {
    153   return this.xMaxValue_;
    154 };
    155 
    156 /**
    157  * Returns the minimum y value of all the data points.
    158  *
    159  * @return {number} The minimum y value of all the data points.
    160  */
    161 Coordinates.prototype.yMinValue = function() {
    162   return this.yMinValue_;
    163 };
    164 
    165 /**
    166  * Returns the maximum y value of all the data points.
    167  *
    168  * @return {number} The maximum y value of all the data points.
    169  */
    170 Coordinates.prototype.yMaxValue = function() {
    171   return this.yMaxValue_;
    172 };
    173 
    174 /**
    175  * Returns the x value at the lower limit of the bounding box of the canvas.
    176  *
    177  * @return {number} The x value at the lower limit of the bounding box of
    178  *     the canvas.
    179  */
    180 Coordinates.prototype.xLowerLimitValue = function() {
    181   return this.xMinValue_ - this.xBufferSpace_;
    182 };
    183 
    184 /**
    185  * Returns the x value at the upper limit of the bounding box of the canvas.
    186  *
    187  * @return {number} The x value at the upper limit of the bounding box of
    188  *     the canvas.
    189  */
    190 Coordinates.prototype.xUpperLimitValue = function() {
    191   return this.xMaxValue_ + this.xBufferSpace_;
    192 };
    193 
    194 /**
    195  * Returns the y value at the lower limit of the bounding box of the canvas.
    196  *
    197  * @return {number} The y value at the lower limit of the bounding box of
    198  *     the canvas.
    199  */
    200 Coordinates.prototype.yLowerLimitValue = function() {
    201   return this.yMinValue_ - this.yBufferSpace_;
    202 };
    203 
    204 /**
    205  * Returns the y value at the upper limit of the bounding box of the canvas.
    206  *
    207  * @return {number} The y value at the upper limit of the bounding box of
    208  *     the canvas.
    209  */
    210 Coordinates.prototype.yUpperLimitValue = function() {
    211   return this.yMaxValue_ + this.yBufferSpace_;
    212 };
    213