block by zanarmstrong efd2d76e3455e9a35a51

custom ease

Full Screen

Draw a custom easing function in the white box on the left by clicking and dragging on it. When you let go the shapes on the right will be animated by converting the drawn path into an easing function with mojs and transitioned with d3.js

Built with blockbuilder.org

forked from enjalot‘s block: custom ease

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
  
  <style>
    body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
    #ease { 
      position: absolute;
      top: 50px;
      left: 50px;
      width: 400px; height: 400px; 
      background-color: #eaf4fa;
    }
    #ease .container {
      cursor: pointer;
    }
    #anim { 
      position: absolute;
      top: 50px;
      left: 520px;
      width: 400px; height: 400px; 
      background-color: #eafaf2;
      cursor: pointer;
    }
    
    
    path.ease {
      fill: none;
      stroke: #ff8e9d;
      stroke-width: 5;
      pointer-events: none;
    }
    .yaxis {
      pointer-events: none;
      -webkit-touch-callout: none;
      -webkit-user-select: none;
      -khtml-user-select: none;
      -moz-user-select: none;
      -ms-user-select: none;
      user-select: none;
    }
    .yaxis path {
      fill: none;
      stroke: #111;
      
    }
  </style>
</head>

<body>
  <script src="//cdn.jsdelivr.net/mojs/latest/mo.min.js"></script>
  <svg id="ease"></svg>
  <svg id="anim"></svg>
  <script>
    var easesvg = d3.select("#ease");
    var easeWidth = 400;
    var easeHeight = 400;
    var animsvg = d3.select("#anim");
    
    var ey0 = 50;
    var ey1 = 350;
    var ex0 = 50;
    var ex1 = 300;
    var easeYscale = d3.scale.linear()
    .range([ey1, ey0])
    var easeXscale = d3.scale.linear()
    .range([0, ex1])
    
    var moEaseXScale = d3.scale.linear()
    .range([0, 100])
    var moEaseYScale = d3.scale.linear()
    //.domain([ey1, ey0])
    .range([0, 100])
    
    var line = d3.svg.line()
      .x(function(d) { return easeXscale(d.x) })
      .y(function(d) { return ey1 - easeYscale(d.y) })
      .interpolate("linear")
    var lineEase = d3.svg.line()
      .x(function(d) { return moEaseXScale(d.x) })
      .y(function(d) { return moEaseYScale(d.y) })
    // note: changed interpolation from "linear" to "basis" here
      .interpolate("basis")
    
    var points = [];
    var drag = d3.behavior.drag()
    .on("dragstart", function() {
      points = [{
        x: 0,
        y: 1
      }]
    })
    .on("drag", function() {
      var x = (d3.mouse(this)[0]-ex0)/ex1;
      var pm1 = points[points.length-1];
      if(x < pm1.x) x = pm1.x+1;
      if(x > 1) return;
      var point = {
        x: x,
        y: (d3.mouse(this)[1]-ey0/2)/ey1
      }
      // TODO smooth?
      points.push(point)
      update();
    })
    .on("dragend", function() {
      var pm1 = points[points.length-1];
      if(pm1.x < 1) {
        points.push({
          x: 1,
          y: pm1.y
        })
      }
      update();
      animate()
    })
    
    var yg = easesvg.append("g")
    	.classed("yaxis", true)
      .attr("transform", "translate(50,0)")
    var axis = d3.svg.axis()
      .scale(easeYscale)
      .orient("left")
      .tickValues([0, 1])
    yg.call(axis);
    
    var easecontainer = easesvg.append("rect").classed("container", true)
    .attr({
      x: ex0,
      y: ey0,
      width: ex1,
      height: ey1-ey0,
      "fill-opacity": 0.5,
      "fill": "#fff"
    })
    
    var path = easesvg.append("path")
    	.classed("ease", true)
      .attr("transform", "translate(" + [ex0, ey0] + ")");
    
    function update() {
      path.datum(points)
        .attr("d", line)
    }
    
    var rectStart = {
      x: 50, y: ey1 - 25,
      width: 50, height: 50,
      fill: "#333"
    }
    var rectEnd = {
      x: 50, y: ey0 - 25,
      width: 50, height: 50
    }
    var circleStart = {
      cx: 200,cy: 200, r: 5,
      fill: "#312"
    }
    var circleEnd = {
      cx: 200,cy: 200, r: 50,
      fill: "#efe"
    }
    var rect = animsvg.append("rect")
      .attr(rectStart)
    var circle = animsvg.append("circle")
      .attr(circleStart);
    
    var easeLine = easesvg.append("line")
    .attr({
      x1: ex0, y1: ey0,
      x2: ex0, y2: ey1,
      stroke: "#111"
    })

    var duration = 1500;
    var endDuration = 1000;
    
    function animate() {
      //we pass the svg line string to the mojs easing function creator
      var ease = mojs.easing.path(lineEase(points));
      
      console.log("0, 0.5, 1: ", ease(0), ease(0.5), ease(1))
      
      
      rect.transition()
        .duration(duration)
      	.ease(ease)
      	.attr(rectEnd)
      .transition()
        .duration(endDuration)
        //.ease("linear")
        .ease(ease)
        .attr(rectStart)
      
      circle.transition()
        .duration(duration)
      	.ease(ease)
      	.attr(circleEnd)
      .transition()
        .duration(endDuration)
        //.ease("linear")
        .ease(ease)
        .attr(circleStart)
      
      easeLine.transition()
        .duration(duration)
        .ease("linear")
        .attr({
          x1: ex1+ex0, x2: ex1+ex0
        })
      .transition()
        .duration(endDuration)
        .ease("linear")
        .attr({
          x1: ex0, x2: ex0
        })
      
    }
    animsvg.on("click", animate);
    easecontainer.call(drag)
    
  </script>
</body>