带绳索图案的二次曲线

时间:2015-09-01 03:13:43

标签: canvas html5-canvas fabricjs

我试图在Fabric中创建一根绳子。当它是一根直绳时,一切都很好,但如果我让它弯曲一点,就会变成这样的

http://i.stack.imgur.com/EZeSb.png

当我的绳子弯曲时,我失去了一部分绳索。

所以我试着将它分成多个小矩形,并将模式添加到所有这些,但它看起来不自然,所有矩形都在凌乱的坐标系中。

那么无论如何都要创建一条普通的曲线绳索?谢谢!

1 个答案:

答案 0 :(得分:1)

enter image description here

是的,你可以,但它非常复杂,曲线必须相对“温和”(没有急转弯)。

您在问题中使用的曲线可以正常工作。

您必须在原生html5画布上绘制弯曲的绳索,然后在FabricJS上显示该原生画布。

请参阅此链接,了解如何在曲线上绘制渐变:

Gradient Stroke Along Curve in Canvas

然后沿曲线而不是渐变逐渐绘制绳索图像:

  1. 从水平绳索图像开始,
  2. 你要将它垂直切成1px长度,
  3. 沿着曲线逐渐绘制绳索切片,每个切片与曲线上每个新点的曲线角度相切。
  4. 您可以使用转换完成#3:

    1. 将画布原点重置为曲线上的某个点:context.translate(curveX,curveY)
    2. 以与曲线相切的角度旋转画布:context.rotate(tangentAngle).
    3. 使用剪切版本drawImage

      绘制图像的下一个切片
      drawImage(ropeImg,sliceX,0,1,ropeImg.height,0,0,1,ropeImg.height);
      
    4. 通过撤消转换进行清理:context.setTransform(1,0,0,1,0,0);

    5. 使用曲线上的下一个点和下一个绳索片重复#1。
    6. 继续曲线上的所有点。
    7. 此时,您在原生html5画布上有一条弯曲的绳索。

      使用nativeCanvas.toDataURL()作为图像源创建新的FabricJS图像。

      示例代码和演示

      var canvas=document.getElementById("canvas");
      var ctx=canvas.getContext("2d");
      var cw=canvas.width;
      var ch=canvas.height;
      
      // variables defining a cubic bezier curve
      var PI2=Math.PI*2;
      var s={x:20,y:50};
      var c1={x:200,y:70};
      var c2={x:40,y:230};
      var e={x:270,y:250};
      
      // an array of points plotted along the bezier curve
      var points=[];
      
      // we use PI often so put it in a variable
      var PI=Math.PI;
      
      // plot 400 points along the curve
      // and also calculate the angle of the curve at that point
      // NOTE: You may need to adjust the point count (==100 here)
      //      if the curve is much shorter or longer than this demo's curve
      for(var t=0;t<=100;t+=0.25){
      
        var T=t/100;
      
        // plot a point on the curve
        var pos=getCubicBezierXYatT(s,c1,c2,e,T);
      
        // calculate the tangent angle of the curve at that point
        var tx = bezierTangent(s.x,c1.x,c2.x,e.x,T);
        var ty = bezierTangent(s.y,c1.y,c2.y,e.y,T);
        var a = Math.atan2(ty, tx)-PI/2;
      
        // save the x/y position of the point and the tangent angle
        // in the points array
        points.push({
          x:pos.x,
          y:pos.y,
          angle:a
        });
      
      }
      
      var img=new Image();
      img.onload=function(){
        slicer();
      };
      img.src='https://dl.dropboxusercontent.com/u/139992952/multple/rope.png';
      
      
      function slicer(){
      
        // Note: increase the lineWidth if 
        // the gradient has noticable gaps 
        ctx.lineWidth=2;
      
        ctx.strokeStyle='skyblue';
      
        var sliceCount=0;
      
        // draw a gradient-stroked line tangent to each point on the curve
        for(var i=0;i<points.length;i++){
          var p=points[i];
          ctx.translate(p.x,p.y);
          ctx.rotate(p.angle-PI/2);
          // draw multiple times to fill gaps on outside of rope slices
          ctx.drawImage(img,sliceCount,0,1,img.height,0,0,1,img.height);
          ctx.drawImage(img,sliceCount,0,1,img.height,0,0,1,img.height);
          ctx.drawImage(img,sliceCount,0,1,img.height,0,0,1,img.height);
          ctx.setTransform(1,0,0,1,0,0);
          ++sliceCount;
          if(sliceCount>(img.width-1)){sliceCount=0;}
        }
      
      }
      
      
      //////////////////////////////////////////
      // helper functions
      //////////////////////////////////////////
      
      // calculate one XY point along Cubic Bezier at interval T
      // (where T==0.00 at the start of the curve and T==1.00 at the end)
      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 distance
      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;
      }
      
      // calculate the tangent angle at interval T on the curve
      function bezierTangent(a, b, c, d, t) {
        return (3 * t * t * (-a + 3 * b - 3 * c + d) + 6 * t * (a - 2 * b + c) + 3 * (-a + b));
      };
      body{ background-color: ivory; }
      #canvas{border:1px solid red; margin:0 auto; }
      <h4>Source horizontal rope image</h4>
      <img src='https://dl.dropboxusercontent.com/u/139992952/multple/rope.png'>
      <h4>After slicing rope and drawing it along curve</h4>
      <canvas id="canvas" width=300 height=300></canvas>