jquery.flot.dashes.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /*
  2. * jQuery.flot.dashes
  3. *
  4. * options = {
  5. * series: {
  6. * dashes: {
  7. *
  8. * // show
  9. * // default: false
  10. * // Whether to show dashes for the series.
  11. * show: <boolean>,
  12. *
  13. * // lineWidth
  14. * // default: 2
  15. * // The width of the dashed line in pixels.
  16. * lineWidth: <number>,
  17. *
  18. * // dashLength
  19. * // default: 10
  20. * // Controls the length of the individual dashes and the amount of
  21. * // space between them.
  22. * // If this is a number, the dashes and spaces will have that length.
  23. * // If this is an array, it is read as [ dashLength, spaceLength ]
  24. * dashLength: <number> or <array[2]>
  25. * }
  26. * }
  27. * }
  28. */
  29. (function($){
  30. function init(plot) {
  31. plot.hooks.processDatapoints.push(function(plot, series, datapoints) {
  32. if (!series.dashes.show) return;
  33. plot.hooks.draw.push(function(plot, ctx) {
  34. var plotOffset = plot.getPlotOffset(),
  35. axisx = series.xaxis,
  36. axisy = series.yaxis;
  37. function plotDashes(xoffset, yoffset) {
  38. var points = datapoints.points,
  39. ps = datapoints.pointsize,
  40. prevx = null,
  41. prevy = null,
  42. dashRemainder = 0,
  43. dashOn = true,
  44. dashOnLength,
  45. dashOffLength;
  46. if (series.dashes.dashLength[0]) {
  47. dashOnLength = series.dashes.dashLength[0];
  48. if (series.dashes.dashLength[1]) {
  49. dashOffLength = series.dashes.dashLength[1];
  50. } else {
  51. dashOffLength = dashOnLength;
  52. }
  53. } else {
  54. dashOffLength = dashOnLength = series.dashes.dashLength;
  55. }
  56. ctx.beginPath();
  57. for (var i = ps; i < points.length; i += ps) {
  58. var x1 = points[i - ps],
  59. y1 = points[i - ps + 1],
  60. x2 = points[i],
  61. y2 = points[i + 1];
  62. if (x1 == null || x2 == null) continue;
  63. // clip with ymin
  64. if (y1 <= y2 && y1 < axisy.min) {
  65. if (y2 < axisy.min) continue; // line segment is outside
  66. // compute new intersection point
  67. x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
  68. y1 = axisy.min;
  69. } else if (y2 <= y1 && y2 < axisy.min) {
  70. if (y1 < axisy.min) continue;
  71. x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
  72. y2 = axisy.min;
  73. }
  74. // clip with ymax
  75. if (y1 >= y2 && y1 > axisy.max) {
  76. if (y2 > axisy.max) continue;
  77. x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
  78. y1 = axisy.max;
  79. } else if (y2 >= y1 && y2 > axisy.max) {
  80. if (y1 > axisy.max) continue;
  81. x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
  82. y2 = axisy.max;
  83. }
  84. // clip with xmin
  85. if (x1 <= x2 && x1 < axisx.min) {
  86. if (x2 < axisx.min) continue;
  87. y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
  88. x1 = axisx.min;
  89. } else if (x2 <= x1 && x2 < axisx.min) {
  90. if (x1 < axisx.min) continue;
  91. y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
  92. x2 = axisx.min;
  93. }
  94. // clip with xmax
  95. if (x1 >= x2 && x1 > axisx.max) {
  96. if (x2 > axisx.max) continue;
  97. y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
  98. x1 = axisx.max;
  99. } else if (x2 >= x1 && x2 > axisx.max) {
  100. if (x1 > axisx.max) continue;
  101. y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
  102. x2 = axisx.max;
  103. }
  104. if (x1 != prevx || y1 != prevy) {
  105. ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset);
  106. }
  107. var ax1 = axisx.p2c(x1) + xoffset,
  108. ay1 = axisy.p2c(y1) + yoffset,
  109. ax2 = axisx.p2c(x2) + xoffset,
  110. ay2 = axisy.p2c(y2) + yoffset,
  111. dashOffset;
  112. function lineSegmentOffset(segmentLength) {
  113. var c = Math.sqrt(Math.pow(ax2 - ax1, 2) + Math.pow(ay2 - ay1, 2));
  114. if (c <= segmentLength) {
  115. return {
  116. deltaX: ax2 - ax1,
  117. deltaY: ay2 - ay1,
  118. distance: c,
  119. remainder: segmentLength - c
  120. }
  121. } else {
  122. var xsign = ax2 > ax1 ? 1 : -1,
  123. ysign = ay2 > ay1 ? 1 : -1;
  124. return {
  125. deltaX: xsign * Math.sqrt(Math.pow(segmentLength, 2) / (1 + Math.pow((ay2 - ay1)/(ax2 - ax1), 2))),
  126. deltaY: ysign * Math.sqrt(Math.pow(segmentLength, 2) - Math.pow(segmentLength, 2) / (1 + Math.pow((ay2 - ay1)/(ax2 - ax1), 2))),
  127. distance: segmentLength,
  128. remainder: 0
  129. };
  130. }
  131. }
  132. //-end lineSegmentOffset
  133. do {
  134. dashOffset = lineSegmentOffset(
  135. dashRemainder > 0 ? dashRemainder :
  136. dashOn ? dashOnLength : dashOffLength);
  137. if (dashOffset.deltaX != 0 || dashOffset.deltaY != 0) {
  138. if (dashOn) {
  139. ctx.lineTo(ax1 + dashOffset.deltaX, ay1 + dashOffset.deltaY);
  140. } else {
  141. ctx.moveTo(ax1 + dashOffset.deltaX, ay1 + dashOffset.deltaY);
  142. }
  143. }
  144. dashOn = !dashOn;
  145. dashRemainder = dashOffset.remainder;
  146. ax1 += dashOffset.deltaX;
  147. ay1 += dashOffset.deltaY;
  148. } while (dashOffset.distance > 0);
  149. prevx = x2;
  150. prevy = y2;
  151. }
  152. ctx.stroke();
  153. }
  154. //-end plotDashes
  155. ctx.save();
  156. ctx.translate(plotOffset.left, plotOffset.top);
  157. ctx.lineJoin = 'round';
  158. var lw = series.dashes.lineWidth,
  159. sw = series.shadowSize;
  160. // FIXME: consider another form of shadow when filling is turned on
  161. if (lw > 0 && sw > 0) {
  162. // draw shadow as a thick and thin line with transparency
  163. ctx.lineWidth = sw;
  164. ctx.strokeStyle = "rgba(0,0,0,0.1)";
  165. // position shadow at angle from the mid of line
  166. var angle = Math.PI/18;
  167. plotDashes(Math.sin(angle) * (lw/2 + sw/2), Math.cos(angle) * (lw/2 + sw/2));
  168. ctx.lineWidth = sw/2;
  169. plotDashes(Math.sin(angle) * (lw/2 + sw/4), Math.cos(angle) * (lw/2 + sw/4));
  170. }
  171. ctx.lineWidth = lw;
  172. ctx.strokeStyle = series.color;
  173. if (lw > 0) {
  174. plotDashes(0, 0);
  175. }
  176. ctx.restore();
  177. });
  178. //-end draw hook
  179. });
  180. //-end processDatapoints hook
  181. }
  182. //-end init
  183. $.plot.plugins.push({
  184. init: init,
  185. options: {
  186. series: {
  187. dashes: {
  188. show: false,
  189. lineWidth: 2,
  190. dashLength: 10
  191. }
  192. }
  193. },
  194. name: 'dashes',
  195. version: '0.1'
  196. });
  197. })(jQuery)