svg路径动画_生存僵尸启示录:动态SVG和路径动画

svg路径动画

尽管SVG已经存在了一段时间,但它作为HTML5的一部分的采用赋予了它新的生命。 为了庆祝这一事实,本系列演练通过构建几乎完全由SVG和JavaScript创建的Zombie Apocalypse Survival Predictor(僵尸启示录生存预测器),探索了如果死者也有新生命将会发生的情况。

在本系列的第3部分中,处于该预测变量中心的尖叫着的人四面被危险包围。 JavaScript首次用于操纵Core DOM和SVG DOM,添加了数十个新的僵尸,然后使用“ transform”属性对其进行翻转。

在本系列的最后一部分中,JavaScript将再次被使用,这一次以购物商场和繁琐的形式将人类寄予了希望。 够了吗? 敬请期待,直到最后,当JavaScript还用于计算人类的生存几率,然后通过嗅探浏览器的实际SVG功能并采取相应行动来设置预测指标。

注意:本演练以本系列第3部分的完整代码为基础,可以在http://justinwhitney.com/zombies/zombies_part3.htm的源代码中找到该代码。

添加更多的SVG元素

本系列的第3部分展示了如何为“控制面板”画布的六个增量/减量控件中的一个进行动画处理:“更多僵尸”控件。 那根本不会做。 人口控制也需要更少的僵尸。 但是在执行此操作之前,需要添加其他SVG图像。 人类需要一些保护。

从购物中心开始。 为简单起见,假设该城市最多有四个购物中心,这些购物中心将放置在四个角落。 由于需要跟踪购物中心的数量,因此在<script>部分顶部为购物中心添加一个全局数组:

<script>

var malls = new Array();

…

newMall代码将根据阵列中商场的数量为新的SVG元素设置x,y坐标,并针对商场图像本身的100×100尺寸进行调整。 其余代码与newZombie代码基本相同,除了新的SVG元素将被推送到数组以进行跟踪之外:

function newMall(){

  if (malls.length < 4) {

    var svg = document.createElementNS("http://www.w3.org/2000/svg","image");

    svg.setAttributeNS('http://www.w3.org/1999/xlink','href','building.svg');

    svg.setAttribute('width','471');

    svg.setAttribute('height','303');

    var scale = .21;

    var x = 0;

    var y = 0;

    var thisMall = malls.length;

    if (thisMall == 0 || thisMall == 2) {

      x = 20;

    } else {

      x = 480;

    }

    if (thisMall == 0 || thisMall == 1) {

      y = 10;

    } else {

      y = 300;

    }

    malls.push(svg);

    svg.setAttribute('transform','translate(' + (x) + ', ' + (y) + ') scale(' + scale + ', ' + scale + ')');

    document.getElementById('cityBox').appendChild(svg);

  }

}

最后,将鼠标事件添加到商城增量按钮,该按钮是ID为“ mallMore”的<path>元素:

<path id="mallMore" d="M 300 150 l -50 -25 l 0 50 l 50 -25" stroke="black" stroke-width="1" fill="red" onmouseup="newMall();" />

图1显示了购物中心最大化(​​没有僵尸)的结果。

图1.动态添加的SVG Mall <image>元素

图1.动态添加的SVG Mall <image>元素

僵尸乡镇是最坏的情况(尤其是受痛苦折磨的僵尸乡镇家庭),健康的乡镇居民,用弓和箭武装,可以帮助他们在步行或奔跑死亡中幸免于难。 动态地将它们添加到城市就像添加僵尸或购物中心一样。 但是在这种情况下,乡巴佬将被放置在安全区内。 要获得额外的奖励,它们将被翻转成面向外。

function newRedneck(){

  var svg = document.createElementNS("http://www.w3.org/2000/svg","image");

  svg.setAttributeNS('http://www.w3.org/1999/xlink','href','redneck.svg');

  svg.setAttribute('width','375');

  svg.setAttribute('height','950');

  scale = .07;

  var cityWidth = 600;

  var cityHeight = 400;

  var safezoneWidth = 200;

  var safezoneHeight = 200;

  var safezoneX = Math.round((cityWidth - safezoneWidth) / 2, 0);

  var safezoneY = Math.round((cityHeight - safezoneHeight) / 2, 0);

  var x = Math.floor(Math.random()*(safezoneWidth)) + safezoneX;

  var y = Math.floor(Math.random()*(safezoneHeight-100)) + safezoneY;
&nbsp;
  flip = (x > (cityWidth / 2)) ? 1 : -1; //flip rednecks left of center

  svg.setAttribute('transform','translate(' + (x) + ', ' + (y) + ') scale(' + (flip * scale) + ', ' + scale + ')');

  document.getElementById('cityBox').appendChild(svg);

}

将对该函数的调用添加到ID为“ redneckMore”的<path>元素中:

<path id="redneckMore" d="M 300 250 l -50 -25 l 0 50 l 50 -25" stroke="black" stroke-width="1" fill="red" onmouseup="newRedneck();" />

快速测试应该可以使尖叫的人安全地躺在一排排的乡巴佬中,如图2所示。

图2.动态添加的僵尸防御团队

图2.动态添加的僵尸防御团队

在所有这三个元素都在起作用的情况下,这座城市(图3)现在已经变得栩栩如生。

图3.对未来的展望,由JavaScript和SVG提供

完成控制面板

到目前为止,一切都很好。 但是要完成控制面板,需要完成三件事:

  • 减量按钮应启用
  • 文字应更新
  • 参数应该有上限和下限

免费学习PHP!

全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。

原价$ 11.95 您的完全免费

一次完成所有三个目标的最佳方法是添加第四个函数来处理所有按钮响应以及对这三个创建函数的调用。 该脚本将称为tickSVG。

在控制SVG种群方面,newMall例程是朝正确方向迈出的一步,因此可以将其用作模型。 首先,还为僵尸和乡下人添加全局数组:

<script>

  var zombies = new Array();

  var malls = new Array();

  var rednecks = new Array();

…

接下来,不是直接将元素添加到DOM,而是每个创建函数都需要返回新的SVG元素。 因此,对于这三个功能中的每一个,都以:

//document.getElementById('cityBox').appendChild(svg);

return svg;

另外,在newMall中,删除以下行:

malls.push(svg);

tickSVG函数本身将根据按钮传递的参数来管理SVG <image>填充。 首先,该函数用新的总数更新相关的<text>元素。 其次,基于最大和最小限制以及当前数组大小,tickSVG要么创建新的<image>元素,要么从数组堆栈中获取顶部元素,具体取决于按下哪个按钮。 最后,它要么像原来在newMall例程中所做的那样,将新的<image>元素推到数组上并将其添加到DOM中,要么将其弹出数组并从DOM中删除(请注意removeChild的用法)方法)。

function tickSVG(textName, increment, min, max) {

  var textElement = document.getElementById(textName);

  var currentValue = parseInt(textElement.textContent);

  currentValue += increment;

  if ( (currentValue <= max) && (currentValue >= min) ) {

    textElement.textContent = currentValue;

    isMore = (increment == Math.abs(increment));

    switch (textName) {

      case 'zombieText':

        var svgArray = zombies;

        var newSVG = (isMore ? newZombie() : svgArray[svgArray.length - 1]);

        break;

      case 'redneckText':

        var svgArray = rednecks;

        var newSVG = (isMore ? newRedneck() : svgArray[svgArray.length - 1]);

        break;

      case 'mallText':

        var svgArray = malls;

        var newSVG = (isMore ? newMall() : svgArray[svgArray.length - 1]);

        break;

    }

    if (isMore) {

      svgArray.push(newSVG);

      document.getElementById('cityBox').appendChild(newSVG);

    } else {

      document.getElementById('cityBox').removeChild(newSVG);

      svgArray.pop(svgArray.length - 1);

    }

  }

}

最后,所有按钮都需要新的onmouseup调用。 找到以下每个路径,并替换现有的onmouseup调用或添加新的。 对tickSVG的这些调用包括对在较早步骤中创建的<text>元素的引用,以及一些任意的max和min值(购物中心除外),这些购物中心设计为最多四个。

<path id="zombieLess" d="M 50 50 l 50 -25 l 0 50 l -50 -25" stroke="black" stroke-width="1" fill="red" onmouseup="tickSVG('zombieText',-100,0,3000);" />

<path id="zombieMore" d="M 300 50 l -50 -25 l 0 50 l 50 -25" stroke="black" stroke-width="1" fill="red" onmouseup="tickSVG('zombieText',100,0,3000);" />

<path id="mallLess" d="M 50 150 l 50 -25 l 0 50 l -50 -25" stroke="black" stroke-width="1" fill="red" onmouseup="tickSVG('mallText',-1,0,4);" />

<path id="mallMore" d="M 300 150 l -50 -25 l 0 50 l 50 -25" stroke="black" stroke-width="1" fill="red" onmouseup="tickSVG('mallText',1,0,4);" />

<path id="redneckLess" d="M 50 250 l 50 -25 l 0 50 l -50 -25" stroke="black" stroke-width="1" fill="red" onmouseup="tickSVG('redneckText',-1,0,10);" />

<path id="redneckMore" d="M 300 250 l -50 -25 l 0 50 l 50 -25" stroke="black" stroke-width="1" fill="red" onmouseup="tickSVG('redneckText',1,0,10);" />

完整修订的代码在本演练的末尾链接。 如果工作正常,页面应该类似于图4。

图4.完全实现的控制面板,又称启示录

图4.完全实现的控制面板,又称启示录

赔率是多少?

僵尸启示录生存预测器需要再完成一件。 赔率计算器需要移动。 至少,它需要一些DOM操作JavaScript来更新顶部和箭头位置的0%。 但是对于兼容的浏览器,JavaScript可以使箭头沿着动态生成的路径移动,从而可以向本系列第2部分介绍的一种动画技术中添加一些特殊的调味料。

但是首先,要进行一些计算。 在<script>部分的顶部添加一个名为currentOdds的新全局变量,并将其设置为0:

<script>

  var zombies = new Array();

  var malls = new Array();

  var rednecks = new Array();

  var currentOdds = 0;

…

接下来,创建一个名为calcOdds的新函数。 在使用严格的方法进行详尽的研究之后,精心设计了以下公式来预测一个人在僵尸启示录中的生存情况:

function calcOdds() {

  var zombieCount = parseInt(document.getElementById('zombieText').textContent);

  if (zombieCount == 0) {

    currentOdds = 100;

  } else {

    var redneckCount = parseInt(document.getElementById('redneckText').textContent);

    var mallCount = parseInt(document.getElementById('mallText').textContent);

    var speed = document.getElementById('speedText').textContent;

    var threat = Math.round((zombieCount * (speed == 'Slow' ? 2 : 18)) / 180);

    var protection = Math.round(((mallCount * 10) + (redneckCount * 5)) / 60 * 100);

    currentOdds = Math.round((100 + protection - threat) / 2);

  }

  if (currentOdds > 100) currentOdds = 100;

  if (currentOdds < 0) currentOdds = 0;

}

请注意,与本演练开始时的<text>元素一样,可以通过访问其textContent属性来访问该元素的文本值。 除此之外,DOM看起来与HTML相同。 要测试计算,请找到ID为“ oddsButton”的组(<g>)元素。 如第1部分所述,按钮由两个不同的元素组成,即<rect>和<text>元素。 幸运的是,通过将它们分组,parent <g>元素允许将样式和鼠标事件与整个按钮相关联。 现在,暂时添加一个onmouseup事件以测试calcOdds:

<g id="oddsButton" style="cursor: pointer;" onmouseup="calcOdds(); alert(currentOdds);">

如果这行得通,那就是下一步了:移动指针。 创建一个名为movePointer的新函数:

function movePointer() {

  calcOdds();

  document.getElementById('oddsText').textContent = currentOdds + '%';

  var newY = -2 * currentOdds; //relative Y coordinate

  newY += 300; //actual Y coordinate

  document.getElementById('oddsPointer').setAttribute('points',

    "150," + newY + " 100," + (newY - 25) + " 100," + (newY + 25));

}

是的,newY的计算可以一步完成。 它被拆分是有原因的,很快就会揭晓。 值得注意的是最后一行,即setAttribute函数。 请记住,oddsPointer是作为<polygon>元素创建的,它通过使用绝对坐标定义“点”属性来工作。 与大多数其他属性一样,可以通过DOM来获取点,方法是:获取元素并使用setAttribute,然后指定哪个属性(“点”)和新值。 在这种情况下,新值是由三对坐标组成的文本字符串。 在此示例中,指针被硬编码为50×50空间中的右指向三角形。 其中心的Y坐标范围可以从仪表底部的300到顶部的100,分别对应于0到100的几率。 在此处分解的公式“ newY = 300 –(2 * currentOdds)”应将三角形的右尖精确地沿着该系列的第2部分中创建的标记所标记的刻度放置。

要观看它的运行情况,请使用对新函数的调用来替换oddsButton onmouseup事件:

<g id="oddsButton" style="cursor: pointer;" onmouseup="movePointer();">

在城市中填充一些僵尸,大型购物中心和乡巴佬,甚至可以切换到快速僵尸,然后单击“计算赔率”。 指针应该跳到对末日启示下一个人生存的极其准确的预测,如图5所示。

图5.成品:挽救生命的工具

图5.成品:挽救生命的工具

额外功能:动态路径动画

因为本演练的重点是JavaScript和DOM,所以这是向指针移动添加一些动画的另一个好技巧。 如第2部分中所述,可以通过在SVG元素中添加<animateMotion>元素,然后引用路径来对SVG进行动画处理(在兼容的浏览器中)。

更进一步,JavaScript可以动态更改该路径的坐标,从而可以随时随地移动屏幕上的任何元素。

要使单词生效,请找到oddsPointer多边形。 需要进行两项更改。 首先,定义一个ID为“ oddsPath”的简单路径。 然后在<animateMotion>元素内引用该路径,该元素本身嵌套在oddsPointer中。 请注意,<polygon>元素从自动关闭变为冗长,因此请务必仔细检查语法。

<g id="oddsMeter" stroke="#000000" stroke-width="2">

  <path d="M100 100 h75 m-75 100 h75 m-75 100 h75" stroke-width="3" />

  <path d="M100 150 h50 m-50 100 h50" />

  <path id="oddsPath" d="M 0 0 L 0 -200" />

  <polygon id="oddsPointer" points="150,300 100,275 100,325" fill="#FF0000" stroke-width="1">

    <animateMotion dur="2s" begin="oddsButton.click">

      <mpath xlink:href="#oddsPath" />

    </animateMotion>

  </polygon>

  <rect x="90" y="75" rx="15" ry="10" width="20" height="250" fill="#0000FF" />

</g>

此处的陷阱与<path>元素一起使用。 请记住,动画路径并不定义实际坐标,而是动画的相对运动。 如果要在屏幕上绘制此<path>,它将从画布的左上角开始并一直向上。 但是,它告诉指针要做的是从其当前位置(M 0 0)开始,然后从该位置开始向上200px(L 0 -200)。

请注意,如在“ begin”属性中所设置的,动画被设置为在单击oddsButton时开始。 但是,如果要立即单击该按钮,则指针将跳至其正确位置,然后向上浮动。 与以前的动画示例不同,这里需要区分能够识别和不识别SVG动画的浏览器。 通常,最好使用document.implementation.hasFeature来检查浏览器中的功能实现。 在这种情况下,要查找的功能是SVG 1.1规范中的“动画”。 添加一个名为supportsAnimation()的函数:

function supportsAnimation() {

  return document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Animation", "1.1");

}

这是可以在http://www.w3.org/TR/SVG11/feature中找到的几种可用功能字符串之一。

接下来,再添加一个全局变量,该全局变量将跟踪路径的“ L”值,以使指针始终从先前中断的位置开始,而不是重置为其原始位置。

<script>

  var zombies = new Array();

  var malls = new Array();

  var rednecks = new Array();

  var currentOdds = 0;

  var previousL = 0;

鉴于先前对动画路径如何工作的描述,这可能会有些混乱。 但是请记住,JavaScript将更改<path>的属性,而不是<polygon>的属性。 移动也不会更改<polygon>的points属性,因此使用此方法,这些点将保持不变。 因此,如果<path>始终从M 0 0开始,则<polygon>始终会在移动之前返回到该坐标,从而在动画前造成难看的跳转。 因此,每次都需要更改路径的“ M”值,以使运动保持相对状态。

返回到movePointer函数并添加嗅探器。 现在,混乱的“ newY”的奥秘变得清晰了。 根据浏览器的功能,将在动画开始前及时更改动画路径的“ d”属性,或设置多边形的points属性:

function movePointer() {

  calcOdds();

  document.getElementById('oddsText').textContent = currentOdds + '%';

  var newY = -2 * currentOdds; //relative Y coordinate

  if (supportsAnimation()) {

    document.getElementById('oddsPath').setAttribute('d','M 0 ' + previousL + ' L 0 ' + newY);

      previousL = newY;

  } else {

    newY += 300; //actual Y coordinate

    document.getElementById('oddsPointer').setAttribute('points',

     "150," + newY + " 100," + (newY - 25) + " 100," + (newY + 25));

  }

}

这样,这个僵尸启示录生存预测器就完成了! 立即在http://justinwhitney.com/zombies/zombies_part4.htm上尝试一下,或查看页面的源代码以获取本演练的最终版本。 可在http://justinwhitney.com/zombies/zombiesAssets.zip中找到此页面上使用的所有资产(由http://openclipart.org提供 )。

结语

虽然幸存的僵尸启示的机会可能会有所不同,但被人抓住的机会却很小。 但是正如CDC所知( http://www.cdc.gov/phpr/zombies.htm ),准备僵尸的公司也为许多其他事情做好了准备。 我希望这一系列演练可以说明如何将SVG用于视觉动态,可扩展的Web应用程序。

此处学习的技能可以用于许多其他应用程序。 就像为小行星做准备一样。

因为小行星的启示肯定会发生。

本文是Internet Explorer团队HTML5技术系列的一部分。 通过三个月的免费BrowserStack跨浏览器测试@ http://modern.IE来尝试本文中的概念

翻译自: https://www.sitepoint.com/surviving-the-zombie-apocalypse-dynamic-svg-and-path-animation/

svg路径动画

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值