PHP/JavaScript webapp to analyse spending habits
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

jquery.flot.stack.js 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /*
  2. Flot plugin for stacking data sets, i.e. putting them on top of each
  3. other, for accumulative graphs. Note that the plugin assumes the data
  4. is sorted on x. Also note that stacking a mix of positive and negative
  5. values in most instances doesn't make sense (so it looks weird).
  6. Two or more series are stacked when their "stack" attribute is set to
  7. the same key (which can be any number or string or just "true"). To
  8. specify the default stack, you can set
  9. series: {
  10. stack: null or true or key (number/string)
  11. }
  12. or specify it for a specific series
  13. $.plot($("#placeholder"), [{ data: [ ... ], stack: true ])
  14. The stacking order is determined by the order of the data series in
  15. the array (later series end up on top of the previous).
  16. Internally, the plugin modifies the datapoints in each series, adding
  17. an offset to the y value. For line series, extra data points are
  18. inserted through interpolation. For bar charts, the second y value is
  19. also adjusted.
  20. */
  21. (function ($) {
  22. var options = {
  23. series: { stack: null } // or number/string
  24. };
  25. function init(plot) {
  26. function findMatchingSeries(s, allseries) {
  27. var res = null
  28. for (var i = 0; i < allseries.length; ++i) {
  29. if (s == allseries[i])
  30. break;
  31. if (allseries[i].stack == s.stack)
  32. res = allseries[i];
  33. }
  34. return res;
  35. }
  36. function stackData(plot, s, datapoints) {
  37. if (s.stack == null)
  38. return;
  39. var other = findMatchingSeries(s, plot.getData());
  40. if (!other)
  41. return;
  42. var ps = datapoints.pointsize,
  43. points = datapoints.points,
  44. otherps = other.datapoints.pointsize,
  45. otherpoints = other.datapoints.points,
  46. newpoints = [],
  47. px, py, intery, qx, qy, bottom,
  48. withlines = s.lines.show, withbars = s.bars.show,
  49. withsteps = withlines && s.lines.steps,
  50. i = 0, j = 0, l;
  51. while (true) {
  52. if (i >= points.length)
  53. break;
  54. l = newpoints.length;
  55. if (j >= otherpoints.length
  56. || otherpoints[j] == null
  57. || points[i] == null) {
  58. // degenerate cases
  59. for (m = 0; m < ps; ++m)
  60. newpoints.push(points[i + m]);
  61. i += ps;
  62. }
  63. else {
  64. // cases where we actually got two points
  65. px = points[i];
  66. py = points[i + 1];
  67. qx = otherpoints[j];
  68. qy = otherpoints[j + 1];
  69. bottom = 0;
  70. if (px == qx) {
  71. for (m = 0; m < ps; ++m)
  72. newpoints.push(points[i + m]);
  73. newpoints[l + 1] += qy;
  74. bottom = qy;
  75. i += ps;
  76. j += otherps;
  77. }
  78. else if (px > qx) {
  79. // we got past point below, might need to
  80. // insert interpolated extra point
  81. if (withlines && i > 0 && points[i - ps] != null) {
  82. intery = py + (points[i - ps + 1] - py) * (qx - px) / (points[i - ps] - px);
  83. newpoints.push(qx);
  84. newpoints.push(intery + qy)
  85. for (m = 2; m < ps; ++m)
  86. newpoints.push(points[i + m]);
  87. bottom = qy;
  88. }
  89. j += otherps;
  90. }
  91. else {
  92. for (m = 0; m < ps; ++m)
  93. newpoints.push(points[i + m]);
  94. // we might be able to interpolate a point below,
  95. // this can give us a better y
  96. if (withlines && j > 0 && otherpoints[j - ps] != null)
  97. bottom = qy + (otherpoints[j - ps + 1] - qy) * (px - qx) / (otherpoints[j - ps] - qx);
  98. newpoints[l + 1] += bottom;
  99. i += ps;
  100. }
  101. if (l != newpoints.length && withbars)
  102. newpoints[l + 2] += bottom;
  103. }
  104. // maintain the line steps invariant
  105. if (withsteps && l != newpoints.length && l > 0
  106. && newpoints[l] != null
  107. && newpoints[l] != newpoints[l - ps]
  108. && newpoints[l + 1] != newpoints[l - ps + 1]) {
  109. for (m = 0; m < ps; ++m)
  110. newpoints[l + ps + m] = newpoints[l + m];
  111. newpoints[l + 1] = newpoints[l - ps + 1];
  112. }
  113. }
  114. datapoints.points = newpoints;
  115. }
  116. plot.hooks.processDatapoints.push(stackData);
  117. }
  118. $.plot.plugins.push({
  119. init: init,
  120. options: options,
  121. name: 'stack',
  122. version: '1.0'
  123. });
  124. })(jQuery);