SVG - 动画问题

4

我有一些形状,使用两个按钮旋转它们,一个用于顺时针方向,另一个用于逆时针方向:

var svgNS = "http://www.w3.org/2000/svg";

function cwAnim(evt) {
  if (window.svgDocument == null)
    svgDoc = evt.target.ownerDocument;

  addRotateTransform('someShape', 1, -1, 180);
  addRotateTransform('shape1', 1, 1, 360);
  addRotateTransform('shape2', 1, 1, 360);
}

function acwAnim(evt) {
  if (window.svgDocument == null)
    svgDoc = evt.target.ownerDocument;

  addRotateTransform('someShape', 1, 1, 180);
  addRotateTransform('shape1', 1, -1, 360);
  addRotateTransform('shape2', 1, -1, 360);
}

function addRotateTransform(target_id, dur, dir, angle) {
  var my_element = svgDoc.getElementById(target_id);
  var a = svgDoc.createElementNS(svgNS, "animateTransform");

  var bb = my_element.getBBox();
  var cx = bb.x + bb.width / 2;
  var cy = bb.y + bb.height / 2;

  a.setAttributeNS(null, "attributeName", "transform");
  a.setAttributeNS(null, "attributeType", "XML");
  a.setAttributeNS(null, "type", "rotate");
  a.setAttributeNS(null, "dur", dur + "s");
  a.setAttributeNS(null, "repeatCount", "1");
  a.setAttributeNS(null, "fill", "freeze");
  a.setAttributeNS(null, "additive", "sum");
  a.setAttributeNS(null, "accumulate", "sum");
  a.setAttributeNS(null, "from", "0 " + cx + " " + cy);
  a.setAttributeNS(null, "to", angle * dir + " " + cx + " " + cy);

  my_element.appendChild(a);
  a.beginElement();
}
<svg width="600px" height="600px" viewBox="0 0 1000 1000">
  <circle stroke="#000000" stroke-miterlimit="10" cx="468.451" cy="474.385" r="350" />
  <g id="someShape">
    <circle fill="#FFFFFF" stroke="#000000" stroke-miterlimit="10" cx="468.451" cy="474.385" r="350" />
    <path id="shape1" fill="#DC5A00" stroke="#000000" stroke-miterlimit="10" d="M692.373,317.798C692.373,418.425,606.244,500,500,500
   c-106.245,0-192.374-81.575-192.374-182.202c0-100.629,86.128-182.204,192.374-182.204
   C606.244,135.595,692.373,217.169,692.373,317.798z M553.391,220.34c-39.316,0-71.188,31.87-71.188,71.187
   s31.871,71.187,71.188,71.187c39.314,0,71.186-31.87,71.186-71.187S592.705,220.34,553.391,220.34z" />
    <path id="shape2" fill="#3DFF63" stroke="#000000" stroke-miterlimit="10" d="M577.368,647.034c0,69.738-56.913,126.271-127.119,126.271
   c-70.206,0-127.119-56.533-127.119-126.271c0-69.737,56.913-126.271,127.119-126.271
   C520.455,520.764,577.368,577.297,577.368,647.034z M466.352,617.373c-21.998,0-39.831,17.453-39.831,38.983
   c0,21.529,17.833,38.982,39.831,38.982s39.831-17.453,39.831-38.982C506.182,634.826,488.349,617.373,466.352,617.373z" />
  </g>
  <g onclick="cwAnim(evt)">
    <rect x="89.762" y="815.369" stroke="#000000" stroke-miterlimit="10" width="217.865" height="134.426" />
    <text transform="matrix(1 0 0 1 127.4673 864.5491)" fill="#FFFFFF" font-family="'MyriadPro-Regular'" font-size="21">AntiClockwise</text>
  </g>
  <g onclick="acwAnim(evt)">
    <rect x="692.373" y="815.369" stroke="#000000" stroke-miterlimit="10" width="194.11" height="134.426" />
    <text transform="matrix(1 0 0 1 752.0576 869.467)" fill="#FFFFFF" font-family="'MyriadPro-Regular'" font-size="21">Clockwise</text>
  </g>
</svg>

你也可以在这个CodePen链接中查看:http://codepen.io/Daolagajao/pen/qdyBLo 当我单击一次时,形状的动画效果很好。问题是如果我快速连续点击按钮(双击、三连击等),轴心会发生变化,这显然不是期望的结果。
有没有解决这个问题的办法?比如当我点击下一个按钮时,之前正在进行的动画就停止并保持位置,然后新的动画开始。

抱歉,现在已经更新了代码片段。正在查看中。 - somethinghere
在我的电脑上,它跑的方向错误。这有点古怪。 - QuentinUK
@QuentinUK 是的,我的也是这样(甚至没有注意到)。但这只是将函数切换一下的问题。 - somethinghere
1个回答

3

通过添加一个busy变量,您可以表示当前正在执行动画,并且不应该执行任何其他动画。您可以对此进行更多操作,但它可以解决基本问题。

var svgNS = "http://www.w3.org/2000/svg";
var busy = false;

function animationDelegate(evt, direction){
    /* Check if we are busy before doing anything.*/
    /* If we are, stop executing this request, otherwise, set busy to true.*/
    if(busy) return; else busy = true;
    if(direction === 'cw') cwAnim(evt);
    else if(direction === 'ccw') acwAnim(evt);
    /* Your duration is 1 second, so 1000ms.*/
    /* Set a timeout that resets busy.*/
    setTimeout(function(){ busy = false}, 1000);
}

function cwAnim(evt){
  if ( window.svgDocument == null)
    svgDoc = evt.target.ownerDocument;

  addRotateTransform('someShape', 1, -1, 180);
  addRotateTransform('shape1', 1, 1, 360);
  addRotateTransform('shape2', 1, 1, 360);    
}

function acwAnim(evt){
  if ( window.svgDocument == null)
    svgDoc = evt.target.ownerDocument;

  addRotateTransform('someShape', 1, 1, 180);
  addRotateTransform('shape1', 1, -1, 360);
  addRotateTransform('shape2', 1, -1, 360);       
}

function addRotateTransform(target_id, dur, dir, angle){
  var my_element = svgDoc.getElementById(target_id);
  var a = svgDoc.createElementNS(svgNS, "animateTransform");

  var bb = my_element.getBBox();
  var cx = bb.x + bb.width/2;
  var cy = bb.y + bb.height/2;

  a.setAttributeNS(null, "attributeName", "transform");
  a.setAttributeNS(null, "attributeType", "XML");
  a.setAttributeNS(null, "type", "rotate");
  a.setAttributeNS(null, "dur", dur + "s");
  a.setAttributeNS(null, "repeatCount", "1");
  a.setAttributeNS(null, "fill", "freeze");
  a.setAttributeNS(null, "additive", "sum");
  a.setAttributeNS(null, "accumulate", "sum");
  a.setAttributeNS(null, "from", "0 "+cx+" "+cy);
  a.setAttributeNS(null, "to", angle*dir+" "+cx+" "+cy);

  my_element.appendChild(a);
  a.beginElement();
}
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="600px" height="600px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
  <circle stroke="#000000" stroke-miterlimit="10" cx="468.451" cy="474.385" r="350" />
  <g id="someShape">
    <circle fill="#FFFFFF" stroke="#000000" stroke-miterlimit="10" cx="468.451" cy="474.385" r="350" />
    <path id="shape1" fill="#DC5A00" stroke="#000000" stroke-miterlimit="10" d="M692.373,317.798C692.373,418.425,606.244,500,500,500
   c-106.245,0-192.374-81.575-192.374-182.202c0-100.629,86.128-182.204,192.374-182.204
   C606.244,135.595,692.373,217.169,692.373,317.798z M553.391,220.34c-39.316,0-71.188,31.87-71.188,71.187
   s31.871,71.187,71.188,71.187c39.314,0,71.186-31.87,71.186-71.187S592.705,220.34,553.391,220.34z" />
    <path id="shape2" fill="#3DFF63" stroke="#000000" stroke-miterlimit="10" d="M577.368,647.034c0,69.738-56.913,126.271-127.119,126.271
   c-70.206,0-127.119-56.533-127.119-126.271c0-69.737,56.913-126.271,127.119-126.271
   C520.455,520.764,577.368,577.297,577.368,647.034z M466.352,617.373c-21.998,0-39.831,17.453-39.831,38.983
   c0,21.529,17.833,38.982,39.831,38.982s39.831-17.453,39.831-38.982C506.182,634.826,488.349,617.373,466.352,617.373z" />
  </g>
  <g onclick="animationDelegate(evt, 'ccw')">
    <rect x="89.762" y="815.369" stroke="#000000" stroke-miterlimit="10" width="217.865" height="134.426" />
    <text transform="matrix(1 0 0 1 127.4673 864.5491)" fill="#FFFFFF" font-family="'MyriadPro-Regular'" font-size="21">AntiClockwise</text>
  </g>
  <g onclick="animationDelegate(evt, 'cw')">
    <rect x="692.373" y="815.369" stroke="#000000" stroke-miterlimit="10" width="194.11" height="134.426" />
    <text transform="matrix(1 0 0 1 752.0576 869.467)" fill="#FFFFFF" font-family="'MyriadPro-Regular'" font-size="21">Clockwise</text>
  </g>
</svg>


1
不是可行的解决方案。它会禁用其他旋转功能。 - user4447799
你可以随时将解决方案移动到特定的函数而不是主函数中。 - somethinghere
我尝试将它移动到点击函数中,但这会禁用第一个旋转后的所有内容。也许是我做错了什么,你能展示一下应该如何做吗? - user4447799
好的,让我再试着解释一下。我的意思是,当我点击CW/antiCW按钮时,我希望所有3个旋转函数都执行,但我想禁用/排队另一个点击事件。这样,在一个点击事件中执行的所有动画都可以正常运行,但不会被在动画执行期间调用的另一个点击事件干扰。我希望我能更清楚地表达我的问题。 - user4447799
哦,这很奇怪,Chrome 抛出了一个错误。让我看看。在 Safari 中它可以工作。 - somethinghere
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接