graphs.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. //Creates a line graph within a canvas
  2. //Will expand or shrink to the size of the canvas
  3. //Inputs:
  4. // canvas = the canvas that you would like to draw on
  5. // yName = a string for the name of the Y axis
  6. // xName = a string for the name of the X axis
  7. class LineGraph{
  8. constructor(canvas, yName, xName){
  9. canvas.height = canvas.clientHeight;
  10. canvas.width = canvas.clientWidth;
  11. this.canvas = canvas;
  12. this.context = canvas.getContext("2d");
  13. this.left = canvas.clientWidth - (canvas.clientWidth * 0.9);
  14. this.right = canvas.clientWidth * 0.9;
  15. this.top = canvas.clientHeight - (canvas.clientHeight * 0.9);
  16. this.bottom = canvas.clientHeight * 0.9;
  17. this.data = [];
  18. this.max = 0;
  19. this.xName = xName;
  20. this.yName = yName;
  21. this.xRange = [];
  22. this.colors = [];
  23. this.colorIndex = 0;
  24. for(let i = 0; i < 100; i++){
  25. let redRand = Math.floor(Math.random() * 200);
  26. let greenRand = Math.floor(Math.random() * 200);
  27. let blueRand = Math.floor(Math.random() * 200);
  28. this.colors.push(`rgb(${redRand}, ${greenRand}, ${blueRand})`);
  29. }
  30. }
  31. //Add a dataset to the graph to draw
  32. //Inputs:
  33. // data = array containing list of numbers as the data points for the graph
  34. // data[0] will be on the left. data[data.length-1] will be on the right.
  35. // xRange = array containing two elements, start and end for x axis data (currently only dates)
  36. // identifier = any string, int, etc. to identify this data set. Used for removal
  37. addData(data, xRange, identifier){
  38. data = {
  39. set: data,
  40. colorIndex: this.colorIndex,
  41. id: identifier
  42. }
  43. this.colorIndex++;
  44. this.data.push(data);
  45. let isChange = false;
  46. for(let point of data.set){
  47. if(point > this.max){
  48. this.max = point;
  49. this.verticalMultiplier = (this.bottom - this.top) / this.max;
  50. this.horizontalMultiplier = (this.right - this.left) / (data.set.length - 1);
  51. isChange = true;
  52. }
  53. }
  54. if(this.xRange.length === 0){
  55. this.xRange = xRange;
  56. isChange = true;
  57. }else{
  58. if(xRange[0] < this.xRange[0]){
  59. this.xRange[0] = xRange[0];
  60. isChange = true;
  61. }
  62. if(xRange[1] > this.xRange[1]){
  63. this.xRange[1] = xRange[1];
  64. isChange = true;
  65. }
  66. }
  67. if(isChange){
  68. this.drawGraph();
  69. }else{
  70. this.drawLine(data);
  71. }
  72. }
  73. //Removes a single data set from the graph and its line
  74. //Inputs:
  75. // id = the unique identifier of the data set that was passed in with addData function
  76. removeData(id){
  77. for(let i = 0; i < this.data.length; i++){
  78. if(this.data[i].id === id){
  79. this.data.splice(i, 1);
  80. break;
  81. }
  82. }
  83. this.drawGraph();
  84. }
  85. //Completely clears all data
  86. //Does not delete the current graph displaying
  87. clearData(){
  88. this.max = 0;
  89. this.data = [];
  90. }
  91. /**********
  92. *********PRIVATE*********
  93. **********/
  94. drawGraph(){
  95. this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
  96. this.drawYAxis();
  97. this.drawXAxis();
  98. for(let dataSet of this.data){
  99. this.drawLine(dataSet);
  100. }
  101. }
  102. drawLine(data){
  103. for(let i = 0; i < data.set.length - 1; i++){
  104. this.context.beginPath();
  105. this.context.moveTo(this.left + (this.horizontalMultiplier * i), this.bottom - (this.verticalMultiplier * data.set[i]));
  106. this.context.lineTo(this.left + (this.horizontalMultiplier * (i + 1)), this.bottom - (this.verticalMultiplier * data.set[i + 1]));
  107. this.context.strokeStyle = this.colors[data.colorIndex];
  108. this.context.lineWidth = 3;
  109. this.context.stroke();
  110. }
  111. this.context.strokeStyle = "black";
  112. }
  113. drawXAxis(){
  114. console.log(this.data);
  115. this.context.beginPath();
  116. this.context.moveTo(this.left, this.bottom);
  117. this.context.lineTo(this.right, this.bottom);
  118. this.context.lineWidth = 4;
  119. this.context.stroke();
  120. this.context.font = "25px Arial";
  121. this.context.fillText(this.xName, this.right / 2, this.bottom + 50);
  122. this.context.setLineDash([5, 10]);
  123. this.context.font = "10px Arial";
  124. this.context.lineWidth = 1;
  125. if(Object.prototype.toString.call(this.xRange[0]) === '[object Date]'){
  126. let diff = Math.abs(Math.floor((Date.UTC(this.xRange[0].getFullYear(), this.xRange[0].getMonth(), this.xRange[0].getDate()) - Date.UTC(this.xRange[1].getFullYear(), this.xRange[1].getMonth(), this.xRange[1].getDate())) / (1000 * 60 * 60 * 24))) + 1;
  127. let showDate = new Date(this.xRange[0]);
  128. for(let i = 0; i < diff; i += Math.floor(diff / 10)){
  129. this.context.fillText(showDate.toLocaleDateString("en-US", {month: "short", day: "numeric", year: "2-digit"}), this.left + (this.horizontalMultiplier * i) - 20, this.bottom + 15);
  130. if(i !== 0){
  131. this.context.beginPath()
  132. this.context.moveTo(this.left + (this.horizontalMultiplier * i), this.bottom);
  133. this.context.lineTo(this.left + (this.horizontalMultiplier * i), this.top);
  134. this.context.strokeStyle = "#a5a5a5";
  135. this.context.stroke();
  136. }
  137. showDate.setDate(showDate.getDate() + Math.abs(diff / 10));
  138. }
  139. }
  140. this.context.strokeStyle = "black";
  141. this.context.setLineDash([]);
  142. }
  143. drawYAxis(){
  144. this.context.beginPath();
  145. this.context.moveTo(this.left, this.top);
  146. this.context.lineTo(this.left, this.bottom);
  147. this.context.lineWidth = 2;
  148. this.context.stroke();
  149. this.context.font = "25px Arial";
  150. this.context.fillText(this.yName, 0, this.bottom / 2);
  151. this.context.setLineDash([5, 10]);
  152. this.context.font = "10px Arial";
  153. this.context.lineWidth = 1;
  154. let axisNum = 0;
  155. let verticalIncrement = (this.bottom - this.top) / 10;
  156. let verticalOffset = 0;
  157. do{
  158. this.context.fillText(Math.round(axisNum).toString(), this.left - 20, this.bottom - verticalOffset + 3);
  159. this.context.beginPath();
  160. this.context.moveTo(this.left, this.bottom - verticalOffset);
  161. this.context.lineTo(this.right, this.bottom - verticalOffset);
  162. this.context.strokeStyle = "#a5a5a5";
  163. this.context.stroke();
  164. verticalOffset += verticalIncrement;
  165. axisNum += this.max / 10;
  166. }while(verticalOffset <= (this.bottom - this.top));
  167. this.context.strokeStyle = "black";
  168. this.context.setLineDash([]);
  169. }
  170. }