施杰龙 發表於 2022-12-10 20:01:00

前端开发系列026-基础篇之Canvas绘图(曲线)

<div class="tip">本文将介绍Canvas中的弧度、曲线、圆弧以及文字的绘制方法以及径向渐变等内容,并提供饼状图等综合案例。</div>
<h2 id="一canvas中的弧度曲线和圆弧">一、Canvas中的弧度、曲线和圆弧</h2>
<div class="titleX">专业术语</div>
<img src="http://img.wendingding.vip/blog/canvas_13.png" width="500px">
<p><strong><code>夹角</code></strong> 从一个点发射(延伸)出两条线段,两条线相交的部分会构成一个夹角。</p>
<p><strong><code>角度</code></strong> 两条相交直线中的任何一条与另一条相叠合时必须转动的量的量度,单位符号为<code>°</code>。</p>
<p><strong><code>周角</code></strong> 一条直线围绕起点需要与自己相叠合时必须转动的量的量度被称为周角,周角等分为<code>360</code>度。</p>
<p><strong><code>弧度</code></strong> 角度量单位,弧长等于半径的弧所对圆心角为1弧度(<span style="color: rgba(255, 0, 0, 1)">弧长等于半径时射线夹角为1弧度</span>)。</p>
<div style="border: 1px solid rgba(136, 136, 136, 1); width: 300px; height: 44px; line-height: 44px; text-align: center"> 公式弧度 = 角度 * π / 180 </div>
<p>在使用JavaScript编写代码进行相关计算的时候,经常需要使用Math提供的成员,这里简单说明。<br>
<img src="http://img.wendingding.vip/blog/canvas_14.png"></p>
<p><strong><span style="color: rgba(255, 0, 0, 1)">Math.PI</span></strong> 代表着<strong>π</strong>。</p>
<p><strong><span style="color: rgba(255, 0, 0, 1)">Math.sin(弧度)</span></strong> 夹角对面的边 与 斜边的比值。</p>
<p><strong><span style="color: rgba(255, 0, 0, 1)">Math.cos(弧度)</span></strong> 夹角侧面的边 与 斜边的比值。</p>
<p>这里给出圆形上点坐标的计算公式,其中<code>x0</code>和<code>y0</code>为圆心坐标,<code>rad</code>为弧度,<code>R</code>为圆的半径。</p>
<p>坐标   <code>( x0 + Math.cos(rad) x R    ,    y0 + Math.sin(rad) x R )</code></p>
<div class="titleX">核心API介绍</div>
<p><span style="border: 1px solid rgba(204, 204, 204, 1); padding: 2px 10px; color: rgba(102, 102, 102, 1)"><strong>绘制圆弧</strong></span></p>
<p><strong><code>语法</code></strong> <code>ctx.arc(x,y,r,startAngle,endAngle,counterclockwise);</code></p>
<p><strong><code>作用</code></strong> 通过该方法来绘制圆弧或者(半)圆。</p>
<p><strong><code>参数</code></strong></p>
<ul>
<li><span style="font-family: Georgia">x 圆心X轴坐标</span></li>
<li><span style="font-family: Georgia">y 圆心Y轴坐标</span></li>
<li><span style="font-family: Georgia">r 圆的半径</span></li>
<li><span style="font-family: Georgia">startAngle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;开始弧度</span></li>
<li><span style="font-family: Georgia">endAngle    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;结束弧度</span></li>
<li><span style="font-family: Georgia">counterclockwise &nbsp;&nbsp;是否逆时针旋转(默认为false)</span></li>
</ul>
<p><span style="border: 1px solid rgba(204, 204, 204, 1); padding: 2px 10px; color: rgba(102, 102, 102, 1)"><strong>绘制圆弧曲线</strong></span></p>
<p><strong><code>语法</code></strong> <code>ctx.arcTo(x1,y1,x2,y2,r);</code></p>
<p><strong><code>作用</code></strong> 参考两个点并根据指定半径来创建一条圆弧路径。</p>
<p><strong><code>备注</code></strong> 绘制的圆弧与当前点到第一个点的连线相切且与第一第二个点的连线也相切。</p>
<p><strong><code>说明</code></strong> <code>arcTo</code>方法的这些特性决定了该方法非常适合用来绘制圆角矩形。</p>
<p><strong><code>参数</code></strong></p>
<ul>
<li><span style="font-family: Georgia">x1 第一个参考点的X轴坐标</span></li>
<li><span style="font-family: Georgia">y1 第一个参考点的Y轴坐标</span></li>
<li><span style="font-family: Georgia">x2 第二个参考点的X轴坐标</span></li>
<li><span style="font-family: Georgia">y3 第二个参考点的Y轴坐标</span></li>
<li><span style="font-family: Georgia">r &nbsp;&nbsp;&nbsp;圆的半径</span></li>
</ul>
<p><span style="border: 1px solid rgba(204, 204, 204, 1); padding: 2px 10px; color: rgba(102, 102, 102, 1)"><strong>圆形渐变</strong></span></p>
<p><strong><code>语法</code></strong> <code>ctx.createRadialGradient(x0,y0,r0,x1,y1,r1);</code></p>
<p><strong><code>作用</code></strong> 通过该方法来绘制圆弧或者(半)圆。</p>
<p><strong><code>参数</code></strong></p>
<ul>
<li><span style="font-family: Georgia">x0 渐变开始圆的X轴坐标</span></li>
<li><span style="font-family: Georgia">y0 渐变开始圆的Y轴坐标</span></li>
<li><span style="font-family: Georgia">r0 开始圆的半径</span></li>
<li><span style="font-family: Georgia">x1 渐变结束圆的X轴坐标</span></li>
<li><span style="font-family: Georgia">y1 渐变结束圆的Y轴坐标</span></li>
<li><span style="font-family: Georgia">r1 结束圆的半径</span></li>
</ul>
<h2 id="二canvas曲线-圆弧绘制示例">二、Canvas曲线-圆弧绘制示例</h2>
<div class="titleX">数学方程绘制图形案例(一)</div>
<img src="http://img.wendingding.vip/blog/canvas_17.png" height="120px">
<pre><code>    var canvas= document.getElementById("canvas");
    var ctx   = canvas.getContext("2d");

    //001 通过代数方程来绘制直线
    //设置路径(起点)
    ctx.moveTo(0,0);
    for(var x = 30,y = 0; x &lt; 1000 ; x++)
    {
      //通过代数方程来绘制直线
      y = x / 2 * 0.3;
      ctx.lineTo(x,y);
    }
    //设置描边的颜色样式
    ctx.strokeStyle = "#0Af";
    //描边绘制出图案
    ctx.stroke();

    //002 通过三角函数来绘制曲线(正玄/余弦)
    ctx.beginPath();
    for(var x = 30,y = 0; x &lt; 1000 ; x++)
    {   
      // 高度 * 波长 + 中心轴位置
      y = 50 * Math.sin(x/25) + 100;
      ctx.lineTo(x,y);
    }
    //设置描边的颜色样式
    ctx.strokeStyle = "red";
    //描边绘制出图案
    ctx.stroke();
</code></pre>
<div class="titleX">数学方程绘制图形案例(二)</div>
<img src="http://img.wendingding.vip/blog/canvas_20.png" height="120px">
<pre><code>    var canvas= document.getElementById("canvas");
    var ctx   = canvas.getContext("2d");
    function draw(offsetX,n){
      var dig = Math.PI / 15 * n;
      ctx.beginPath();
      for(var i = 0 ; i &lt; 30 ; i++)
      {
            var x = Math.sin(i * dig);
            var y = Math.cos(i * dig);
            ctx.lineTo(offsetX + x * 80,150 + y * 80);
      }
      //闭合路径
      ctx.closePath();
      //设置样式并填充
      ctx.fillStyle = "#fff";
      ctx.fill();
      //设置样式并描边
      ctx.strokeStyle = "#666";
      ctx.stroke();
    }

    var data = ;
    data.forEach(function(n,i){
      draw((i + 1) * 160,n);
    })
</code></pre>
<div class="titleX">绘制相切曲线案例</div>
<img src="http://img.wendingding.vip/blog/canvas_21.png" height="120px">
<pre><code>    var canvas = document.getElementById("canvas");
    var ctx    = canvas.getContext("2d");

    var x0 = 100,y0 = 100,
      x1 = 500,y1 = 100,
      x2 = 450,y2 = 150;

    ctx.beginPath();
    ctx.moveTo(x0,y0);
    ctx.arcTo(x1,y1,x2,y2,30);
    ctx.strokeStyle = "red";
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(x0,y0);
    ctx.lineTo(x1,y1);
    ctx.lineTo(x2,y2);

    ctx.fillText('x0,y0',x0,y0+10)
    ctx.fillText('x1,y1',x1+10,y1+10)
    ctx.fillText('x2,y2',x2+10,y2)
    ctx.strokeStyle = "#333";
    ctx.stroke();
</code></pre>
<div class="titleX">绘制圆角矩形案例</div>
<img src="http://img.wendingding.vip/blog/canvas_22.png" height="120px">
<pre><code>    var canvas = document.getElementById("canvas");
    var ctx    = canvas.getContext("2d");

    function drawRoundedRect(x,y,w,h,r,isFill,isStrokeRect){
      ctx.beginPath();
      ctx.moveTo( x + r , y );
      ctx.arcTo(x + w , y , x + w , y + h , r);
      ctx.arcTo(x + w , y + h , x , y + h , r);
      ctx.arcTo(x , y + h , x , y , r);
      ctx.arcTo(x , y ,x + r , y , r);

      if(isFill) {
            ctx.fillStyle = getRandomColor();
            ctx.fill();
      }else
      {
            ctx.strokeStyle = getRandomColor();
            ctx.stroke();
      }

       if(isStrokeRect)
      {
            ctx.beginPath();
            ctx.moveTo( x + r , y );
            ctx.lineTo(x + w, y );
            ctx.lineTo(x + w, y + h);
            ctx.lineTo(x, y + h);
            ctx.lineTo(x, y);
            ctx.lineTo(x + r, y);

            ctx.fillStyle = "#000";
            ctx.fillText("x0,y0",x + r,y);
            ctx.fillText("x1,y1",x + w,y);
            ctx.fillText("x2,y2",x + w,y + h + 10);
            ctx.fillText("x3,y3",x-10,y + h + 10);
            ctx.fillText("x4,y4",x - 10,y-10);
            ctx.fillText("x5,y5",x + r,y + 10);
            ctx.stroke();
      }
    }

    drawRoundedRect(50,40,100,100,50,false,true);
    drawRoundedRect(200,40,100,100,50,true,false);
    drawRoundedRect(350,40,100,100,10,true);
    drawRoundedRect(500,40,100,100,20);
    drawRoundedRect(650,40,120,100,30,true);

    function getRandomColor(){
      var r = getRandom();
      var g = getRandom();
      var b = getRandom();
      return "rgb("+r+","+g+","+b+")";
    }

    function getRandom(){
      return Math.floor(Math.random() * 256);
    }
</code></pre>
<div class="titleX">绘制弧线、扇形、圆弧和圆案例</div>
<img src="http://img.wendingding.vip/blog/canvas_16.png" height="120px">
<pre><code>    var canvas= document.getElementById("canvas");
    var ctx   = canvas.getContext("2d");

    //绘制弧线
    ctx.arc(100,100,50,3/2 * Math.PI,2 * Math.PI,false);
    ctx.stroke();

    //绘制扇形
    ctx.beginPath();
    ctx.moveTo(200,100);
    ctx.arc(200,100,50,3/2 * Math.PI,2 * Math.PI,false);
    ctx.lineTo(200,100);
    ctx.strokeStyle = "#f09";
    ctx.stroke();

    //填充扇形
    ctx.beginPath();
    ctx.moveTo(300,100);
    ctx.arc(300,100,50,3.2/2 * Math.PI,3.8/2 * Math.PI,false);
    ctx.lineTo(300,100);
    ctx.fillStyle = "#195";
    ctx.fill();

    //绘制半圆
    ctx.beginPath();
    ctx.strokeStyle = "#666";
    ctx.arc(450,100,50,Math.PI,2 * Math.PI,false);
    ctx.closePath();
    ctx.stroke();

    //绘制圆形
    ctx.beginPath();
    ctx.strokeStyle = "#000";
    ctx.arc(570,80,40,0,2 * Math.PI,false);
    ctx.stroke();
</code></pre>
<div class="titleX">绘制五环图案案例</div>
<img src="http://img.wendingding.vip/blog/canvas_15.png" height="120px">
<pre><code>    var canvas= document.getElementById("canvas");
    var ctx   = canvas.getContext("2d");
    var x = 100;
    var y = 100;
    var r = 50;
    for(var i = 0 ; i &lt; 5 ; i++)
    {   ctx.beginPath();
      if( i &gt;=3)
      {
            ctx.arc(x + (i * 80) -200,y + 60,r,0,2*Math.PI,false);
      }else{
            ctx.arc(x + (i * 80),y,r,0,2*Math.PI,false);
      }
      ctx.strokeStyle = getRandomColor();
      ctx.stroke();
    }

    function getRandomColor(){
      var r = getRandom();
      var g = getRandom();
      var b = getRandom();
      return "rgb("+r+","+g+","+b+")";
    }
    function getRandom(){
      return Math.floor(Math.random() * 256);
    }
</code></pre>
<div class="titleX">绘制等分的圆案例</div>
<img src="http://img.wendingding.vip/blog/canvas_18.png" height="140px">
<pre><code>    var canvas= document.getElementById("canvas");
    var ctx   = canvas.getContext("2d");

    //描边
    drawCircle(100,100,40,2,true);
    drawCircle(200,100,40,3,true);
    drawCircle(300,100,40,4,true);
    drawCircle(400,100,40,20,true);
    drawCircle(500,100,40,100,true);
    drawCircle(600,100,40,200,true);

    //填充
    drawCircle(100,200,40,2);
    drawCircle(200,200,40,3);
    drawCircle(300,200,40,4);
    drawCircle(400,200,40,20);
    drawCircle(500,200,40,100);
    drawCircle(600,200,40,200);

    function drawCircle(x,y,r,n,isStroke){
      for(vari = 0 ; i &lt; n ; i++)
      {
            //计算开始和结束的角度
            var angle = 2 * Math.PI / n;
            var startAngle= angle * i;
            var endAngle    = angle * (i + 1);

            //开始路径
            ctx.beginPath();

            //设置绘制圆的起点
            ctx.moveTo(x,y);
            ctx.arc(x,y,r,startAngle,endAngle,false);

            if(isStroke)
            {
                // ctx.strokeStyle = getRandomColor();
                ctx.stroke();
            }else
            {
                ctx.fillStyle = getRandomColor();
                ctx.fill();
            }
      }
    }
    //获取填充的颜色/随机
    function getRandomColor(){
      var r = getRandom();
      var g = getRandom();
      var b = getRandom();
      return "rgb("+r+","+g+","+b+")";
    }

    function getRandom(){
      return Math.floor(Math.random() * 256);
    }
</code></pre>
<div class="titleX">绘制饼状图综合示例</div>
<img src="http://img.wendingding.vip/blog/canvas_19.png" height="140px">
<pre><code>    function PieChart (ctx){
      this.ctx      = ctx || document.getElementById("canvas").getContext("2d");
      this.x          = this.ctx.canvas.width/2 - 30;
      this.y          = this.ctx.canvas.height/2;
      this.r          = 120;
      this.outLine    = 20;
      this.dataList   = null;
    }

    PieChart.prototype = {
      constructor:PieChart,
      init:function(dataList){
            this.dataList = dataList || [{title:"默认",value:100}];
            
            //根据数据来计算并转换弧度
            this.transformAngle();

            //绘制饼状图
            this.drawPie();
      },
      drawPie:function(){

            var startAngle = 0,endAngle;

            for(var i = 0 ; i &lt; this.dataList.length ; i++)
            {
                var item = this.dataList;
                endAngle = startAngle + item.angle;

                this.ctx.beginPath();
                this.ctx.moveTo(this.x,this.y);
                this.ctx.arc(this.x,this.y,this.r,startAngle,endAngle,false);
                var color= this.ctx.strokeStyle= this.ctx.fillStyle= this.getRandomColor();
                this.ctx.stroke();
                this.ctx.fill();

                //绘制标题
                this.drawPieTitle(startAngle,item.angle,color,item.title)
   
                //绘制图例
                this.drawPieLegend(i,item.title);
                startAngle = endAngle;
            }

      },
      drawPieTitle:function(startAngle,angle,color,title){

            var edge    = this.r + this.outLine;
            var edgeX   = Math.cos(startAngle + angle / 2) * edge; /*x轴方向的直角边*/
            var edgeY   = Math.sin(startAngle + angle / 2) * edge; /*y轴方向的直角边*/
            var outX    = this.x + edgeX;                        /*计算延伸出去的点坐标*/
            var outY    = this.y + edgeY;

            //画出坐标点
            this.ctx.beginPath();
            this.ctx.moveTo(this.x,this.y);
            this.ctx.lineTo(outX,outY);
            this.ctx.strokeStyle = color;
            this.ctx.stroke();

            //绘制文字下划线
            var textWidth   = this.ctx.measureText(title).width + 5;
            var lineX       = outX &gt; this.x ? outX + textWidth : outX - textWidth;
            this.ctx.lineTo(lineX,outY);
            this.ctx.stroke();

            //绘制文字
            this.ctx.font         = "15px KaiTi";
            this.ctx.textAlign      = outX &gt; this.x ? "left" : "right";
            this.ctx.textBaseline   = "bottom";
            this.ctx.fillText(title,outX,outY);
      },
      drawPieLegend:function(index,title){

            //在计算的时候最好的能够反着计算
            var space = 10;
            var rectW = 40;
            var rectH = 20;
            var rectX = this.x + this.r + 80;
            var rectY = this.y + (index * 30);
            //绘制矩形
            this.ctx.fillRect(rectX,rectY,rectW,rectH);
            // this.ctx.beginPath();
            // 绘制文字
            this.ctx.textAlign      = 'left';
            this.ctx.textBaseline   = 'top';
            this.ctx.fillStyle      = "#000";
            this.ctx.fillText(title,rectX + rectW + space,rectY);
      },
      getRandomColor:function(){
            var r = Math.floor(Math.random() * 256);
            var g = Math.floor(Math.random() * 256);
            var b = Math.floor(Math.random() * 256);
            return 'rgb('+r+','+g+','+b+')';
      },
      transformAngle:function(){
            var self    = this;
            var total   = 0;
            this.dataList.forEach(function(item,i){
                total += item.value;
            })
            this.dataList.forEach(function(item,i){
                self.dataList.angle = 2 * Math.PI * item.value/total;
            })
      },
    }
    vardata = [{value:20,title:"UI"},{value:26,title:"java"},
                {value:20,title:"iOS"},{value:63,title:"H5"},{value:25,title:"Node"}]
    varpie= new PieChart().init(data);

</code></pre>
<h2 id="三canvas中的贝塞尔曲线">三、Canvas中的贝塞尔曲线</h2>
<p>贝塞尔曲线(<code>Bézier curve</code>),最初由法国物理学家和数学家<code>Paul de Casteljau</code>发明,1962年被法国工程师皮埃尔·贝塞尔(<code>Pierre Bézier</code>)广泛发表并运用在汽车的车身设计上,现在多应用在计算机图形系统中。</p>
<p>贝塞尔曲线分为平方(<code>quadratic</code>)贝塞尔曲线和立方(<code>cubic</code>)贝塞尔曲线两其中平方贝塞尔曲线是一种二次曲线,由两个锚点和一个控制点总共三个点来定义,而立方贝塞尔曲线是一种三次曲线,由两个锚点和两个控制点共四个点来定义。它们的区别在于立方贝塞尔曲线能够在两个方向上弯曲。</p>
<p>Canvas支持两种贝塞尔曲线,分别由<code>quadraticCurveTo</code>和<code>bezierCurveTo</code>方法来实现。</p>
<p><span style="border: 1px solid rgba(204, 204, 204, 1); padding: 2px 10px; color: rgba(102, 102, 102, 1)"><strong>二次贝塞尔曲线</strong></span></p>
<p><strong><code>语法</code></strong> <code>ctx.quadraticCurveTo(x0,y0,x1,y1);;</code></p>
<p><strong><code>作用</code></strong> 通过使用表示二次贝塞尔曲线的指定控制点,向当前路径添加一个点绘制曲线。</p>
<p><strong><code>参数</code></strong></p>
<ul>
<li><span style="font-family: Georgia">x0 控制点的X轴坐标</span></li>
<li><span style="font-family: Georgia">y0 控制点的Y轴坐标</span></li>
<li><span style="font-family: Georgia">x1 结束点(锚点)的X轴坐标</span></li>
<li><span style="font-family: Georgia">y1 结束点(锚点)的Y轴坐标</span></li>
</ul>
<p><strong><code>说明</code></strong> 二次贝塞尔曲线需要两个点。分别是用于二次贝塞尔计算中的控制点和曲线的结束点。</p>
<p><strong><code>注意</code></strong> 曲线还需要一个开始点(路径最后的点)如果路径不存在,那么可以使用<code>moveTo() </code>方法来定义。</p>
<p><span style="border: 1px solid rgba(204, 204, 204, 1); padding: 2px 10px; color: rgba(102, 102, 102, 1)"><strong>三次贝塞尔曲线</strong></span></p>
<p><strong><code>语法</code></strong> <code>ctx.bezierCurveTo(x0,y0,x1,y1,x2,y2);;</code></p>
<p><strong><code>作用</code></strong> 通过使用表示二次贝塞尔曲线的指定控制点,向当前路径添加一个点绘制曲线。</p>
<p><strong><code>参数</code></strong></p>
<ul>
<li><span style="font-family: Georgia">x0 第一个控制点的X轴坐标</span></li>
<li><span style="font-family: Georgia">y0 第一个控制点的Y轴坐标</span></li>
<li><span style="font-family: Georgia">x1 第二个控制点的X轴坐标</span></li>
<li><span style="font-family: Georgia">y1 第二个控制点的Y轴坐标</span></li>
<li><span style="font-family: Georgia">x2 结束点(锚点)的X轴坐标</span></li>
<li><span style="font-family: Georgia">y2 结束点(锚点)的Y轴坐标</span></li>
</ul>
<p><strong><code>说明</code></strong> 三次贝塞尔曲线需要三个点,两个控制点和一个锚点。</p>
<p><strong><code>注意</code></strong> 曲线还需要一个开始点(路径最后的点)如果路径不存在,那么可以使用<code>moveTo() </code>方法来定义。</p>
<h2 id="四canvas贝塞尔曲线绘制示例">四、Canvas贝塞尔曲线绘制示例</h2>
<div class="titleX">二次贝塞尔曲线示例</div>
<img src="http://img.wendingding.vip/blog/canvas_24.png" height="150px">
<pre><code>    var canvas = document.getElementById("canvas");
    var ctx    = canvas.getContext("2d");

    //设置曲线的起点(当前路径的最后点没有则通过moveTo设置)
    ctx.moveTo(100,100);
    ctx.quadraticCurveTo(100,300,500,200);
    ctx.stroke();

    //绘制文字
    var margin = 15;
    ctx.fillText("(100,100)",100 - margin,100 - margin);
    ctx.fillText("(100,300)",100 - margin,300 + margin);
    ctx.fillText("(500,200)",500 - margin,200 + margin);

    //绘制线条
    ctx.beginPath();
    ctx.moveTo(100,100);
    ctx.lineTo(100,300);
    ctx.lineTo(500,200);
    ctx.strokeStyle = "red";
    ctx.stroke();

    //绘制点
    ctx.beginPath();
    ctx.arc(100,100,3,0,2 * Math.PI);
    ctx.arc(100,300,3,0,2 * Math.PI);
    ctx.fill();
    ctx.beginPath();
    ctx.arc(500,200,3,0,2 * Math.PI);
    ctx.fill();
</code></pre>
<div class="titleX">三次贝塞尔曲线示例</div>
<img src="http://img.wendingding.vip/blog/canvas_25.png" height="200px">
<pre><code>    var canvas = document.getElementById("canvas");
    var ctx    = canvas.getContext("2d");

    //设置曲线的起点(当前路径的最后点没有则通过moveTo设置)
    ctx.moveTo(100,100);
    ctx.bezierCurveTo(100,300,300,50,500,200);
    ctx.stroke();

    //绘制文字
    var margin = 15;
    ctx.fillText("起点 (100,100)",100 - margin,100 - margin);
    ctx.fillText("控制点 (100,300)",100 - margin,300 + margin);
    ctx.fillText("(300,50)",300 - margin,50 - margin);
    ctx.fillText("(500,200)",500 - margin,200 + margin);
    //绘制线条
    ctx.beginPath();
    ctx.moveTo(100,100);
    ctx.lineTo(100,300);
    ctx.lineTo(300,50);
    ctx.lineTo(500,200);
    ctx.strokeStyle = "red";
    ctx.stroke();

    //绘制点
    ctx.beginPath();
    ctx.arc(100,100,3,0,2 * Math.PI);
    ctx.arc(100,300,3,0,2 * Math.PI);
    ctx.fill();
    ctx.beginPath();
    ctx.arc(300,50,3,0,2 * Math.PI);
    ctx.arc(500,200,3,0,2 * Math.PI);
    ctx.fill();
</code></pre>
<div class="titleX">贝塞尔曲线复杂图形示例</div>
<img src="http://img.wendingding.vip/blog/canvas_26.png" height="150px">
<pre><code>    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");

    //绘制贝塞尔曲线
    function drawBezierCurve(dx,dy,n){

      var s = 120;
      var x0,x1,x3,y1,y2,y3;
      var dig = Math.PI / 15 * n;

      ctx.beginPath();
      for(var i = 0 ; i &lt; 30 ; i++)
      {
            varX = Math.sin(i * dig);
            varY = Math.cos(i * dig);
            x0 = dx + X * s;
            x1 = dx + X * s + 100;
            x2 = dx + X * s;

            y0 = dy + Y * s - 100;
            y1 = dy + Y * s;
            y2 = dy + Y * s;
            ctx.bezierCurveTo(x0 , y0 , x1 , y1 , x2 , y2);
      }
      ctx.closePath();

      //绘制和填充
      ctx.fillStyle   = "#eee";
      ctx.strokeStyle = "red";
      ctx.fill();
      ctx.stroke();
    }

    drawBezierCurve(150,250,13);
    drawBezierCurve(480,250,24);
    drawBezierCurve(820,250,31);
</code></pre>


</div>
<div id="MySignature" role="contentinfo">
    <div>原创文章,访问个人站点 文顶顶 以获得更好的阅读体验。</div>
<div>版权声明:著作权归作者所有,商业转载请联系文顶顶获得授权,非商业转载请注明出处。</div><br><br>
来源:https://www.cnblogs.com/wendingding/p/16970625.html
頁: [1]
查看完整版本: 前端开发系列026-基础篇之Canvas绘图(曲线)