canvascomponents.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. "use strict";
  2. /**
  3. * Various components for drawing diagrams on an HTML5 canvas.
  4. *
  5. * @author n1474335 [n1474335@gmail.com]
  6. * @copyright Crown Copyright 2016
  7. * @license Apache-2.0
  8. *
  9. * @constant
  10. * @namespace
  11. */
  12. const CanvasComponents = {
  13. drawLine: function(ctx, startX, startY, endX, endY) {
  14. ctx.beginPath();
  15. ctx.moveTo(startX, startY);
  16. ctx.lineTo(endX, endY);
  17. ctx.closePath();
  18. ctx.stroke();
  19. },
  20. drawBarChart: function(canvas, scores, xAxisLabel, yAxisLabel, numXLabels, numYLabels, fontSize) {
  21. fontSize = fontSize || 15;
  22. if (!numXLabels || numXLabels > Math.round(canvas.width / 50)) {
  23. numXLabels = Math.round(canvas.width / 50);
  24. }
  25. if (!numYLabels || numYLabels > Math.round(canvas.width / 50)) {
  26. numYLabels = Math.round(canvas.height / 50);
  27. }
  28. // Graph properties
  29. var ctx = canvas.getContext("2d"),
  30. leftPadding = canvas.width * 0.08,
  31. rightPadding = canvas.width * 0.03,
  32. topPadding = canvas.height * 0.08,
  33. bottomPadding = canvas.height * 0.15,
  34. graphHeight = canvas.height - topPadding - bottomPadding,
  35. graphWidth = canvas.width - leftPadding - rightPadding,
  36. base = topPadding + graphHeight,
  37. ceil = topPadding;
  38. ctx.font = fontSize + "px Arial";
  39. // Draw axis
  40. ctx.lineWidth = "1.0";
  41. ctx.strokeStyle = "#444";
  42. CanvasComponents.drawLine(ctx, leftPadding, base, graphWidth + leftPadding, base); // x
  43. CanvasComponents.drawLine(ctx, leftPadding, base, leftPadding, ceil); // y
  44. // Bar properties
  45. var barPadding = graphWidth * 0.003,
  46. barWidth = (graphWidth - (barPadding * scores.length)) / scores.length,
  47. currX = leftPadding + barPadding,
  48. max = Math.max.apply(Math, scores);
  49. // Draw bars
  50. ctx.fillStyle = "green";
  51. for (var i = 0; i < scores.length; i++) {
  52. var h = scores[i] / max * graphHeight;
  53. ctx.fillRect(currX, base - h, barWidth, h);
  54. currX += barWidth + barPadding;
  55. }
  56. // Mark x axis
  57. ctx.fillStyle = "black";
  58. ctx.textAlign = "center";
  59. currX = leftPadding + barPadding;
  60. if (numXLabels >= scores.length) {
  61. // Mark every score
  62. for (i = 0; i <= scores.length; i++) {
  63. ctx.fillText(i, currX, base + (bottomPadding * 0.3));
  64. currX += barWidth + barPadding;
  65. }
  66. } else {
  67. // Mark some scores
  68. for (i = 0; i <= numXLabels; i++) {
  69. var val = Math.ceil((scores.length / numXLabels) * i);
  70. currX = (graphWidth / numXLabels) * i + leftPadding;
  71. ctx.fillText(val, currX, base + (bottomPadding * 0.3));
  72. }
  73. }
  74. // Mark y axis
  75. ctx.textAlign = "right";
  76. var currY;
  77. if (numYLabels >= max) {
  78. // Mark every increment
  79. for (i = 0; i <= max; i++) {
  80. currY = base - (i / max * graphHeight) + fontSize / 3;
  81. ctx.fillText(i, leftPadding * 0.8, currY);
  82. }
  83. } else {
  84. // Mark some increments
  85. for (i = 0; i <= numYLabels; i++) {
  86. val = Math.ceil((max / numYLabels) * i);
  87. currY = base - (val / max * graphHeight) + fontSize / 3;
  88. ctx.fillText(val, leftPadding * 0.8, currY);
  89. }
  90. }
  91. // Label x axis
  92. if (xAxisLabel) {
  93. ctx.textAlign = "center";
  94. ctx.fillText(xAxisLabel, graphWidth / 2 + leftPadding, base + bottomPadding * 0.8);
  95. }
  96. // Label y axis
  97. if (yAxisLabel) {
  98. ctx.save();
  99. var x = leftPadding * 0.3,
  100. y = graphHeight / 2 + topPadding;
  101. ctx.translate(x, y);
  102. ctx.rotate(-Math.PI / 2);
  103. ctx.textAlign = "center";
  104. ctx.fillText(yAxisLabel, 0, 0);
  105. ctx.restore();
  106. }
  107. },
  108. drawScaleBar: function(canvas, score, max, markings) {
  109. // Bar properties
  110. var ctx = canvas.getContext("2d"),
  111. leftPadding = canvas.width * 0.01,
  112. rightPadding = canvas.width * 0.01,
  113. topPadding = canvas.height * 0.1,
  114. bottomPadding = canvas.height * 0.3,
  115. barHeight = canvas.height - topPadding - bottomPadding,
  116. barWidth = canvas.width - leftPadding - rightPadding;
  117. // Scale properties
  118. var proportion = score / max;
  119. // Draw bar outline
  120. ctx.strokeRect(leftPadding, topPadding, barWidth, barHeight);
  121. // Shade in up to proportion
  122. var grad = ctx.createLinearGradient(leftPadding, 0, barWidth + leftPadding, 0);
  123. grad.addColorStop(0, "green");
  124. grad.addColorStop(0.5, "gold");
  125. grad.addColorStop(1, "red");
  126. ctx.fillStyle = grad;
  127. ctx.fillRect(leftPadding, topPadding, barWidth * proportion, barHeight);
  128. // Add markings
  129. var x0, y0, x1, y1;
  130. ctx.fillStyle = "black";
  131. ctx.textAlign = "center";
  132. ctx.font = "13px Arial";
  133. for (var i = 0; i < markings.length; i++) {
  134. // Draw min line down
  135. x0 = barWidth / max * markings[i].min + leftPadding;
  136. y0 = topPadding + barHeight + (bottomPadding * 0.1);
  137. x1 = x0;
  138. y1 = topPadding + barHeight + (bottomPadding * 0.3);
  139. CanvasComponents.drawLine(ctx, x0, y0, x1, y1);
  140. // Draw max line down
  141. x0 = barWidth / max * markings[i].max + leftPadding;
  142. x1 = x0;
  143. CanvasComponents.drawLine(ctx, x0, y0, x1, y1);
  144. // Join min and max lines
  145. x0 = barWidth / max * markings[i].min + leftPadding;
  146. y0 = topPadding + barHeight + (bottomPadding * 0.3);
  147. x1 = barWidth / max * markings[i].max + leftPadding;
  148. y1 = y0;
  149. CanvasComponents.drawLine(ctx, x0, y0, x1, y1);
  150. // Add label
  151. if (markings[i].max >= max * 0.9) {
  152. ctx.textAlign = "right";
  153. x0 = x1;
  154. } else if (markings[i].max <= max * 0.1) {
  155. ctx.textAlign = "left";
  156. } else {
  157. x0 = x0 + (x1 - x0) / 2;
  158. }
  159. y0 = topPadding + barHeight + (bottomPadding * 0.8);
  160. ctx.fillText(markings[i].label, x0, y0);
  161. }
  162. },
  163. };
  164. export default CanvasComponents;