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 */ 19function 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 */ 38Coordinates.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 */ 75Coordinates.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 */ 84Coordinates.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 */ 94Coordinates.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 */ 105Coordinates.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 */ 122Coordinates.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 */ 133Coordinates.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 */ 143Coordinates.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 */ 152Coordinates.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 */ 161Coordinates.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 */ 170Coordinates.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 */ 180Coordinates.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 */ 190Coordinates.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 */ 200Coordinates.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 */ 210Coordinates.prototype.yUpperLimitValue = function() { 211 return this.yMaxValue_ + this.yBufferSpace_; 212}; 213