PHP/JavaScript webapp to analyse spending habits
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

jquery.flot.image.js 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. Flot plugin for plotting images, e.g. useful for putting ticks on a
  3. prerendered complex visualization.
  4. The data syntax is [[image, x1, y1, x2, y2], ...] where (x1, y1) and
  5. (x2, y2) are where you intend the two opposite corners of the image to
  6. end up in the plot. Image must be a fully loaded Javascript image (you
  7. can make one with new Image()). If the image is not complete, it's
  8. skipped when plotting.
  9. There are two helpers included for retrieving images. The easiest work
  10. the way that you put in URLs instead of images in the data (like
  11. ["myimage.png", 0, 0, 10, 10]), then call $.plot.image.loadData(data,
  12. options, callback) where data and options are the same as you pass in
  13. to $.plot. This loads the images, replaces the URLs in the data with
  14. the corresponding images and calls "callback" when all images are
  15. loaded (or failed loading). In the callback, you can then call $.plot
  16. with the data set. See the included example.
  17. A more low-level helper, $.plot.image.load(urls, callback) is also
  18. included. Given a list of URLs, it calls callback with an object
  19. mapping from URL to Image object when all images are loaded or have
  20. failed loading.
  21. Options for the plugin are
  22. series: {
  23. images: {
  24. show: boolean
  25. anchor: "corner" or "center"
  26. alpha: [0,1]
  27. }
  28. }
  29. which can be specified for a specific series
  30. $.plot($("#placeholder"), [{ data: [ ... ], images: { ... } ])
  31. Note that because the data format is different from usual data points,
  32. you can't use images with anything else in a specific data series.
  33. Setting "anchor" to "center" causes the pixels in the image to be
  34. anchored at the corner pixel centers inside of at the pixel corners,
  35. effectively letting half a pixel stick out to each side in the plot.
  36. A possible future direction could be support for tiling for large
  37. images (like Google Maps).
  38. */
  39. (function ($) {
  40. var options = {
  41. series: {
  42. images: {
  43. show: false,
  44. alpha: 1,
  45. anchor: "corner" // or "center"
  46. }
  47. }
  48. };
  49. $.plot.image = {};
  50. $.plot.image.loadDataImages = function (series, options, callback) {
  51. var urls = [], points = [];
  52. var defaultShow = options.series.images.show;
  53. $.each(series, function (i, s) {
  54. if (!(defaultShow || s.images.show))
  55. return;
  56. if (s.data)
  57. s = s.data;
  58. $.each(s, function (i, p) {
  59. if (typeof p[0] == "string") {
  60. urls.push(p[0]);
  61. points.push(p);
  62. }
  63. });
  64. });
  65. $.plot.image.load(urls, function (loadedImages) {
  66. $.each(points, function (i, p) {
  67. var url = p[0];
  68. if (loadedImages[url])
  69. p[0] = loadedImages[url];
  70. });
  71. callback();
  72. });
  73. }
  74. $.plot.image.load = function (urls, callback) {
  75. var missing = urls.length, loaded = {};
  76. if (missing == 0)
  77. callback({});
  78. $.each(urls, function (i, url) {
  79. var handler = function () {
  80. --missing;
  81. loaded[url] = this;
  82. if (missing == 0)
  83. callback(loaded);
  84. };
  85. $('<img />').load(handler).error(handler).attr('src', url);
  86. });
  87. }
  88. function draw(plot, ctx) {
  89. var plotOffset = plot.getPlotOffset();
  90. $.each(plot.getData(), function (i, series) {
  91. var points = series.datapoints.points,
  92. ps = series.datapoints.pointsize;
  93. for (var i = 0; i < points.length; i += ps) {
  94. var img = points[i],
  95. x1 = points[i + 1], y1 = points[i + 2],
  96. x2 = points[i + 3], y2 = points[i + 4],
  97. xaxis = series.xaxis, yaxis = series.yaxis,
  98. tmp;
  99. // actually we should check img.complete, but it
  100. // appears to be a somewhat unreliable indicator in
  101. // IE6 (false even after load event)
  102. if (!img || img.width <= 0 || img.height <= 0)
  103. continue;
  104. if (x1 > x2) {
  105. tmp = x2;
  106. x2 = x1;
  107. x1 = tmp;
  108. }
  109. if (y1 > y2) {
  110. tmp = y2;
  111. y2 = y1;
  112. y1 = tmp;
  113. }
  114. // if the anchor is at the center of the pixel, expand the
  115. // image by 1/2 pixel in each direction
  116. if (series.images.anchor == "center") {
  117. tmp = 0.5 * (x2-x1) / (img.width - 1);
  118. x1 -= tmp;
  119. x2 += tmp;
  120. tmp = 0.5 * (y2-y1) / (img.height - 1);
  121. y1 -= tmp;
  122. y2 += tmp;
  123. }
  124. // clip
  125. if (x1 == x2 || y1 == y2 ||
  126. x1 >= xaxis.max || x2 <= xaxis.min ||
  127. y1 >= yaxis.max || y2 <= yaxis.min)
  128. continue;
  129. var sx1 = 0, sy1 = 0, sx2 = img.width, sy2 = img.height;
  130. if (x1 < xaxis.min) {
  131. sx1 += (sx2 - sx1) * (xaxis.min - x1) / (x2 - x1);
  132. x1 = xaxis.min;
  133. }
  134. if (x2 > xaxis.max) {
  135. sx2 += (sx2 - sx1) * (xaxis.max - x2) / (x2 - x1);
  136. x2 = xaxis.max;
  137. }
  138. if (y1 < yaxis.min) {
  139. sy2 += (sy1 - sy2) * (yaxis.min - y1) / (y2 - y1);
  140. y1 = yaxis.min;
  141. }
  142. if (y2 > yaxis.max) {
  143. sy1 += (sy1 - sy2) * (yaxis.max - y2) / (y2 - y1);
  144. y2 = yaxis.max;
  145. }
  146. x1 = xaxis.p2c(x1);
  147. x2 = xaxis.p2c(x2);
  148. y1 = yaxis.p2c(y1);
  149. y2 = yaxis.p2c(y2);
  150. // the transformation may have swapped us
  151. if (x1 > x2) {
  152. tmp = x2;
  153. x2 = x1;
  154. x1 = tmp;
  155. }
  156. if (y1 > y2) {
  157. tmp = y2;
  158. y2 = y1;
  159. y1 = tmp;
  160. }
  161. tmp = ctx.globalAlpha;
  162. ctx.globalAlpha *= series.images.alpha;
  163. ctx.drawImage(img,
  164. sx1, sy1, sx2 - sx1, sy2 - sy1,
  165. x1 + plotOffset.left, y1 + plotOffset.top,
  166. x2 - x1, y2 - y1);
  167. ctx.globalAlpha = tmp;
  168. }
  169. });
  170. }
  171. function processRawData(plot, series, data, datapoints) {
  172. if (!series.images.show)
  173. return;
  174. // format is Image, x1, y1, x2, y2 (opposite corners)
  175. datapoints.format = [
  176. { required: true },
  177. { x: true, number: true, required: true },
  178. { y: true, number: true, required: true },
  179. { x: true, number: true, required: true },
  180. { y: true, number: true, required: true }
  181. ];
  182. }
  183. function init(plot) {
  184. plot.hooks.processRawData.push(processRawData);
  185. plot.hooks.draw.push(draw);
  186. }
  187. $.plot.plugins.push({
  188. init: init,
  189. options: options,
  190. name: 'image',
  191. version: '1.1'
  192. });
  193. })(jQuery);