在特定帧上在Canvas上呈现文本?

huangapple go评论73阅读模式
英文:

Rendering text in Canvas at a specific frame?

问题

我试图学习如何使用画布来创建类似于苹果Airpods页面的效果。我一直在按照教程进行操作,该教程显示了如何对不同的图像进行动画处理,使每一帧对应滚动。我的问题是,在帧之间如何添加文本?例如,在第50-100帧之间,应该在屏幕中央出现一个文本,并在第100帧过后消失。我最初的想法是使用if语句,在帧计数处于两个值之间时触发它。这样做可以,但它将文本放在文档的顶部。我似乎找不到如何通过画布渲染它的任何信息。我对画布非常陌生,所以希望你能容忍我!

以下是相关代码:

const html = document.documentElement;
const canvas = document.querySelector('.airpods-scrolling');
const context = canvas.getContext('2d');

const currentFrame = index => (
  `https://www.apple.com/105/media/us/airpods-pro/2019/1299e2f5_9206_4470_b28e_08307a42f19b/anim/sequence/large/01-hero-lightpass/${index.toString().padStart(4, '0')}.jpg`
);

const frameCount = 147;

canvas.height = 770;
canvas.width = 1158;
const img = new Image();
img.src = currentFrame(1);
img.onload = function(){
    context.drawImage(img, 0, 0);
}

const updateImage = index => {
    img.src = currentFrame(index);
    context.drawImage(img, 0, 0);
}

window.addEventListener('scroll', () =>{
    const scrollTop = html.scrollTop;
    const maxScrollTop = html.scrollHeight - window.innerHeight;
    const scrollFraction = scrollTop / maxScrollTop;
    const frameIndex = Math.min(frameCount - 1, Math.floor(scrollFraction * frameCount));
    requestAnimationFrame( () => updateImage(frameIndex + 1));
});
html{
    height: 100vh;
}

body{
    background: #000;
    height: 400vh;
}

canvas{
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    max-height: 100vh;
    max-width: 100vw;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <title>Image Scrolling Animation</title>
</head>
<body>

    <canvas class="airpods-scrolling"></canvas>

    <script src="main.js"></script>
    
</body>
</html>
英文:

I am trying to learn how to use canvas in order to create the effect of the Apple Airpods page. I've been following a tutorial which shows how to do the animation of the different images, making each frame correspond to scrolling. My question is, how would you add text inbetween the frames? For example between frame 50-100 a text should appear in the middle of the screen, and disappear after frame 100 has passed. My initial thought was an if-statement, that triggered it when the framecount was between the two values. It works, but it places the text at the top of the document. I cannot seem to find any information on how to render it through the canvas. I am very new to canvas, so I hope you will bear over with me!

The code in question:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const html = document.documentElement;
const canvas = document.querySelector(&#39;.airpods-scrolling&#39;);
const context = canvas.getContext(&#39;2d&#39;);

// index is the number we will be incrementing. index.toString = makes it from a number to a string, so it can be parsed. padStart = adds 4x0 om front of the number.
const currentFrame = index =&gt; (
`https://www.apple.com/105/media/us/airpods-pro/2019/1299e2f5_9206_4470_b28e_08307a42f19b/anim/sequence/large/01-hero-lightpass/${index.toString().padStart(4, &#39;0&#39;)}.jpg`
);

// Handling how many images / frames we have
const frameCount = 147;

// Canvas height and width, same as image
canvas.height = 770;
canvas.width = 1158;
// Generating a new image.
const img = new Image();
// To add to dom put inside ()
img.src = currentFrame(1);
img.onload = function(){
// Drawing image inside canvas - 0, 0 is X and Y coords
    context.drawImage(img, 0, 0);
}

// Function that updates the image
const updateImage = index =&gt; {
    // Passing index so it can update the image
    img.src = currentFrame(index);
    context.drawImage(img, 0, 0);
}

// Handling changes when scrolling. Everytime we scroll this function is triggering
window.addEventListener(&#39;scroll&#39;, () =&gt;{
    // Variable to get the scroll top value
    const scrollTop = html.scrollTop;
    // Adding maximum value a user can scroll to
    const maxScrollTop = html.scrollHeight - window.innerHeight;
    // Handling progress when scrolling
    const scrollFraction = scrollTop / maxScrollTop;
    // Handling frame counting
    const frameIndex = Math.min(frameCount - 1, Math.floor(scrollFraction * frameCount));
    // Rendering the images over and over - using the updateImage function from earlier to refresh the rendering of canvas
    requestAnimationFrame( () =&gt; updateImage(frameIndex + 1));
});

<!-- language: lang-css -->

html{
height: 100vh;
}

body{
background: #000;
height: 400vh;
}

canvas{
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
max-height: 100vh;
max-width: 100vw;
}

<!-- language: lang-html -->

&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&gt;
    &lt;title&gt;Image Scrolling Animation&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

    &lt;canvas class=&quot;airpods-scrolling&quot;&gt;&lt;/canvas&gt;

    &lt;script src=&quot;main.js&quot;&gt;&lt;/script&gt;
    
&lt;/body&gt;
&lt;/html&gt;

<!-- end snippet -->

答案1

得分: 1

我注意到你在两个地方都使用了 drawImage,不太确定你为什么这样做,所以我去掉了其中一个,并添加了 fillText 来渲染文本...

如果你需要了解更多关于 fillText 的信息,请访问这里:
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing_text

我正在渲染两个单词,但第二个在一个 if 语句后面,只有在满足条件 if (frameIndex > 5) 时才会被渲染,你可以根据需要更改条件。

以下是工作代码:

const html = document.documentElement;
const canvas = document.querySelector('.airpods-scrolling');
canvas.height = 770;
canvas.width = 1158;
const context = canvas.getContext('2d');
context.shadowColor = "white";
context.shadowBlur = 4;

const currentFrame = index => (
  `https://www.apple.com/105/media/us/airpods-pro/2019/1299e2f5_9206_4470_b28e_08307a42f19b/anim/sequence/large/01-hero-lightpass/${index.toString().padStart(4, '0')}.jpg`
);

const frameCount = 147;
var frameIndex = 0

const img = new Image();
img.src = currentFrame(1);
img.onload = function() {
  context.drawImage(img, 0, 0);
  context.font = "178px serif";
  context.fillText("Hello", 90, 160);
  if (frameIndex > 5) {
    context.font = "220px serif";
    context.fillText("World", 99, 320);
  }
}

const updateImage = index => {
  img.src = currentFrame(index);
}

window.addEventListener('scroll', () => {
  const scrollFraction = html.scrollTop / (html.scrollHeight - window.innerHeight);
  frameIndex = Math.min(frameCount - 1, Math.floor(scrollFraction * frameCount));
  requestAnimationFrame(() => updateImage(frameIndex + 1));
});
html {
  height: 100vh;
}

body {
  background: #000;
  height: 400vh;
}

canvas {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  max-height: 100vh;
  max-width: 100vw;
}
<canvas class="airpods-scrolling"></canvas>

希望这对你有所帮助。

英文:

I noticed you had two places with drawImage, not quite sure why you are doing that, so I removed one and added the fillText to render the text...

If you need read more about fillText here:
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing_text

I'm rendering two words, but the second is behind an if-statement to only render
if (frameIndex &gt; 5) you can change that to anything you need.

See working code below

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const html = document.documentElement;
const canvas = document.querySelector(&#39;.airpods-scrolling&#39;);
canvas.height = 770;
canvas.width = 1158;
const context = canvas.getContext(&#39;2d&#39;);
context.shadowColor = &quot;white&quot;;
context.shadowBlur = 4;

const currentFrame = index =&gt; (
  `https://www.apple.com/105/media/us/airpods-pro/2019/1299e2f5_9206_4470_b28e_08307a42f19b/anim/sequence/large/01-hero-lightpass/${index.toString().padStart(4, &#39;0&#39;)}.jpg`
);

const frameCount = 147;
var frameIndex = 0

const img = new Image();
img.src = currentFrame(1);
img.onload = function() {
  context.drawImage(img, 0, 0);
  context.font = &quot;178px serif&quot;;
  context.fillText(&quot;Hello&quot;, 90, 160);
  if (frameIndex &gt; 5) {
    context.font = &quot;220px serif&quot;;
    context.fillText(&quot;World&quot;, 99, 320);
  }
}

const updateImage = index =&gt; {
  img.src = currentFrame(index);
}

window.addEventListener(&#39;scroll&#39;, () =&gt; {
  const scrollFraction = html.scrollTop / (html.scrollHeight - window.innerHeight);
  frameIndex = Math.min(frameCount - 1, Math.floor(scrollFraction * frameCount));
  requestAnimationFrame(() =&gt; updateImage(frameIndex + 1));
});

<!-- language: lang-css -->

html {
  height: 100vh;
}

body {
  background: #000;
  height: 400vh;
}

canvas {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  max-height: 100vh;
  max-width: 100vw;
}

<!-- language: lang-html -->

&lt;canvas class=&quot;airpods-scrolling&quot;&gt;&lt;/canvas&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年7月7日 05:05:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76632524.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定