制作动画 Favicon

Avatar of Preethi
Preethi

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

这是您切换标签时首先看到的内容。

这是解释favicon是什么的一种方式。标签区域比大多数人假设的要珍贵得多。如果做得好,除了作为带有图标的标签外,它还可以成为代表网页内容或正在发生什么的完美广告牌。

CSS-Tricks 的 Favicon

当您不在活动标签上时,Favicon 实际上最有用。这是一个示例

想象一下,您正在将最近夏季度假的照片备份到云服务中。在上传过程中,您打开了一个新标签页,收集有关您去过的地方的详细信息,以便稍后为这些照片添加注释。一件事接着一件事,现在您在第七个标签页上观看 Casey Neistat。但是,在焦急地不时检查云服务页面以查看照片是否已上传之前,您无法继续您的 YouTube 马拉松。

在这种情况下,我们可以发挥创意!如果我们可以动态更改该 favicon 中的像素并显示上传进度会怎么样?这正是我们将在本文中要做的。

在受支持的浏览器中,我们可以借助 JavaScript、HTML <canvas> 和一些古老的几何图形将加载/进度动画显示为 favicon。

直接进入主题,我们将从最简单的部分开始:将图标和 canvas 元素添加到 HTML 中。

<head>
    <link rel="icon" type="image/png" href="" width=32px>
</head>

<body>
    <canvas width=32 height=32></canvas>
</body>

在实际使用中,您可能希望隐藏页面上的<canvas>,一种方法是使用 HTML hidden 属性。

<canvas hidden width=32 height=32></canvas>

我将让<canvas>在页面上可见,以便您可以看到 favicon 和 canvas 图像一起动画。

favicon 和 canvas 都采用标准的 favicon 大小:32 个正方形像素。

出于演示目的,为了触发加载动画,我在页面上添加了一个按钮,单击该按钮将启动动画。这也包含在 HTML 中

<button>Load</button>

现在让我们设置 JavaScript。首先,检查 canvas 支持

onload = ()=> {
  canvas = document.querySelector('canvas'),
  context = canvas.getContext('2d');
  if (!!context) {
      /* if canvas is supported */
  }
};

接下来,添加按钮点击事件处理程序,该处理程序将提示 canvas 中的动画。

button = document.querySelector('button');
button.addEventListener('click', function() { 
    /* A variable to track the drawing intervals */
    n = 0, 
    /* Interval speed for the animation */
    loadingInterval = setInterval(drawLoader, 60); 
});

drawLoader将是每隔 60 毫秒执行一次绘制操作的函数,但在编写代码之前,我想定义要绘制的正方形线条的样式。让我们做一个渐变。

/* Style of the lines of the square that'll be drawn */
let gradient = context.createLinearGradient(0, 0, 32, 32);
gradient.addColorStop(0, '#c7f0fe');
gradient.addColorStop(1, '#56d3c9');
context.strokeStyle = gradient;
context.lineWidth = 8;

drawLoader中,我们将按百分比绘制线条:在前 25 个间隔内,将逐步绘制顶线;在第二季度,将绘制右线;依此类推。

动画效果是通过在每个间隔重新绘制前一个间隔的线条稍微长一点之前擦除<canvas>来实现的。

在每个间隔期间,一旦在 canvas 中完成绘制,它就会快速转换为 PNG 图像,并将其分配为 favicon。

function drawLoader() {
  with(context) {
    clearRect(0, 0, 32, 32);
    beginPath();
    /* Up to 25% */
    if (n<=25){ 
      /*
        (0,0)-----(32,0)
      */
      // code to draw the top line, incrementally
    }
    /* Between 25 to 50 percent */
    else if(n>25 && n<=50){ 
      /*
        (0,0)-----(32,0)
                  |
                  |
                  (32,32)
      */
      // code to draw the top and right lines.
    }
    /* Between 50 to 75 percent */
    else if(n>50 && n<= 75){ 
      /*
        (0,0)-----(32,0)
                  |
                  |
        (0,32)----(32,32)
      */
      // code to draw the top, right and bottom lines.
    }
      /* Between 75 to 100 percent */
    else if(n>75 && n<=100){
      /*
        (0,0)-----(32,0)
            |      |
            |      |
        (0,32)----(32,32)
      */
      // code to draw all four lines of the square.
    }
    stroke();
  }
  // Convert the Canvas drawing to PNG and assign it to the favicon
  favicon.href = canvas.toDataURL('image/png');
  /* When finished drawing */
  if (n === 100) {
    clearInterval(loadingInterval);
    return;
  }
  // Increment the variable used to keep track of the drawing intervals
  n++;
}

现在到绘制线条的数学和代码了。

以下是如何在最初 25 个间隔的每个间隔中逐步绘制顶线

n = current interval, 
x = x-coordinate of the line’s end point at a given interval.
(y-coordinate of the end point is 0 and start point of the line is 0,0)

在所有 25 个间隔完成后,x的值为 32(favicon 和 canvas 的大小)。

所以……

x/n = 32/25
x = (32/25) * n

应用此数学并绘制线条的代码为

moveTo(0, 0); lineTo((32/25)*n, 0);

对于接下来的 25 个间隔(右线),我们以类似的方式定位 y 坐标。

moveTo(0, 0); lineTo(32, 0);
moveTo(32, 0); lineTo(32, (32/25)*(n-25));

这是使用其余代码绘制所有四条线的指令。

function drawLoader() {
  with(context) {
    clearRect(0, 0, 32, 32);
    beginPath();
    /* Up to 25% of the time assigned to draw */
    if (n<=25){ 
      /*
        (0,0)-----(32,0)
      */
      moveTo(0, 0); lineTo((32/25)*n, 0);
    }
    /* Between 25 to 50 percent */
    else if(n>25 && n<=50){ 
      /*
        (0,0)-----(32,0)
                  |
                  |
                  (32,32)
      */
      moveTo(0, 0); lineTo(32, 0);
      moveTo(32, 0); lineTo(32, (32/25)*(n-25));
    }
    /* Between 50 to 75 percent */
    else if(n>50 && n<= 75){ 
      /*
        (0,0)-----(32,0)
                  |
                  |
        (0,32)----(32,32)
      */
      moveTo(0, 0); lineTo(32, 0);
      moveTo(32, 0); lineTo(32, 32);
      moveTo(32, 32); lineTo(-((32/25)*(n-75)), 32);
    }
      /* Between 75 to 100 percent */
    else if(n>75 && n<=100){
      /*
        (0,0)-----(32,0)
            |      |
            |      |
        (0,32)----(32,32)
      */
      moveTo(0, 0); lineTo(32, 0);
      moveTo(32, 0); lineTo(32, 32);
      moveTo(32, 32); lineTo(0, 32);
      moveTo(0, 32); lineTo(0, -((32/25)*(n-100)));
    }
    stroke();
  }

  // Convert the Canvas drawing to PNG and assign it to the favicon
  favicon.href = canvas.toDataURL('image/png');
  /* When finished drawing */
  if (n === 100) {
      clearInterval(loadingInterval);
      return;
  }
  // Increment the variable used to keep track of drawing intervals
  n++;
}

就这样!您可以从此 GitHub 仓库查看并下载演示代码。额外奖励:如果您正在寻找圆形加载程序,请查看此仓库

您可以使用任何形状,如果您在 canvas 绘制中使用fill属性,则会产生不同的效果。