Furaffinity-Loading-Animations

Library for creating different loading animations on Furaffinity

이 스크립트는 직접 설치해서 쓰는 게 아닙니다. 다른 스크립트가 메타 명령 // @require https://update.greatest.deepsurf.us/scripts/485153/1549461/Furaffinity-Loading-Animations.js(으)로 포함하여 쓰는 라이브러리입니다.

질문, 리뷰하거나, 이 스크립트를 신고하세요.
  1. // ==UserScript==
  2. // @name Furaffinity-Loading-Animations
  3. // @namespace Violentmonkey Scripts
  4. // @require https://update.greatest.deepsurf.us/scripts/525666/1549449/Furaffinity-Prototype-Extensions.js
  5. // @grant none
  6. // @version 1.2.1
  7. // @author Midori Dragon
  8. // @description Library for creating different loading animations on Furaffinity
  9. // @icon https://www.furaffinity.net/themes/beta/img/banners/fa_logo.png
  10. // @license MIT
  11. // @homepageURL https://greatest.deepsurf.us/scripts/485153-furaffinity-loading-animations
  12. // @supportURL https://greatest.deepsurf.us/scripts/485153-furaffinity-loading-animations/feedback
  13. // ==/UserScript==
  14. // jshint esversion: 8
  15. (() => {
  16. "use strict";
  17. class LoadingBar {
  18. constructor(baseElem) {
  19. this._delay = 2e3;
  20. this._loadingBar = document.createElement("div");
  21. if (!document.getElementById("flaloadingbarstyle")) {
  22. const style = document.createElement("style");
  23. style.id = "flaloadingbarstyle";
  24. style.innerHTML = "@keyframes gradient { 0% { background-position: 0 0; } 100% { background-position: -200% 0; } }";
  25. document.head.appendChild(style);
  26. }
  27. this._baseElem = baseElem;
  28. this._baseElem.appendChild(this._loadingBar);
  29. this.updateBaseElem();
  30. }
  31. get baseElem() {
  32. return this._baseElem;
  33. }
  34. set baseElem(value) {
  35. if (this._baseElem !== value) {
  36. this._baseElem = value;
  37. this.updateBaseElem();
  38. }
  39. }
  40. get delay() {
  41. return this._delay;
  42. }
  43. set delay(value) {
  44. if (this._delay !== value) {
  45. this._delay = value;
  46. this._loadingBar.style.animation = `gradient ${this._delay / 1e3}s infinite`;
  47. }
  48. }
  49. get text() {
  50. var _a;
  51. return null !== (_a = this._loadingBar.textContent) && void 0 !== _a ? _a : "";
  52. }
  53. set text(value) {
  54. if (this._loadingBar.textContent !== value) this._loadingBar.textContent = value;
  55. }
  56. get cornerRadius() {
  57. return parseFloat(this._loadingBar.style.borderRadius.trimEnd("px"));
  58. }
  59. set cornerRadius(value) {
  60. if (parseFloat(this._loadingBar.style.borderRadius.trimEnd("px")) !== value) this._loadingBar.style.borderRadius = value + "px";
  61. }
  62. get height() {
  63. return parseFloat(this._loadingBar.style.height.trimEnd("px"));
  64. }
  65. set height(value) {
  66. if (parseFloat(this._loadingBar.style.height.trimEnd("px")) !== value) {
  67. this._loadingBar.style.height = value + "px";
  68. this._loadingBar.style.lineHeight = value + "px";
  69. }
  70. }
  71. get fontSize() {
  72. return parseFloat(this._loadingBar.style.fontSize.trimEnd("px"));
  73. }
  74. set fontSize(value) {
  75. if (parseFloat(this._loadingBar.style.fontSize.trimEnd("px")) !== value) if (null != value) this._loadingBar.style.fontSize = value + "px"; else this._loadingBar.style.fontSize = "";
  76. }
  77. get gradient() {
  78. return this._loadingBar.style.background;
  79. }
  80. set gradient(value) {
  81. if (this._loadingBar.style.background !== value) this._loadingBar.style.background = value;
  82. }
  83. get visible() {
  84. return "none" !== this._loadingBar.style.display;
  85. }
  86. set visible(value) {
  87. if (this._loadingBar.style.display !== (value ? "block" : "none")) this._loadingBar.style.display = value ? "block" : "none";
  88. }
  89. dispose() {
  90. this.visible = false;
  91. this._baseElem.removeChild(this._loadingBar);
  92. }
  93. updateBaseElem() {
  94. this._loadingBar.className = "fla-loadingbar";
  95. this._loadingBar.textContent = this.text;
  96. this._loadingBar.style.width = "100%";
  97. this._loadingBar.style.height = "60px";
  98. this._loadingBar.style.lineHeight = this.height + "px";
  99. this._loadingBar.style.textShadow = "-1px -1px 0 #000000, 1px -1px 0 #000000, -1px 1px 0 #000000, 1px 1px 0 #000000";
  100. this._loadingBar.style.fontSize = "15px";
  101. this._loadingBar.style.background = "repeating-linear-gradient(to right, rgba(255,10,3,1) 0%, rgba(255,139,6,1) 8%, rgba(253,228,11,1) 16%, rgba(127,236,12,1) 26%, rgba(32,225,207,1) 36%, rgba(140,60,223,1) 46%, rgba(140,60,223,1) 54%, rgba(32,225,207,1) 64%, rgba(127,236,12,1) 74%, rgba(253,228,11,1) 84%, rgba(255,139,6,1) 92%, rgba(255,10,3,1) 100%)";
  102. this._loadingBar.style.backgroundSize = "200% auto";
  103. this._loadingBar.style.backgroundPosition = "0 100%";
  104. this._loadingBar.style.animation = `gradient ${this.delay / 1e3}s infinite`;
  105. this._loadingBar.style.animationFillMode = "forwards";
  106. this._loadingBar.style.animationTimingFunction = "linear";
  107. this._loadingBar.style.display = "none";
  108. }
  109. }
  110. class LoadingImage {
  111. constructor(baseElem) {
  112. this.delay = 100;
  113. this.doScaleImage = true;
  114. this.scaleChange = .05;
  115. this.scaleChangeMax = 1.2;
  116. this.scaleChangeMin = .8;
  117. this.doRotateImage = true;
  118. this.rotateDegrees = 5;
  119. this._isGrowing = true;
  120. this._scale = 1;
  121. this._rotation = 0;
  122. this._size = 60;
  123. this._image = document.createElement("img");
  124. this._image.src = "https://www.furaffinity.net/themes/beta/img/banners/fa_logo.png";
  125. this._imageContainer = document.createElement("div");
  126. this._baseElem = baseElem;
  127. this._imageContainer.appendChild(this._image);
  128. this._baseElem.appendChild(this._imageContainer);
  129. this.updateBaseElem();
  130. }
  131. get baseElem() {
  132. return this._baseElem;
  133. }
  134. set baseElem(value) {
  135. if (this._baseElem !== value) {
  136. this._baseElem = value;
  137. this.updateBaseElem();
  138. }
  139. }
  140. get imageSrc() {
  141. return this._image.src;
  142. }
  143. set imageSrc(value) {
  144. if (this._image.src !== value) this._image.src = value;
  145. }
  146. get rotation() {
  147. return this._rotation;
  148. }
  149. set rotation(value) {
  150. if (this._rotation !== value) {
  151. this._rotation = value;
  152. this._image.style.transform = `scale(${this._scale}) rotate(${this._rotation}deg)`;
  153. }
  154. }
  155. get scale() {
  156. return this._scale;
  157. }
  158. set scale(value) {
  159. if (this._scale !== value) {
  160. this._scale = value;
  161. this._image.style.transform = `scale(${this._scale}) rotate(${this._rotation}deg)`;
  162. }
  163. }
  164. get size() {
  165. return parseFloat(this._imageContainer.style.width.trimEnd("px"));
  166. }
  167. set size(value) {
  168. if (parseFloat(this._imageContainer.style.width.trimEnd("px")) !== value) {
  169. this._imageContainer.style.width = this._size + "px";
  170. this._imageContainer.style.height = this._size + "px";
  171. }
  172. }
  173. get visible() {
  174. return "none" !== this._imageContainer.style.display;
  175. }
  176. set visible(value) {
  177. if (this._imageContainer.style.display !== (value ? "block" : "none")) {
  178. this._imageContainer.style.display = value ? "block" : "none";
  179. if (value) this._intervalId = setInterval((() => {
  180. this.updateAnimationFrame();
  181. }), this.delay); else clearInterval(this._intervalId);
  182. }
  183. }
  184. get isGrowing() {
  185. return this._isGrowing;
  186. }
  187. set isGrowing(value) {
  188. if (this._isGrowing !== value) this._isGrowing = value;
  189. }
  190. dispose() {
  191. this.visible = false;
  192. this._baseElem.removeChild(this._imageContainer);
  193. }
  194. updateBaseElem() {
  195. this._imageContainer.className = "fla-loading-image-container";
  196. this._imageContainer.style.position = "relative";
  197. this._imageContainer.style.width = this.size + "px";
  198. this._imageContainer.style.height = this.size + "px";
  199. this._imageContainer.style.left = "50%";
  200. this._imageContainer.style.transform = "translateX(-50%)";
  201. this._imageContainer.style.display = "none";
  202. this._image.className = "fla-loading-image";
  203. this._image.src = this.imageSrc;
  204. this._image.style.width = "100%";
  205. this._image.style.height = "100%";
  206. this._image.style.transition = "transform 0.5s ease-in-out";
  207. }
  208. updateAnimationFrame() {
  209. if (this.isGrowing) {
  210. this._scale += this.scaleChange;
  211. this._rotation += this.rotateDegrees;
  212. } else {
  213. this._scale -= this.scaleChange;
  214. this._rotation -= this.rotateDegrees;
  215. }
  216. if (this._scale >= this.scaleChangeMax || this._scale <= this.scaleChangeMin) this.isGrowing = !this.isGrowing;
  217. this._image.style.transform = `scale(${this._scale}) rotate(${this._rotation}deg)`;
  218. }
  219. }
  220. class LoadingSpinner {
  221. constructor(baseElem) {
  222. this._delay = 1e3;
  223. this._size = 60;
  224. this._spinnerThickness = 4;
  225. this._spinnerLength = 1;
  226. this._linearSpin = false;
  227. this._animationCurve = "cubic-bezier(.53,.24,.46,.83)";
  228. this._forecolorHex = "#8941de";
  229. this._backcolorHex = "#f3f3f3";
  230. this._spinner = document.createElement("div");
  231. this._spinnerContainer = document.createElement("div");
  232. if (!document.getElementById("flaspinnerstyle")) {
  233. const style = document.createElement("style");
  234. style.id = "flaspinnerstyle";
  235. style.innerHTML = "@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }";
  236. document.head.appendChild(style);
  237. }
  238. this._baseElem = baseElem;
  239. this._spinnerContainer.appendChild(this._spinner);
  240. this._baseElem.appendChild(this._spinnerContainer);
  241. this.updateBaseElem();
  242. }
  243. get baseElem() {
  244. return this._baseElem;
  245. }
  246. set baseElem(value) {
  247. if (this._baseElem !== value) {
  248. this._baseElem = value;
  249. this.updateBaseElem();
  250. }
  251. }
  252. get delay() {
  253. return this._delay;
  254. }
  255. set delay(value) {
  256. if (this._delay !== value) {
  257. this._delay = value;
  258. this._spinner.style.animation = `spin ${this._delay / 1e3}s ${this.animationCurve} infinite`;
  259. }
  260. }
  261. get linearSpin() {
  262. return this._linearSpin;
  263. }
  264. set linearSpin(value) {
  265. if (this._linearSpin !== value) {
  266. this._linearSpin = value;
  267. this._animationCurve = this._linearSpin ? "linear" : "cubic-bezier(.53,.24,.46,.83)";
  268. this._spinner.style.animation = `spin ${this.delay / 1e3}s ${this.animationCurve} infinite`;
  269. }
  270. }
  271. get animationCurve() {
  272. return this._animationCurve;
  273. }
  274. set animationCurve(value) {
  275. if (this._animationCurve !== value) {
  276. this._animationCurve = value;
  277. this._linearSpin = "linear" === this._animationCurve;
  278. this._spinner.style.animation = `spin ${this.delay / 1e3}s ${this.animationCurve} infinite`;
  279. }
  280. }
  281. get size() {
  282. return this._size;
  283. }
  284. set size(value) {
  285. if (this._size !== value) {
  286. this._size = value;
  287. this.updateSize();
  288. }
  289. }
  290. get spinnerThickness() {
  291. return this._spinnerThickness;
  292. }
  293. set spinnerThickness(value) {
  294. if (this._spinnerThickness !== value) {
  295. this._spinnerThickness = value;
  296. this.updateSpinnerBorders();
  297. this.updateSize();
  298. }
  299. }
  300. get spinnerLength() {
  301. return this._spinnerLength;
  302. }
  303. set spinnerLength(value) {
  304. if (this._spinnerLength !== value) {
  305. this._spinnerLength = value;
  306. this.updateSpinnerBorders();
  307. }
  308. }
  309. get forecolorHex() {
  310. return this._forecolorHex;
  311. }
  312. set forecolorHex(value) {
  313. if (this._forecolorHex !== value) {
  314. if (!value.startsWith("#")) value = "#" + value;
  315. this._forecolorHex = value;
  316. this.updateSpinnerBorders();
  317. }
  318. }
  319. get backcolorHex() {
  320. return this._backcolorHex;
  321. }
  322. set backcolorHex(value) {
  323. if (this._backcolorHex !== value) {
  324. if (!value.startsWith("#")) value = "#" + value;
  325. this._backcolorHex = value;
  326. this.updateSpinnerBorders();
  327. }
  328. }
  329. get visible() {
  330. return "none" !== this._spinnerContainer.style.display;
  331. }
  332. set visible(value) {
  333. if (this._spinnerContainer.style.display !== (value ? "block" : "none")) this._spinnerContainer.style.display = value ? "block" : "none";
  334. }
  335. dispose() {
  336. this.visible = false;
  337. this._baseElem.removeChild(this._spinnerContainer);
  338. }
  339. updateSize() {
  340. this._spinnerContainer.style.width = this.size + "px";
  341. this._spinnerContainer.style.height = this.size + "px";
  342. this._spinner.style.width = this.size - 2 * this.spinnerThickness + "px";
  343. this._spinner.style.height = this.size - 2 * this.spinnerThickness + "px";
  344. }
  345. updateSpinnerBorders() {
  346. this._spinner.style.border = this.spinnerThickness + "px solid " + this.backcolorHex;
  347. if (this.spinnerLength >= 4) this._spinner.style.borderLeft = this.spinnerThickness + "px solid " + this._forecolorHex; else if (this.spinnerLength >= 3) this._spinner.style.borderBottom = this.spinnerThickness + "px solid " + this._forecolorHex; else if (this.spinnerLength >= 2) this._spinner.style.borderRight = this.spinnerThickness + "px solid " + this._forecolorHex; else if (this.spinnerLength >= 1) this._spinner.style.borderTop = this.spinnerThickness + "px solid " + this._forecolorHex;
  348. }
  349. updateBaseElem() {
  350. this._spinnerContainer.className = "fla-spinner-container";
  351. this._spinnerContainer.style.position = "relative";
  352. this._spinnerContainer.style.width = this.size + "px";
  353. this._spinnerContainer.style.height = this.size + "px";
  354. this._spinnerContainer.style.left = "50%";
  355. this._spinnerContainer.style.transform = "translateX(-50%)";
  356. this._spinnerContainer.style.display = "none";
  357. this._spinner.className = "fla-spinner";
  358. this.updateSpinnerBorders();
  359. this._spinner.style.borderRadius = "50%";
  360. this._spinner.style.position = "relative";
  361. this._spinner.style.width = this.size - 2 * this.spinnerThickness + "px";
  362. this._spinner.style.height = this.size - 2 * this.spinnerThickness + "px";
  363. this._spinner.style.animation = `spin ${this.delay / 1e3}s ${this.animationCurve} infinite`;
  364. this.updateSize();
  365. }
  366. }
  367. class LoadingTextSpinner {
  368. constructor(baseElem) {
  369. this._characters = [ "◜", "◠", "◝", "◞", "◡", "◟" ];
  370. this._delay = 600;
  371. this._currIndex = -1;
  372. this._spinner = document.createElement("div");
  373. this._baseElem = baseElem;
  374. this._baseElem.appendChild(this._spinner);
  375. this.updateBaseElem();
  376. }
  377. get baseElem() {
  378. return this._baseElem;
  379. }
  380. set baseElem(value) {
  381. if (this._baseElem !== value) {
  382. this._baseElem = value;
  383. this.updateBaseElem();
  384. }
  385. }
  386. get fontSize() {
  387. return parseFloat(this._spinner.style.fontSize.trimEnd("px"));
  388. }
  389. set fontSize(value) {
  390. if (parseFloat(this._spinner.style.fontSize.trimEnd("px")) !== value) this._spinner.style.fontSize = value + "px";
  391. }
  392. get visible() {
  393. return "none" !== this._spinner.style.display;
  394. }
  395. set visible(value) {
  396. if (this._spinner.style.display !== (value ? "block" : "none")) {
  397. this._spinner.style.display = value ? "block" : "none";
  398. if (value) this.start(); else this.stop();
  399. }
  400. }
  401. get delay() {
  402. return this._delay;
  403. }
  404. set delay(value) {
  405. if (this._delay !== value) {
  406. this._delay = value;
  407. if (this.visible) {
  408. this.stop();
  409. this.start();
  410. }
  411. }
  412. }
  413. get characters() {
  414. return this._characters;
  415. }
  416. set characters(value) {
  417. if (this._characters !== value) {
  418. this._characters = value;
  419. if (this.visible) {
  420. this.stop();
  421. this.start();
  422. }
  423. }
  424. }
  425. dispose() {
  426. this.visible = false;
  427. this._baseElem.removeChild(this._spinner);
  428. }
  429. start() {
  430. if (null == this._intervalId && 0 !== this._characters.length) {
  431. if (this._currIndex < 0) this._currIndex = 0;
  432. this._prevContainerTextContent = function removeTextNodes(targetElement) {
  433. let removedText = "";
  434. !function traverseAndRemoveTextNodes(node) {
  435. var _a;
  436. for (let i = node.childNodes.length - 1; i >= 0; i--) {
  437. const child = node.childNodes[i];
  438. if (child.nodeType === Node.TEXT_NODE) {
  439. removedText += (null !== (_a = child.textContent) && void 0 !== _a ? _a : "") + "\n";
  440. node.removeChild(child);
  441. }
  442. }
  443. }(targetElement);
  444. return removedText;
  445. }(this._baseElem);
  446. this._spinner.textContent = "⠀⠀";
  447. this._intervalId = setInterval((() => {
  448. if (this._currIndex >= this.characters.length) this._currIndex = 0;
  449. this._spinner.textContent = this.characters[this._currIndex];
  450. this._currIndex++;
  451. }), this.delay / this.characters.length);
  452. }
  453. }
  454. stop() {
  455. var _a;
  456. if (null != this._intervalId) {
  457. clearInterval(this._intervalId);
  458. this._baseElem.textContent = null !== (_a = this._prevContainerTextContent) && void 0 !== _a ? _a : null;
  459. this._intervalId = void 0;
  460. }
  461. }
  462. updateBaseElem() {
  463. this._spinner.className = "fla-text-spinner";
  464. this._spinner.style.display = "none";
  465. this._spinner.style.fontSize = "15px";
  466. }
  467. }
  468. Object.defineProperties(window, {
  469. FALoadingSpinner: {
  470. get: () => LoadingSpinner
  471. },
  472. FALoadingTextSpinner: {
  473. get: () => LoadingTextSpinner
  474. },
  475. FALoadingImage: {
  476. get: () => LoadingImage
  477. },
  478. FALoadingBar: {
  479. get: () => LoadingBar
  480. }
  481. });
  482. })();