今天,我们将创建一个可以通过点击,点击或使用键盘来演奏的SVG动画鼓套件,也可以编程为单独播放!我们将使用GreenSock的 TweenMax动画库,jQuery和<audio>元素。
打开你选择的矢量编辑软件(我使用的是Adobe Illustrator,但有许多选择,如Affinity Designer, Sketch或Inkscape),并得到绘图!我发现有几张照片想要画在我的画板上,以供参考。保持风格平坦,相当简单,无论是在绘画还是动画方面,都会让生活变得更加轻松,而功能较弱的设备会感谢您减少渲染的内容。在这种风格中,鼓套件实际上是一组相当简单的(大部分)矩形对象。在绘制任何想要动画的SVG的同时,还有几件事值得记住:
“g元素是一个用于分组其他SVG元素的容器。应用于g元素的转换将在其所有子元素上执行,并且其任何属性都由其子元素继承。
对于我们来说,这个关键部分是“在所有子元素上执行应用于g元素的转换”,这在将SVG动画化时非常方便, 我们可以简单地将我们想要的动画元素进行分组,并将单个动画应用到该组,从而不用将动画应用到小鼓的每个单独组件。 命名良好的组织将在以后更轻松地操纵SVG!
如果您的绘图应用程序有这样的选项,请启用XML标识名称(在Illustrator首选项>单位>标识对象:> XML ID),这允许您编辑/查看id我们将使用的元素和组的实际属性瞄准他们。
我们需要将两个主要元素集合在一起:
我们希望能够触发我们的动画和声音基于他们各自的鼓被点击/点击,所以我们需要将点击/点击“目标”元素分组在一起。 例如,将整个小鼓,包括支架组合在一起,所以用户触摸的任何部分都会触发动画/声音。
将我们想要动画的元素组合在一起。例如,将小军鼓组合起来; 当小军鼓动画被触发时,我们只想要鼓动画,而不是立场。
“我发现绘制所有东西都很有用,然后在需要时显示部分。”
我们希望能够用键盘演奏鼓,所以某些指示哪些键触发鼓将是有用的。选择你想要“演奏”每个鼓的键,并添加一些指示到您的SVG。将它们组合在一起,以便我们稍后可以隐藏/显示。
将所有组保存为一个.svg文件,然后在文本编辑器中打开它。
我们可以把它直接放到我们的HTML文档中。不过,我建议首先优化Web的SVG。有足够的工具可以做到这一点,SVGOMG可能是最简单的使用之一。
我们提供音频元素ID,以便我们可以在需要播放时对其进行定位。
1 2 3 | < audio id = "Snare-Audio" > < source src = "mp3/Snare.mp3" type = "audio/mp3" > </ audio > |
通过添加属性,preload="auto"我们可以告诉浏览器“用户需要这个,确保它被下载”。这就是它在某些浏览器中的工作原理。其他浏览器(特别是移动设备上的浏览器)实际上忽略了这一点,这可能会导致一些奇怪的行为,但我们稍后会回到这一点。
1 2 3 | < audio id = "Snare-Audio" preload = "auto" > < source src = "mp3/Snare.mp3" type = "audio/mp3" > </ audio > |
在我们打鼓之前,我们还有很多事情要做,但每个鼓部分可以分成三个步骤:
音频、动画、触发这些用户交互。
首先将我们需要的DOM元素作为变量进行存储。例如,对于小鼓,我们想要小鼓音频和小鼓,两个位我们想要动画和部分将触发动画和音频。
播放我们的音频实际上非常简单:我们只是.play()在我们想播放的音频元素上使用该方法。
1 2 | var snareAudio = $( '#Snare-Audio' ); snareAudio.get(0).play(); |
就是这样!嗯, 几乎..。这很有用, 但是如果我们在音频已经播放时再次调用该方法, 则不会发生任何事情。我们希望在每次触发鼓时从音频文件的开头触发声音。因此, 我们需要设置的音频开始位置是每次触发。
1 2 3 4 | var snareAudio = $( '#Snare-Audio' ); var snareAudioEl = snareAudio.get(0); snareAudioEl.currentTime = 0; snareAudioEl.play(); |
对于那些不熟悉的人来说,TweenMax是一个JavaScript库,可以随时间处理任何对象(或对象数组)的一个或多个属性的“补间”。我不打算深入每一个动画的解剖,但每个可以分解成几个简单的步骤:
创建一个新的时间轴Tween属性补 (或大量属性)
我们只是试图模拟一些接近于我们“期望”鼓被击中时移动的东西。有时为了达到预期的效果,夸大运动量是值得的。这在一定程度上是反复试验的,但幸运的是,GreenSock在行动中有很多很好的例子,你可以检查灵感。同样,像Chris Gannon这样的人是看GreenSock能做什么的好方法。
最后,easing是GreenSock提供给你的动画最有用的工具之一。GreenSock有一个很容易的可视化,它可以帮助你决定什么是适合你的动画。
1 2 3 4 5 6 7 8 9 10 11 12 | snareDrum = $( '#Snare-Drum' ); // Create a new timeline, that's paused by default var snaretl = new TimelineMax({ paused: true }); // The animation tweens snaretl.to(snareDrum, 0.1, {scaleX: 1.04, transformOrigin: "50% 50%" , ease: Expo.easeOut}) .to(snareDrum, 0.1, {scaleY: 0.9, transformOrigin: "50% 100%" , ease: Expo.easeOut}, '0 ') // The last tween, returns the element to it' s original properties .to(snareDrum, 0.4, {scale: 1, transformOrigin: "50% 100%" , ease: Elastic.easeOut}); |
我们有我们的音频和我们的动画准备。现在我们只需要把它放在一起并在用户交互中触发它。我们将音频和动画方法封装在一个函数中:
1 2 3 4 5 6 7 | function snare(){ snaretl.restart(); snaretl.play(); var snareAudioEl = snareAudio.get(0); snareAudioEl.currentTime = 0; snareAudioEl.play(); } |
然后,在点击/触摸事件上调用该函数:
1 2 3 4 5 6 7 8 9 10 11 | var clickTouchSnareDone = false ; snareDrumAll.on( "touchstart click" , function () { if (!clickTouchSnareDone) { clickTouchSnareDone = true ; setTimeout( function () { clickTouchSnareDone = false ; }, 100); snare(); return false ; } }); |
当用户点击或触摸鼓时,会触发动画和音频。下一步是连接键盘。
1 2 3 4 5 6 7 | document.onkeydown = function (e) { switch (e.keyCode) { case 72: snare(); break ; } }; |
使用键盘时,我们甚至可以为键盘指定动画:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | function animateKey(key) { keytl = new TimelineMax({ paused: true }); keytl.to(key, 0.1, {scale: 1.1, transformOrigin: "50% 50%" , ease: Expo.easeOut}) .to(key, 0.4, {scale: 1, transformOrigin: "50% 50%" , ease: Elastic.easeOut}); keytl.restart(); keytl.play(); } document.onkeydown = function (e) { // This string will have to match the id of your key guides thisKeyID = 'Key-' + e.keyCode; thisKey = $( '#' + thisKeyID); switch (e.keyCode) { case 72: snare(); animateKey(thisKey); break ; } }; |
冲洗并重复这个过程中的每个鼓在我们的套件。
现在我们已经有了一个功能齐全的鼓组套件,我们可以用鼠标,键盘或触摸来玩。但是,我们不要停留在这里。
我们有可玩的鼓,但可以使我们的鼓可编程。我们要构建一个可以编程来播放循环的音序器。这可能相当复杂,但同样可以分解成简单的步骤:
创建一个表示鼓和时间 (或节拍) 的 "矩阵"
循环通过列或节拍
如果鼓是活跃的在当前敲打, 演奏鼓
幸运的是,我可以确切地告诉你我们的矩阵是什么!这是一个简单的网格,其中:
行将代表我们的鼓列将代表节拍
我们需要能够选择在我们的音序器的每个节拍中是否播放鼓。<input>具有该type="checkbox"属性的< 元素是完全适合这个,但是,这不是那么容易的风格,但有一个黑客。
我们将为每个鼓创建一个行,并为每个节拍创建一个列。在这个演示中,我们将使用8节拍。我们将添加一个data-target-drum属性(这可以被称为任何东西)与我们之前创建的鼓功能的名称。我们可以使用该属性来帮助我们确定要调用哪个相应的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 | <!-- A "row" of our sequencer, we'll need one of these for each drum --> < div class = "row" data-target-drum = "snare" > <!-- This image indicates which drum the row controls --> < img src = "img/snare.png" > < label >< input type = "checkbox" >< div ></ div ></ label > < label >< input type = "checkbox" >< div ></ div ></ label > < label >< input type = "checkbox" >< div ></ div ></ label > < label >< input type = "checkbox" >< div ></ div ></ label > < label >< input type = "checkbox" >< div ></ div ></ label > < label >< input type = "checkbox" >< div ></ div ></ label > < label >< input type = "checkbox" >< div ></ div ></ label > < label >< input type = "checkbox" >< div ></ div ></ label > </ div > |
而且一次循环“行”和“拍”的功能如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | rows = $( '.row' ); rowLength = rows.first().children().length; labels = $( 'label' ); // Beat starts at 1 because 0 is the img for each row beat = 1; // Sequencer function sequencer () { labels.removeClass( 'active' ); // Do this function for each .row $(rows).each( function () { // Select the child element at the "beat" index current = $( this ).children().eq(beat); current.addClass( 'active' ); // If the current input is checked do some stuff! if (current.find( 'input' ).is( ":checked" )) { targetDrum = (current.parent().attr( 'data-target-drum' )); // If there a function that shares the same name as the data attribute, do it! fn = window[targetDrum]; if ( typeof fn === "function" ) { fn(); } } }); // If we get to the last child, start over if ( beat < (rowLength - 1) ) { ++beat; } else { beat = 1; } } |
时机就是一切
我们有一个功能来演奏当前节拍的鼓声。但我们需要循环这些节拍。我们可以用这个.setInterval()方法来做到这一点。它基本上定义了函数应该执行的频率(以毫秒为单位)。所以我们可以用它来启动音序器并设置其速度。在音乐方面,节拍(或节奏)的频率通常被称为bpm或每分钟节拍。所以bpm可以简单地定义为一分钟内的毫秒数除以bpm。我们将bpm设置为合理的默认值150.然后我们设置点击播放按钮的时间间隔。
1 2 3 4 5 6 7 | sequencerOn = false ; // Start Sequencer $( '#sequencer-active-btn' ).click( function () { intervalId = window.setInterval(sequencer, interval); sequencerOn = true ; }); |
这很好,但是当我们需要停止音序器时呢?我们可以通过将.setInterval()方法返回的ID传递给方法来停止顺序器.clearInterval():
1 2 3 4 5 6 7 8 9 10 11 12 | sequencerOn = false ; // Start/Stop Sequencer $( '#sequencer-active-btn' ).click( function () { if (sequencerOn === false ) { intervalId = window.setInterval(sequencer, interval); sequencerOn = true ; } else { window.clearInterval(intervalId); sequencerOn = false ; } }); |
如果我们可以改变我们的拍子的bpm以获得更快或更慢的循环,那将会更加酷:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | bpm = 150; interval = 60000 / bpm; // Set tempo function setTempo() { window.clearInterval(intervalId); intervalId = window.setInterval(sequencer, interval); } // Increase tempo $( '#bpm-increase-btn' ).click( function () { if ( bpm < 300 ) { bpm = parseInt($( '#bpm-indicator' ).val()); bpm += 10; interval = 60000 / bpm; $( '#bpm-indicator' ).val(bpm); if (sequencerOn === true ) { setTempo(); } } }); //Decrease tempo $( '#bpm-decrease-btn' ).click( function () { if ( bpm > 100 ) { bpm = parseInt($( '#bpm-indicator' ).val()); bpm -= 10; interval = 60000 / bpm; $( '#bpm-indicator' ).val(bpm); if (sequencerOn === true ) { setTempo(); } } }); |
许多移动浏览器不仅忽略,preload="auto"而且实际上只会在用户触摸事件中加载音频。这基本上意味着我们的音序器不会触发任何音频,直到它已经被用户触发。所以我们需要在第一次用户交互中加载音频。这是一个黑客,但它意味着音序器将在移动设备上工作。
1 2 3 4 5 6 7 | // Load audio on iOS devices on the first user interaction $( '#sequencer-visible-btn' ).one( 'click' , function () { $( "audio" ).each( function (i) { this .play(); this .pause(); }); }); |
就是这样!我们制作了一个我们可以玩的鼓乐器,我们可以编程自己玩。我希望这个教程能够激发你创建自己的交互式动画SVG。使用相同的技巧,你可以建立其他乐器,或任何东西!如果你这样做,请让我知道,我很想看看你创造了什么!
特别申明:
本站所有资源都是由网友投稿发布,或转载各大下载站,请自行检测软件的完整性!
本站所有资源仅供学习与参考,请勿用于商业用途,否则产生的一切后果将由您自己承担!
如有侵权请联系我们删除下架,联系方式:lei1294551502@163.com