FaviconBadger

Add a counter badge on the favicon

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/453212/1105873/FaviconBadger.js

  1. // ==UserScript==
  2. // @name FaviconBadger
  3. // @description Add a counter badge on the favicon
  4. // @version 1.0
  5. // @author ??
  6. // ==/UserScript==
  7.  
  8. /**
  9. * Create new FaviconBadger instance
  10. * @param {Object} [Options]
  11. * @param {Object} [Options.size=0.6] - Badge's size
  12. * @param {Object} [Options.position='ne'] - Badge's position ['n' 's' 'e' 'w' 'nw' 'ne' 'sw' 'se']
  13. * @param {Object} [Options.radius=8] - Badge's border radius
  14. * @param {Object} [Options.backgroundColor='#f00'] - Badge's background color
  15. * @param {Object} [Options.color='#fff'] - Badge's text color
  16. * @return {Object} FaviconBadger object
  17. * @example
  18. * const faviconBadger = new FaviconBadger({
  19. * size : 0.6,
  20. * position : 'ne',
  21. * radius : 8,
  22. * backgroundColor : '#f00',
  23. * color : '#fff'
  24. * });
  25. * faviconBadger.value = 1;
  26. * faviconBadger.update();
  27. */
  28. const FaviconBadger = (function () {
  29. function FaviconBadger(options) {
  30. const _this = this;
  31. this.backgroundColor = options.backgroundColor || '#f00';
  32. this.color = options.color || '#fff';
  33. this.size = options.size || 0.6;
  34. this.position = options.position || 'ne';
  35. this.radius = options.radius || 8;
  36. // this.src = options.src || '';
  37. this.canvas = document.createElement('canvas');
  38. var _a;
  39. this.src = (_a = document.querySelector('link[rel$=icon]')) === null || _a === void 0 ? void 0 : _a.href;
  40. this.ctx = this.canvas.getContext('2d');
  41. this.faviconSize = 0;
  42. this.offset = { x: 0, y: 0 };
  43. this.badgeSize = 0;
  44. this.value = 0;
  45. this.img = new Image();
  46. this.img.addEventListener('load', function () {
  47. _this.faviconSize = _this.img.naturalWidth;
  48. _this.badgeSize = _this.faviconSize * _this.size;
  49. _this.canvas.width = _this.faviconSize;
  50. _this.canvas.height = _this.faviconSize;
  51. const sd = _this.faviconSize - _this.badgeSize;
  52. const sd2 = sd / 2;
  53. _this.offset = {
  54. n: { x: sd2, y: 0 },
  55. e: { x: sd, y: sd2 },
  56. s: { x: sd2, y: sd },
  57. w: { x: 0, y: sd2 },
  58. nw: { x: 0, y: 0 },
  59. ne: { x: sd, y: 0 },
  60. sw: { x: 0, y: sd },
  61. se: { x: sd, y: sd }
  62. }[_this.position] || { x: 0, y: 0 };
  63. _this._draw();
  64. });
  65. this.img.crossOrigin = 'Anonymous';
  66. this.img.src = this.src;
  67. }
  68. FaviconBadger.prototype._drawIcon = function () {
  69. this.ctx.clearRect(0, 0, this.faviconSize, this.faviconSize);
  70. if (this.value)
  71. this.ctx.drawImage(this.img, 0, 0 + this.faviconSize * 0.2, this.faviconSize * 0.8, this.faviconSize * 0.8);
  72. else
  73. this.ctx.drawImage(this.img, 0, 0, this.faviconSize, this.faviconSize);
  74. };
  75. FaviconBadger.prototype._drawShape = function () {
  76. const r = this.radius;
  77. const xa = this.offset.x;
  78. const ya = this.offset.y;
  79. const xb = this.offset.x + this.badgeSize;
  80. const yb = this.offset.y + this.badgeSize;
  81. this.ctx.beginPath();
  82. this.ctx.moveTo(xb - r, ya);
  83. this.ctx.quadraticCurveTo(xb, ya, xb, ya + r);
  84. this.ctx.lineTo(xb, yb - r);
  85. this.ctx.quadraticCurveTo(xb, yb, xb - r, yb);
  86. this.ctx.lineTo(xa + r, yb);
  87. this.ctx.quadraticCurveTo(xa, yb, xa, yb - r);
  88. this.ctx.lineTo(xa, ya + r);
  89. this.ctx.quadraticCurveTo(xa, ya, xa + r, ya);
  90. this.ctx.fillStyle = this.backgroundColor;
  91. this.ctx.fill();
  92. this.ctx.closePath();
  93.  
  94. const margin = (this.badgeSize * 0.18) / 2;
  95. this.ctx.beginPath();
  96. this.ctx.textBaseline = 'middle';
  97. this.ctx.textAlign = 'center';
  98. this.ctx.font = 'bold '.concat(this.badgeSize * 0.9, 'px Arial');
  99. this.ctx.fillStyle = this.color;
  100. this.ctx.fillText(this.value.toString(), this.badgeSize / 2 + this.offset.x, this.badgeSize / 2 + this.offset.y + margin);
  101. this.ctx.closePath();
  102. };
  103. FaviconBadger.prototype._drawFavicon = function () {
  104. document.querySelectorAll('link[rel*=\'icon\']').forEach(elm => {
  105. elm.parentElement.removeChild(elm);
  106. });
  107. const link = document.createElement('link');
  108. link.type = 'image/x-icon';
  109. link.rel = 'shortcut icon';
  110. link.href = this.canvas.toDataURL();
  111. document.querySelector('head').appendChild(link);
  112. };
  113. FaviconBadger.prototype._draw = function () {
  114. this._drawIcon();
  115. if (this.value)
  116. this._drawShape();
  117. this._drawFavicon();
  118. };
  119. FaviconBadger.prototype.update = function () {
  120. this.value = Math.min(99, parseInt(this.value.toString(), 10));
  121. this._draw();
  122. };
  123. return FaviconBadger;
  124. }());