将split cubic-bezier外推至1,1

时间:2014-05-05 14:46:56

标签: javascript css-transitions bezier cubic

我需要帮助解决此处提供的解决方案。

Create easy function 40% off set

我需要对其进行修改,以便在拆分后将返回的左侧和权限外推到1,1。这是因为如果我没有推断,我就不能使用返回的split cubic-bezier作为css转换。

所以这是我做的测试。请帮助,因为真实不符合迈克的方式:(我认为问题是我需要将结果推断为1,1。我不能简单地将值加倍,尽管我很确定。

用于获取Mike方式的代码是:

var result = split({
    z: .5,
    x: [0, 0.42, 0.58, 1],
    y: [0, 0, 1, 1]
});
alert(result.toSource());

2 个答案:

答案 0 :(得分:1)

  

上半部分为easy-in,其为cubic-bezier(.42,0,1,1),图形为http://cubic-bezier.com/#.42,0,1,1

请验证此假设。 (曲线原始终点为0,0,css timing function中为1,1) 贝塞尔曲线[0,0,.42,0,.58,1,1,1]的前半部分不应为[0,0 .42,0,1,1,1,1] 终点是正确的(在缩放到1,1之后),但是你在那里失去了连续性。

Mike的算法返回的值是正确的。

Try this visualisation解释为什么您的假设可能出错。

您用于拆分的算法是一种众所周知的称为de Casteljau算法的算法。该方法可以以非常简单的方式几何表达。查看关于如何在任意点进行分割的动画可视化https://en.wikipedia.org/wiki/B%C3%A9zier_curve

然而,您可能很快就会遇到一个问题,试图正确缩放贝塞尔曲线的分割部分以适合单位平方,端点固定为0,0和1,1。这可能你可以很容易地在纸上试试。最简单的方法可能只是线性缩放贝塞尔曲线的控制点,但在大多数情况下你会得到一条压扁的曲线。

答案 1 :(得分:0)

我创建了Mike的拆分函数的修改版本,因此它适合单位正方形:)它使用hkrish的指针来进行坐标规范化。

只需将参数fitUnitCell设置为true即可。 :)

function splitCubicBezier(options) {
  var z = options.z,
      cz = z-1,
      z2 = z*z,
      cz2 = cz*cz,
      z3 = z2*z,
      cz3 = cz2*cz,
      x = options.x,
      y = options.y;

  var left = [
    x[0],
    y[0],
    z*x[1] - cz*x[0], 
    z*y[1] - cz*y[0], 
    z2*x[2] - 2*z*cz*x[1] + cz2*x[0],
    z2*y[2] - 2*z*cz*y[1] + cz2*y[0],
    z3*x[3] - 3*z2*cz*x[2] + 3*z*cz2*x[1] - cz3*x[0],
    z3*y[3] - 3*z2*cz*y[2] + 3*z*cz2*y[1] - cz3*y[0]];

  var right = [
    z3*x[3] - 3*z2*cz*x[2] + 3*z*cz2*x[1] - cz3*x[0],
    z3*y[3] - 3*z2*cz*y[2] + 3*z*cz2*y[1] - cz3*y[0],
                    z2*x[3] - 2*z*cz*x[2] + cz2*x[1],
                    z2*y[3] - 2*z*cz*y[2] + cz2*y[1],
                                    z*x[3] - cz*x[2], 
                                    z*y[3] - cz*y[2], 
                                                x[3],
                                                y[3]];

  if (options.fitUnitSquare) {
    return {
      left: left.map(function(el, i) {
        if (i % 2 == 0) {
          //return el * (1 / left[6])
          var Xmin = left[0];
          var Xmax = left[6]; //should be 1
          var Sx = 1 / (Xmax - Xmin);
          return (el - Xmin) * Sx;
        } else {
          //return el * (1 / left[7])
          var Ymin = left[1];
          var Ymax = left[7]; //should be 1
          var Sy = 1 / (Ymax - Ymin);
          return (el - Ymin) * Sy;
        }
      }),
      right: right.map(function(el, i) {
        if (i % 2 == 0) {
          //xval
          var Xmin = right[0]; //should be 0
          var Xmax = right[6];
          var Sx = 1 / (Xmax - Xmin);
          return (el - Xmin) * Sx;
        } else {
          //yval
          var Ymin = right[1]; //should be 0
          var Ymax = right[7];
          var Sy = 1 / (Ymax - Ymin);
          return (el - Ymin) * Sy;
        }
      })
    }
  } else {
   return { left: left, right: right};
  }
}

var easeInOut = {
  xs: [0, .42, .58, 1],
  ys: [0,   0,   1, 1]
};


var splitRes = splitCubicBezier({
  z: .5,
  x: easeInOut.xs,
  y: easeInOut.ys,
  fitUnitSquare: false
});

alert(splitRes.toSource())