KodiakSA
KodiakSA

Reputation: 213

KineticJS: Adding Images along Spline

I would like to add images along a Spline. So a spline is drawn by the user, and then after it is drawn I'd like to run images along it's path. Fundamentally, the images would be repeated along the path of the spline Any ideas on how this could be achieved?

Upvotes: 0

Views: 154

Answers (1)

markE
markE

Reputation: 105035

You can place markers (or your images) at intervals along the spline

  • You can get the starting point of the Kinetic.Spline by calling mySpline.getPoints().

  • You can get the curve definitions for a spline by calling the internal mySpline.getTensionPoints.

  • The first curve is a quadratic curve (controlX, controlY, endX, endY)

  • The intermediate curves are cubic curves. (control1X, control1Y, control2X, control2Y, endX, endY);

  • The last curve is a quadratic curve (controlX, controlY, endX, endY)

With this info and some Math, you can place markers (or your images) at intervals on each curve.

enter image description here

Here’s code and a Demo: http://jsfiddle.net/m1erickson/8mb9r/

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Prototype</title>
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
    <script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.0.0.min.js"></script>
<style>
body{padding:20px;}
#container{
  border:solid 1px #ccc;
  margin-top: 10px;
  width:400px;
  height:350px;
}
</style>        
<script>
$(function(){

    var stage = new Kinetic.Stage({
        container: 'container',
        width: 400,
        height: 350
    });
    var layer = new Kinetic.Layer();
    stage.add(layer);


    var spline = new Kinetic.Line({
      points: [20,100,340,100,200,200,50,200],
      stroke: 'green',
      strokeWidth: 3,
      lineCap: 'round',
      tension: 1,
    });
    layer.add(spline);
    layer.draw();

//
// the following code places markers along the spline at interval
//

    showSplineMarkers(spline,0.25);

    function showSplineMarkers(spline,interval){
        var points = spline.getPoints();
        var length = points.length;
        var tension = spline.getTension();
        var closed = spline.getClosed();
        var tp, len, n, pt1, pt2, pt3, pt4;
        var intervalT=interval;
        var spots=[];

        pt1={x:points[0],y:points[1]};  // starting point of spline


        // return if not a spline (tension==0)
        // return when insufficient spline points are declared

        if(tension==0 || length<=4){ return; }

        // walk along the spline and place markets at interval

        tp = spline.getTensionPoints();
        len = tp.length;
        n = closed ? 0 : 4;


        // the first curve of the spline is Quadratic

        if (!closed) {
            pt2={x:tp[0],y:tp[1]};
            pt3={x:tp[2],y:tp[3]};
            placeAlongQuad(intervalT,pt1,pt2,pt3);
            pt1=pt3;
        }

        // all intermediate curves of the spline are CubicBezier

        while(n < len - 2) {
            pt2={x:tp[n++],y:tp[n++]};
            pt3={x:tp[n++],y:tp[n++]};
            pt4={x:tp[n++],y:tp[n++]};
            placeAlongCubicBezier(intervalT,pt1,pt2,pt3,pt4);
            pt1=pt4;
        }

        // the last curve of the spline is Quadratic

        if (!closed) {
            pt2={x:tp[len-2],y:tp[len-1]};
            pt3={x:points[length-2],y:points[length-1]};
            placeAlongQuad(intervalT,pt1,pt2,pt3);
        }

    }  //  end showSplineMarkers


    // place markers at interval along the Quad curve

    function placeAlongQuad(intervalT,pt1,pt2,pt3){
        for(var i=0.00;i<=1.00;i+=intervalT){
            var pt=getQuadraticBezierXYatT(pt1,pt2,pt3,i);
            spot(pt.x,pt.y);
        }
    }

    // place markers at interval along CubicBez curve

    function placeAlongCubicBezier(intervalT,pt1,pt2,pt3,pt4){
        for(var i=0.00;i<=1.00;i+=intervalT){
            var pt=getCubicBezierXYatT(pt1,pt2,pt3,pt4,i);
            spot(pt.x,pt.y);
        }
    }

    // draw a marker

    function spot(x,y){
        var n=new Kinetic.Circle({
            x:x,
            y:y,
            radius:4,
            fill:"red"
        });
        layer.add(n);
        layer.draw();
    }

    // get XY at interval on Quad

    function getQuadraticBezierXYatT(startPt,controlPt,endPt,T) {
        var x = Math.pow(1-T,2) * startPt.x + 2 * (1-T) * T * controlPt.x + Math.pow(T,2) * endPt.x; 
        var y = Math.pow(1-T,2) * startPt.y + 2 * (1-T) * T * controlPt.y + Math.pow(T,2) * endPt.y; 
        return( {x:x,y:y} );
    }

    // get XY at interval on CubicBez

    function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){
        var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
        var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
        return({x:x,y:y});
    }

    // cubic helper formula at T
    function CubicN(T, a,b,c,d) {
        var t2 = T * T;
        var t3 = t2 * T;
        return a + (-a * 3 + T * (3 * a - a * T)) * T
        + (3 * b + T * (-6 * b + b * 3 * T)) * T
        + (c * 3 - c * 3 * T) * t2
        + d * t3;
    }

}); // end $(function(){});

</script>       
</head>

<body>
    <div id="container"></div>
</body>
</html>

Upvotes: 1

Related Questions