Discord 放大小图示

放大滑鼠光标下的图像。

当前为 2020-06-11 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Discord: Zoom In Small Icon
  3. // @name:zh-TW Discord 放大小圖示
  4. // @name:zh-CN Discord 放大小图示
  5. // @name:ja Discord 小さいアイコンにズームイン
  6. // @name:ko Discord 작은 아이콘 확대
  7. // @name:ru Discord Увеличить маленькую иконку
  8. // @version 1.0.0
  9. // @description Zoom in the image which is under the cursor.
  10. // @description:zh-TW 放大滑鼠游標下的圖片。
  11. // @description:zh-CN 放大滑鼠光标下的图像。
  12. // @description:ja カーソルの下にある画像を拡大します。
  13. // @description:ko 커서 아래에있는 이미지를 확대합니다.
  14. // @description:ru Увеличьте изображение под курсором.
  15. // @author Hayao-Gai
  16. // @namespace https://github.com/HayaoGai
  17. // @icon https://i.imgur.com/rE9N0R7.png
  18. // @match https://discord.com/channels/*
  19. // @grant none
  20. // ==/UserScript==
  21.  
  22. /* jshint esversion: 6 */
  23.  
  24. (function() {
  25. 'use strict';
  26.  
  27. const targets = [ "avatarContainer-2inGBK", "avatar-1BDn8e", "wrapper-3t9DeA", "emoji" ];
  28. const textStyle = `
  29. .zoomin-canvas {
  30. border-radius: 8px;
  31. position: fixed;
  32. background-color: #e0e0e0;
  33. pointer-events: none;
  34. opacity: 0 !important;
  35. z-index: 1003;
  36. }
  37. .zoomin-canvas-show {
  38. transition: opacity 0.4s;
  39. opacity: 1 !important;
  40. }
  41. .zoomin-zoom {
  42. position: relative;
  43. left: 5px;
  44. top: 5px;
  45. border-radius: 8px;
  46. pointer-events: none;
  47. opacity: 0 !important;
  48. }
  49. .zoomin-zoom-show {
  50. transition: opacity 0.4s;
  51. opacity: 1 !important;
  52. }`;
  53. let currentUrl = document.location.href;
  54. let updating = false, showing = false;
  55. let canvas, zoom;
  56.  
  57. css();
  58.  
  59. init(10);
  60.  
  61. locationChange();
  62.  
  63. window.addEventListener("scroll", update, true);
  64.  
  65. function init(times) {
  66. for (let i = 0; i < times; i++) {
  67. setTimeout(createCanvas, 500 * i);
  68. setTimeout(createZoom, 500 * i);
  69. for (const target of targets) {
  70. setTimeout(() => eventListener(target), 500 * i);
  71. }
  72. }
  73. }
  74.  
  75. // create
  76. function createCanvas() {
  77. // check exist
  78. if (!!canvas) return;
  79. // create
  80. canvas = document.createElement("div");
  81. canvas.classList.add("zoomin-canvas");
  82. document.body.appendChild(canvas);
  83. }
  84.  
  85. function createZoom() {
  86. // check exist
  87. if (!canvas || !!zoom) return;
  88. // create
  89. zoom = document.createElement("img");
  90. zoom.classList.add("zoomin-zoom");
  91. zoom.style.backgroundColor = getTheme();
  92. canvas.appendChild(zoom);
  93. }
  94.  
  95. // event
  96. function eventListener(target) {
  97. // return if canvas or zoom doesn't exist.
  98. if (!canvas || !zoom) return;
  99. // add target mouse event.
  100. document.querySelectorAll(`.${target}:not(zoomin-listener)`).forEach(t => {
  101. t.classList.add("zoomin-listener");
  102. t.addEventListener("mousemove", showImage);
  103. t.addEventListener("mouseleave", hideImage);
  104. });
  105. }
  106.  
  107. function showImage() {
  108. // avoid calling this function multiple times.
  109. if (showing) return;
  110. showing = true;
  111. // detail
  112. const url = getSource(this);
  113. if (!url) return;
  114. zoom.setAttribute("src", url);
  115. zoomDetail();
  116. }
  117.  
  118. function hideImage() {
  119. showing = false;
  120. canvas.classList.remove("zoomin-canvas-show");
  121. zoom.classList.remove("zoomin-zoom-show");
  122. setTimeout(() => {
  123. if (!showing) zoom.removeAttribute("src");
  124. }, 500);
  125. }
  126.  
  127. function zoomDetail() {
  128. // wait until get the image size.
  129. if (!zoom.naturalWidth)
  130. {
  131. setTimeout(zoomDetail, 100);
  132. return;
  133. }
  134. // size
  135. const w = zoom.naturalWidth;
  136. const h = zoom.naturalHeight;
  137. canvas.style.width = `${w + 10}px`;
  138. canvas.style.height = `${h + 10}px`;
  139. zoom.style.width = `${w}px`;
  140. zoom.style.height = `${h}px`;
  141. // position
  142. let left = getCursorX();
  143. let top = getCursorY();
  144. const clientW = document.documentElement.clientWidth;
  145. // situation 1: the icon position is too right to show.
  146. if (left + w > clientW) left = left - w;
  147. // situation 2: the icon position is too top to show.
  148. if (top - h - 30 > 0) top = top - h - 30;
  149. canvas.style.left = `${left}px`;
  150. canvas.style.top = `${top}px`;
  151. // class
  152. canvas.classList.add("zoomin-canvas-show");
  153. zoom.classList.add("zoomin-zoom-show");
  154. }
  155.  
  156. // method
  157. function getSource(element) {
  158. // situation 1: image
  159. if (!!element.src) return element.src;
  160. // situation 2: div with style
  161. else if (!!element.style.backgroundImage) return element.style.backgroundImage.split(/"/)[1];
  162. // situation 3: div children
  163. else if (!!element.querySelector("img")) return element.querySelector("img").src;
  164. // situation 4: not an image
  165. else return null;
  166. }
  167.  
  168. function getTheme() {
  169. const theme = document.querySelector("html").className.includes("light") ? "#ffffff" : "#363940";
  170. return theme;
  171. }
  172.  
  173. function getCursorX() {
  174. const e = window.event;
  175. return e.pageX - document.documentElement.scrollLeft - document.body.scrollLeft;
  176. }
  177.  
  178. function getCursorY() {
  179. const e = window.event;
  180. return e.pageY - document.documentElement.scrollTop - document.body.scrollTop;
  181. }
  182.  
  183. // others
  184. function css() {
  185. const style = document.createElement("style");
  186. style.type = "text/css";
  187. style.innerHTML = textStyle;
  188. document.head.appendChild(style);
  189. }
  190.  
  191. function update() {
  192. if (updating) return;
  193. updating = true;
  194. init(3);
  195. setTimeout(() => { updating = false; }, 1000);
  196. }
  197.  
  198. function locationChange() {
  199. const observer = new MutationObserver(mutations => {
  200. mutations.forEach(() => {
  201. if (currentUrl !== document.location.href) {
  202. currentUrl = document.location.href;
  203. init(10);
  204. }
  205. });
  206. });
  207. const target = document.body;
  208. const config = { childList: true, subtree: true };
  209. observer.observe(target, config);
  210. }
  211.  
  212. })();