contextBackground.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. var createContextBackground = (function() {
  2. var canvas = document.createElement("canvas")
  3. ,ctx = canvas.getContext('2d')
  4. /** @const */
  5. ,WIDTH = canvas.width = 250
  6. /** @const */
  7. ,HEIGHT = canvas.height = 290
  8. /** @const */
  9. ,MARGIN = 20
  10. /** @const */
  11. ,NB_ITEM = 3
  12. /** @const */
  13. ,ITEM_SIZE = (WIDTH -2*MARGIN) / NB_ITEM
  14. /** @const */
  15. ,ITEM_SPACING = 0.1 * ITEM_SIZE
  16. /** @const */
  17. ,ITEM_INNER_SIZE = Math.floor(ITEM_SIZE -(ITEM_SPACING*2))
  18. /** @const */
  19. ,AVATAR_SIZE = ITEM_INNER_SIZE * 0.5
  20. ,RESULT;
  21. var drawItem = function(background, avatar, x0, y0) {
  22. var y0Index = Math.floor(y0)
  23. ,y1Index = Math.floor(y0 + ITEM_SIZE)
  24. ,topColor = [
  25. background.data[y0Index *WIDTH *4 +0]
  26. ,background.data[y0Index *WIDTH *4 +1]
  27. ,background.data[y0Index *WIDTH *4 +2]
  28. ]
  29. ,botColor = [
  30. background.data[y1Index *WIDTH *4 +0]
  31. ,background.data[y1Index *WIDTH *4 +1]
  32. ,background.data[y1Index *WIDTH *4 +2]
  33. ]
  34. ,targetPcent = 1.1
  35. ,targetColor = (((topColor[0] *targetPcent) << 16) |
  36. ((topColor[1] *targetPcent) << 8) |
  37. (topColor[2] *targetPcent)).toString(16);
  38. ctx.fillStyle = '#' +targetColor;
  39. ctx.beginPath();
  40. ctx.moveTo(x0 +ITEM_SIZE /2, y0 +ITEM_SPACING);
  41. ctx.lineTo(x0 -ITEM_SPACING +ITEM_SIZE, y0 +ITEM_SIZE /2);
  42. ctx.lineTo(x0 +ITEM_SIZE /2, y0 -ITEM_SPACING +ITEM_SIZE);
  43. ctx.lineTo(x0 +ITEM_SPACING, y0 +ITEM_SIZE /2);
  44. ctx.closePath();
  45. ctx.fill();
  46. ctx.putImageData(
  47. blend(
  48. ctx.getImageData(
  49. x0 +ITEM_SPACING,
  50. y0 +ITEM_SPACING,
  51. ITEM_INNER_SIZE,
  52. ITEM_INNER_SIZE),
  53. avatar),
  54. x0 +ITEM_SPACING,
  55. y0 +ITEM_SPACING);
  56. };
  57. var blend = function(img, img2) {
  58. var margin = (img.height -img2.height) /2;
  59. for (var i =0; i < img2.height; i++)
  60. for (var j =0; j < img2.width; j++) {
  61. var img2Grey = (img2.data[(i *img2.width +j) *4]) / 255
  62. ,iImg = ((i +margin) *img.width +j +margin) *4;
  63. img.data[iImg] *= img2Grey;
  64. img.data[iImg +1] *= img2Grey;
  65. img.data[iImg +2] *= img2Grey;
  66. }
  67. return img;
  68. }
  69. var drawBackground = function() {
  70. var grd = ctx.createLinearGradient(0, 0, 0, HEIGHT);
  71. grd.addColorStop(0, "#4D394B");
  72. grd.addColorStop(1, "#201820");
  73. ctx.fillStyle = grd;
  74. ctx.fillRect(0, 0, WIDTH, HEIGHT);
  75. return ctx.getImageData(0, 0, WIDTH, HEIGHT)
  76. };
  77. var filterImage = function(img) {
  78. var pixelSum = 0;
  79. for (var i =0; i < img.width *img.height *4; i +=4) {
  80. img.data[i] = img.data[i +1] = img.data[i +2] = (img.data[i] +img.data[i +1] +img.data[i +2]) / 3;
  81. img.data[i +3] = 50;
  82. pixelSum += img.data[i];
  83. }
  84. // Invert colors if image is dark
  85. if (pixelSum / (img.height * img.width) < 50)
  86. for (var i =0; i < img.width *img.height *4; i +=4)
  87. img.data[i] = img.data[i +1] = img.data[i +2] = 255 - img.data[i];
  88. return img;
  89. }
  90. var loadImgFromUrl = function(src, cb) {
  91. var xhr = new XMLHttpRequest();
  92. xhr.responseType = 'blob';
  93. xhr.onreadystatechange = function() {
  94. if (xhr.readyState === 4) {
  95. if (xhr.response) {
  96. var img = new Image();
  97. img.onload = function() {
  98. var imgCanvas = document.createElement("canvas");
  99. imgCanvas.height = imgCanvas.width = AVATAR_SIZE;
  100. var imgCtx = imgCanvas.getContext('2d');
  101. imgCtx.drawImage(img, 0, 0, AVATAR_SIZE, AVATAR_SIZE);
  102. cb(filterImage(imgCtx.getImageData(0, 0, AVATAR_SIZE, AVATAR_SIZE)));
  103. };
  104. img.onerror = function() {
  105. cb(null);
  106. };
  107. img.src = window.URL.createObjectURL(/** @type {Blob!} */ (xhr.response));
  108. } else {
  109. cb(null);
  110. }
  111. }
  112. };
  113. xhr.open('GET', src, true);
  114. xhr.send(null);
  115. };
  116. var loadImages = function(userImgs, doneImgLoading) {
  117. for (var i =0, nbImgs = userImgs.length; i < nbImgs; i++) {
  118. if (userImgs[i].img === undefined) {
  119. // Do load image
  120. loadImgFromUrl(userImgs[i].src, function(img) {
  121. userImgs[i].img = img;
  122. loadImages(userImgs, doneImgLoading);
  123. });
  124. return;
  125. }
  126. }
  127. var imgs = [];
  128. userImgs.forEach(function(i) {
  129. if (i.img)
  130. imgs.push(i.img);
  131. });
  132. doneImgLoading(imgs);
  133. };
  134. var renderAvatars = function(background, imgs) {
  135. imgs.sort(function(a, b) {
  136. return Math.random() - 0.5;
  137. });
  138. for (var imgIndex =0, i =MARGIN; i < WIDTH -MARGIN*2; i += ITEM_SIZE)
  139. for (var j =0; j +ITEM_SIZE <= HEIGHT; j += ITEM_SIZE) {
  140. drawItem(background, imgs[imgIndex], i, j);
  141. imgIndex++;
  142. if (imgIndex === imgs.length) {
  143. imgs.sort(function(a, b) {
  144. if (!a.img)
  145. return 1;
  146. if (!b.img)
  147. return -1;
  148. return Math.random() - 0.5;
  149. });
  150. imgIndex = 0;
  151. }
  152. }
  153. }
  154. return function(cb) {
  155. if (RESULT) {
  156. cb(RESULT);
  157. } else {
  158. var background = drawBackground()
  159. ,userImgs = [];
  160. for (var userId in SLACK.context.users) {
  161. if (!SLACK.context.users[userId].deleted)
  162. userImgs.push({
  163. src: "api/avatar?user=" +userId
  164. });
  165. }
  166. loadImages(userImgs, function(imgs) {
  167. renderAvatars(background, imgs);
  168. RESULT = canvas.toDataURL();
  169. cb(RESULT);
  170. });
  171. }
  172. }
  173. })();