contextBackground.js 6.2 KB

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