【问题标题】:How to use clip-path in an animation?如何在动画中使用剪辑路径?
【发布时间】:2015-02-22 02:07:45
【问题描述】:

我已经阅读了很多帖子,并且一直在尝试为剪辑路径设置动画。在这一点上,我只能让它在 Firefox 中显示剪辑路径,并且它总是将路径固定到 0,0。

这是一个示例代码 -> http://jsfiddle.net/justintense/4torLok9/1/

我使用简单的内联 SVG 作为路径:

    <clipPath id="clipping">

        <polygon fill="#FFFFFF" points="40,35 40,15 20,35   "/>
        <polygon fill="#FFFFFF" points="0,35 20,35 0,15     "/>

        <circle id="white_overlay_9_" fill="#FFFFFF" cx="20" cy="18.77" r="7.393"/>
    </clipPath>

我不确定我尝试做的事情是否可能,所以我只是在寻找指针,这样我就可以得到这一首曲目。

编辑:

我正在尝试重新创建类似于此站点的行为--------> http://uppymama.com/

【问题讨论】:

  • 你想要实现什么样的动画?
  • 基本从左到右滑动。如果您查看 .full > div > div,您可以看到它位于左侧:50%。希望通过改变左边它也会移动剪辑路径。但我不认为它是这样工作的。
  • 附言。我试图重新创建指针(导航底部)-> uppymama.com

标签: css animation svg clip


【解决方案1】:

定义clipPath:

clipPath 中不需要三个元素,可以将其简化为单个 path 元素。

<path d="M0,0 L40,0 L20,15z M20,5 m-5,0 a5,5 0 1,0 10,0 a5,5 0 1,0 -10,0z" />

clipPath 应用于div

为了应用clip-path,如果你想要maximum browser support,你可以通过svgforeignObject元素将div导入svg元素。然后,将clip-path 应用到foreignObject

这里是 browser support,如果您通过 CSS 应用 clip-path


动画clipPath

现在,为了在菜单项的中间对齐指针,您需要 JavaScript 进行一些计算并对 clipPathtransform 属性进行动画处理。

  1. 当页面加载时,计算从左窗口角到第一个菜单项的距离,并将clip-path 移动到该坐标。

  2. 当窗口调整大小时,再次计算距离并移动指针。

  3. 单击菜单项时,计算距离并使用setTimeout()同步代码为指针设置动画,直到它到达正确的位置。

同步代码意味着一次执行一个操作,并且在一个操作结束之前,代码执行被阻止进入下一个操作。


site 的精确复制品:

正如您在该网站上看到的那样,指针未居中。

我的解决方案将始终根据菜单项的宽度将指针居中。

CodePen上的演示

var items = document.getElementsByClassName('menu-item');
var clipPath = document.getElementById('clip-path');
var lastActive = items[0];
for (i = 0; i < items.length; i++) {
  items[i].addEventListener('click', function() {
    var x = this.getBoundingClientRect().left + (this.offsetWidth / 2) - 20;
    animStart(x);
    lastActive = this;
  })
}

function animStart(end) {
  for (start = 0; start <= end; start += 0.1) {
    anim(start);
  }
}

function anim(start) {
  setTimeout(function() {
    clipPath.setAttribute('transform', 'translate(' + start + ', 0)');
  }, 1 * start);
}

function align() {
  var x = lastActive.getBoundingClientRect().left + (lastActive.offsetWidth / 2) - 20;
  animStart(x);
}

function resize() {
  var x = lastActive.getBoundingClientRect().left + (lastActive.offsetWidth / 2) - 20;
  clipPath.setAttribute('transform', 'translate(' + x + ', 0)');
}
window.onresize = resize;
window.onload = align;
body {
  background: #222222;
  margin: 0;
}
.nav-container {
  top: 20px;
  position: relative;
  width: 100%;
  height: 50px;
  background: repeating-linear-gradient(90deg, palegoldenrod 5px, palegreen 10px, palegreen 15px, paleturquoise 15px, paleturquoise 20px, plum 20px, plum 25px);
}
.nav {
  width: 100%;
  height: 50px;
  margin: 0 auto;
  text-align: center;
}
.menu-item {
  display: inline-block;
  width: 70px;
  padding: 17px 20px;
  color: #222222;
  font-size: 14px;
}
.menu-item:hover {
  color: seagreen;
  cursor: pointer;
}
#bottom {
  width: 100%;
  height: 35px;
  background: repeating-linear-gradient(90deg, palegoldenrod 5px, palegreen 10px, palegreen 15px, paleturquoise 15px, paleturquoise 20px, plum 20px, plum 25px);
}
#clip-path {
  transition: 0.5s transform;
}
<body>
  <div class="nav-container">
    <div class="nav">
      <div id="menu-item-1" class="menu-item">Home</div>
      <div id="menu-item-2" class="menu-item">About</div>
      <div id="menu-item-3" class="menu-item">Services</div>
      <div id="menu-item-4" class="menu-item">Locations</div>
      <div id="menu-item-5" class="menu-item">Contact Us</div>
    </div>
    <svg style="position: relative; top: -1px;" class="svg-defs" height="35" width="100%">
      <defs>
        <clipPath id="clipping">
          <path id="clip-path" transform="translate(0,0)" d="M0,0 L40,0 L20,15z M20,6 m-5,0 a5,5 0 1,0 10,0 a5,5 0 1,0 -10,0z" />
        </clipPath>
      </defs>
      <foreignObject x="0" y="0" clip-path="url(#clipping)" height="35" width="100%">
        <div id="bottom"></div>
      </foreignObject>
    </svg>
  </div>
</body>

更好:

保持指针的最后位置。

CodePen上的演示

var items = document.getElementsByClassName('menu-item');
var clipPath = document.getElementById('clip-path');
var last = items[0];
for (i = 0; i < items.length; i++) {
  items[i].addEventListener('click', function() {
    var x = this.getBoundingClientRect().left + (this.offsetWidth / 2) - 20;
    var currentX = clipPath.getAttribute('transform').replace('translate(', '');
    currentX = parseInt(currentX.replace(', 0)', ''), 10);
    animStart(currentX, x);
    last = this;
  })
}

function animStart(begin, end) {
  if (begin < end) {
    for (start = begin; start <= end; start += 0.1) {
      anim(start);
    }
  } else {
    var c = end;
    for (start = begin; end <= start; start -= 0.1) {
      animD(start, c);
      c += 0.1
    }
  }
}

function anim(start) {
  setTimeout(function() {
    clipPath.setAttribute('transform', 'translate(' + start + ', 0)');
  }, 1 * start);
}

function animD(start, c) {
  setTimeout(function() {
    clipPath.setAttribute('transform', 'translate(' + start + ', 0)');
  }, 1 * c);
}

function align() {
  var x = last.getBoundingClientRect().left + (last.offsetWidth / 2) - 20;
  animStart(0, x);
}

function resize() {
  var x = last.getBoundingClientRect().left + (last.offsetWidth / 2) - 20;
  clipPath.setAttribute('transform', 'translate(' + x + ', 0)');
}
window.onresize = resize;
window.onload = align;
body {
  background: #222222;
  margin: 0;
}
.nav-container {
  top: 20px;
  position: relative;
  width: 100%;
  height: 50px;
  background: repeating-linear-gradient(90deg, palegoldenrod 5px, palegreen 10px, palegreen 15px, paleturquoise 15px, paleturquoise 20px, plum 20px, plum 25px);
}
.nav {
  width: 600px;
  height: 50px;
  margin: 0 auto;
  text-align: center;
}
.menu-item {
  display: inline-block;
  width: 70px;
  padding: 17px 20px;
  color: #222222;
  font-size: 14px;
}
.menu-item:hover {
  color: seagreen;
  cursor: pointer;
}
#bottom {
  width: 100%;
  height: 35px;
  background: repeating-linear-gradient(90deg, palegoldenrod 5px, palegreen 10px, palegreen 15px, paleturquoise 15px, paleturquoise 20px, plum 20px, plum 25px);
}
<body>
  <div class="nav-container">
    <div class="nav">
      <div id="menu-item-1" class="menu-item">Home</div>
      <div id="menu-item-2" class="menu-item">About</div>
      <div id="menu-item-3" class="menu-item">Services</div>
      <div id="menu-item-4" class="menu-item">Locations</div>
      <div id="menu-item-5" class="menu-item">Contact Us</div>
    </div>
    <svg style="position: relative; top: -1px;" class="svg-defs" height="35" width="100%">
      <defs>
        <clipPath id="clipping">
          <path id="clip-path" transform="translate(0,0)" d="M0,0 L40,0 L20,15z M20,6 m-5,0 a5,5 0 1,0 10,0 a5,5 0 1,0 -10,0z" />
        </clipPath>
      </defs>
      <foreignObject x="0" y="0" clip-path="url(#clipping)" height="35" width="100%">
        <div id="bottom"></div>
      </foreignObject>
    </svg>
  </div>
</body>

【讨论】:

  • 你太棒了。谢谢chipChocolate.py!我喜欢 foreignObject 概念,所以会尝试一下!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-13
  • 2012-11-22
  • 2015-09-21
  • 1970-01-01
  • 2023-03-11
  • 2021-05-01
  • 2019-11-28
相关资源
最近更新 更多