当前位置:首页 > 网站技术 > 前端技术 > 正文内容

js基础之canvas绘图技术

小彬2020-09-29前端技术66


1.canvas的默认宽度和高度是300*150 

  canvas宽高应设置在canvas标签上(画布大小),设在style里会让canvas根据样式进行缩放(画布被拉伸后的大小)


2.使用 <canvas> 元素之前,首先要检测 getContext() 方法是否存在

  if (drawing.getContext)
  使用 toDataURL() 方法,可以导出在 <canvas> 元素上绘制的图像
  // 取得图像的数据 URI
  var imgURI = drawing.toDataURL("image/png");


3.如何在canvas进行绘画

  1:先通过document.querySelector('canvas')拿到canvas画布

  2:得到上下文canvas.getContext('2d')

  3:判断是否支持cnavas,if(drawing.getContext){}

  4:在此进行一系列的画布操作...

  最后一步:使用context.stroke()方法对路径绘制结束 重要


4.context.moveTo(0,0)从该点开始绘制。

  context.lineTo(0,0)绘制到该点结束。

 context.linewidth=number 线条加粗


5.填充和描边,属性的值可以是字符串、渐变对象或模式对象

  context.strokeStyle=""对上下文进行描边(添加颜色)。

  context.fillStyle=""对上下文进行填充颜色


6.路径的开始和结束

context.beginPath()可以重新开启绘制路径

context.stroke()结束路径绘制


7.canvas画圆:arc(x,y,r,0,2*Math.PI,false|true)

context.arc(100,100,50,0,2*Math.PI,false)画圆(画圆需要beginPath和stroke)

最后如果要填充颜色,记得使用ctx.fillStyle='';ctx.fill()


8.canvas画矩形

context.strokeRect(x, y, width, height)画描边矩形

context.fillRect(x, y, width, height)画填充矩形


9.arcTo(x1, y1, x2, y2, radius) :从上一点开始绘制一条弧线,到 (x2,y2) 为止,并且以给定的半径 radius 穿过 (x1,y1) 。

  rect(x, y, width, height) :从点 (x,y) 开始绘制一个矩形,宽度和高度分别由 width 和height 指定。这个方法绘制的是矩形路径,而不是 strokeRect() 和 fillRect() 所绘制的独立的形状


  canvas圆弧:实践观察true和false的不同之处

  ctx.arc(100,100,0,Math.PI/2,true|false)



10.二次样条曲线和贝塞尔曲线:最好借用线上工具

ctx.bezierCurveTo(c1x, c1y, c2x, c2y, x, y) :从上一点开始绘制一条曲线,到 (x,y) 为止,并且以 (c1x,c1y) 和 (c2x,c2y) 为控制点。

ctx.quadraticCurveTo(cx, cy, x, y) :从上一点开始绘制一条二次曲线,到 (x,y) 为止,并且以 (cx,cy) 作为控制点。


11.context.closePath()闭合路径

context.fill()自动填充图形


12.canvas平移teanslate

context.teanslate(x,y)

如果平移方法写在开始绘制前,则平移绘制圆点的坐标 

如果平移方法写在moveTo之后,则会造成平移后绘制的终点加上平移的(x,y)作为最终终点


13.canvas旋转rotate 围绕原点旋转图像 angle 弧度。

context.rotate(Math.PI/4) 旋转 图形变换是针对坐标系变换


14.canvas缩放scale

context.scale(scalex,scaley)在x方向乘以scaleX,在y方向乘以scaleY。scaleX和scaleY的默认值都是1.0。可叠加


15.canvas修改矩阵

 transform(m1_1, m1_2, m2_1, m2_2, dx, dy) :直接修改变换矩阵,方式是乘以如下矩阵。

m1_1 m1_2 dx

m2_1 m2_2 dy

0 0 1

16.canavs恢复默认矩阵

setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy) :将变换矩阵重置为默认状态,然后再调用 transform() 。


17.ctx.save()保存上下文环境,包括图形变换和样式。在新的环境里进行一系列环境里的方法。

ctx.restore()恢复保存环境之前的环境。一起成对出现


18.canvas线性渐变

ctx.createLinearGradient(x1,y1,x2,y2)创建线性渐变曲线的线条

ctx.createLinearGradient(x1,y1,x2,y2).addColorStop(百分比,'#ffffff')在百分比的时候是color颜色

使ctx.fillStyle等于该渐变值,最后使用ctx.fill()进行填充即可

var linearGradient=ctx.createLinearGradient(50,50,120,120);
    linearGradient.addColorStop(0,'#0f0');
    linearGradient.addColorStop(1,'#f00');
    ctx.fillStyle=linearGradient;
    ctx.fillRect(0,0,200,200)
    ctx.fill()


19.canvas径向渐变

ctx.createRadialGradient(x1,y1,r1,x2,y2,r2)径向渐变(两个圆的坐标点和半径)

ctx.createRadialGradient(x1,y1,r1,x2,y2,r2).addColorStop(百分比,'#ffffff')在百分比的时候是color颜色

使ctx.fillStyle等于该渐变值,最后使用ctx.fill()进行填充即可

 var RadiaColor=ctx.createRadialGradient(400,150,0,400,150,100);
        RadialColor.addColorStop(0,'#ffb472');
        RadialColor.addColorStop(0.5,'#ffbfc6');
        RadialColor.addColorStop(1,'#b0d6e4');
        ctx.beginPath();
        ctx.fillStyle=RadialColor
        ctx.arc(400,150,100,0,2*Math.PI,false);
        ctx.fill()


20.canvas绘制文本

ctx.font="fontWeight fontSize  fontFamily "(先后顺序不能变)
ctx.textAlign="start | center | end"
ctx.textBaseline="top | hanging | middle | alphabetic | ideographic | bottom"
ctx.fillText(string,x,y)文字填充
ctx.strokeText(string,x,y)文字描边
ctx.measureText(str).width文本宽度

21.导入图片drawImage(img,x,y,width,height)

drawImage() 方法的这种调用方式总共需要传入 9 个参数:要绘制的图像、源图像的 x 坐标、源图像的 y 坐标、源图像的宽度、源图像的高度、目标图像的 x 坐标、目标图像的 y 坐标、目标图像的宽度、目标图像的高度。这样调用drawImage() 方法可以获得最多的控制

var img=new Image();
img.src='';
一定要在图像加载完成后的回调中绘制图像
img.onload=function(){
  //在(0,0)处绘制img图像,缩放成width*height
  ctx.drawImage(img,0,0,width,height)
  //获取img图像的(0,0)处的width*height区域,绘制在(100,100)点处,缩放成(80,80)
  ctx.drawImage(img,0,0,width,height,100,100,80,80)
}


22.canvas背景图片填充(图形画刷):ctx.createPattern(img,'repeat'),

第二个参数有四个值:repeat,no-repeat,repeat-x,repeat-y

var img =new Image();
img.src='1.jpg';
img.onload=function(){
  var pattern=ctx.createPattern(img,'repeat');
  ctx.fillStyle=pattern;
  ctx.fillRect(0,0,canvas.width,canvas.height)
}


23.canvas区域剪辑:ctx.clip()


ctx.arc(400,400,200,0,2*Math.PI,true);
//在后面的都会裁剪,除非设置save()区域
ctx.clip()
ctx.fillStyle='red'
ctx.fillRect(200,200,200,200)

24.canvas阴影:

ctx.shadowColor :用 CSS 颜色格式表示的阴影颜色,默认为黑色。

ctx.shadowOffsetX :形状或路径 x 轴方向的阴影偏移量,默认为 0。

ctx.shadowOffsetY :形状或路径 y 轴方向的阴影偏移量,默认为 0。

ctx.shadowBlur :模糊的像素数,默认 0,即不模糊。

这些属性都可以通过 context 对象来修改。只要在绘制前为它们设置适当的值,就能自动产生阴影。


25.canvas合成:globalAlpha 和 globalCompositionOperation

 globalAlpha 是一个介于 0 和 1 之间的值(包括 0和 1),用于指定所有绘制的透明度。默认值为 0。

 如果所有后续操作都要基于相同的透明度,就可以先把 globalAlpha 设置为适当值,然后绘制,最后再把它设置回默认值 0。

第二个属性 globalCompositionOperation 表示后绘制的图形怎样与先绘制的图形结合。这个属性的值是字符串,可能的值如下。

 source-over (默认值):后绘制的图形位于先绘制的图形上方。

 source-in :后绘制的图形与先绘制的图形重叠的部分可见,两者其他部分完全透明。

 source-out :后绘制的图形与先绘制的图形不重叠的部分可见,先绘制的图形完全透明。

 source-atop :后绘制的图形与先绘制的图形重叠的部分可见,先绘制图形不受影响。

 destination-over :后绘制的图形位于先绘制的图形下方,只有之前透明像素下的部分才可见。

 destination-in :后绘制的图形位于先绘制的图形下方,两者不重叠的部分完全透明。

 destination-out :后绘制的图形擦除与先绘制的图形重叠的部分。

 destination-atop :后绘制的图形位于先绘制的图形下方,在两者不重叠的地方,先绘制的图形会变透明。

 lighter :后绘制的图形与先绘制的图形重叠部分的值相加,使该部分变亮。

 copy :后绘制的图形完全替代与之重叠的先绘制图形。

 xor :后绘制的图形与先绘制的图形重叠的部分执行“异或”操作。



26.清除画布:ctx.clearRect(0,0,canvas.width,canvas.height)



27.canvas动画:使用定时器和清除画布、事件实现canvas动画

  var x=150,y=0,isxy=1
  setInterval(function(){
      y += isxy*10;
      ctx.clearRect(0,0,canvas.width,canvas.height)
      ctx.fillRect(x,y,50,50);
      ctx.fillStyle='green';
      ctx.fill()
      if(y+50>=canvas.height){
          isxy=-1
      }else if(y<=0){
          isxy=1
      }
  },10)


28.离屏canvas技术(提高性能的一种技术方法)

  1、创建离屏canvas,设置display:none样式

  2、在js里对离屏canvas进行绘制

  3、绘制成功后使用ctx.drawImage(offCanvas,0,0,offCanvas.width,offCanvas.height,0,0,canvas.width,canvas.height)导入离屏canvas

  4、over




实操:使用canvas做了一个手机解锁功能

js基础之canvas绘图技术

html:

<script src="js.js"></script>
<script>
    new canvasLock({chooseType:3}).init()
</script>

javascript:

(function(){
  
    // 传入自定义宽高对象
    window.canvasLock=function(obj){
        this.width=obj.width
        this.height=obj.height
        this.chooseType=obj.chooseType
    }
    canvasLock.prototype.init=function(){
      this.initDom();
      var canvas=document.querySelector('#canvas');
      this.ctx=canvas.getContext('2d');
      this.touchFlag=false
      // 1确定圆的半径和圆心坐标
      // 2一行3个圆14个半径,一行4个圆18个半径
      this.createCircle()

      // 实现画圆和划线
      this.bindEvent()
  }

    canvasLock.prototype.initDom=function(){
        var wrap=document.createElement('div');
        var str="<h3 class='title' id='title'> 绘制解锁图案</h3>";
        wrap.setAttribute('style','text-align:center')

        var canvas=document.createElement('canvas');

        var width=this.width || 300
        var height=this.height || 300
        canvas.setAttribute('width',width+'px')
        canvas.setAttribute('height',height+'px')
        canvas.setAttribute('id','canvas')
        wrap.innerHTML=str;
        wrap.appendChild(canvas)
        document.body.appendChild(wrap) 
    }

    canvasLock.prototype.drawCle=function(x,y){
        this.ctx.strokeStyle='orange'
        this.ctx.lineWidth=2
        this.ctx.beginPath()
        this.ctx.arc(x,y,this.r,0,2*Math.PI,true)
        this.ctx.stroke()
    }
    canvasLock.prototype.createCircle=function(){
        var n=this.chooseType
        var count=0
        // 圆半径的计算
        this.r=this.ctx.canvas.width/(2+4*n)
        this.lastPoint=[];
        this.arr=[];
        this.restPoint=[]
        var r =this.r
        for(var i=0;i<n;i++){
            for(var j=0;j<n;j++){
                count++
                var obj={
                    // x:3*r*(i+1),
                    // y:3*r*(j+1),
                    x:j*4*r+3*r,
                    y:i*4*r+3*r,
                    
                    index:count
                }
                this.arr.push(obj)
                // 初始值是9个,一旦当画了实心圆,restPoint是剩下的圆个数
                this.restPoint.push(obj)
            }
        }
        console.log(this.arr,'点')
        this.ctx.clearRect(0,0,this.ctx.canvas.width,this.ctx.canvas.height)
        for(var k=0;k<this.arr.length;k++){
            // 画圆函数
            this.drawCle(this.arr[k].x,this.arr[k].y)
        }
        
    }
    /*
    * 实现画圆和划线
    * 1、添加事件touchstart、touchmove、touchend
    * 2、touchstart判断是否点击的位置处于圆内getPosition,处于则初始化lastPoint,restPoint
    * 3、touchmove做的就是:画圆drawPoint和划线drawLine
    */
    canvasLock.prototype.bindEvent=function(){
        var self=this
        console.log(this.ctx.canvas)
        this.ctx.canvas.addEventListener("touchstart",function(e){
            // po有两个值,并且相较于canvas的边距
            var po = self.getPosition(e)
            // 判断是否在圆内的原理:多出来的这条x/y < r 在圆内
            for(var i=0;i<self.arr.length;i++){
                if(Math.abs(po.x-self.arr[i].x)<self.r && Math.abs(po.y-self.arr[i].y)<self.r){
                    self.touchFlag=true;
                    // lastPoint存放的是选中圆的圆心坐标
                    self.lastPoint.push(self.arr[i]);
                    self.restPoint.splice(i,1);
                    console.log(self,'圆内')
                    break;
                    
                }
            }

        },false)
        // touchmove做的就是:画圆drawPoint和划线drawLine
        this.ctx.canvas.addEventListener("touchmove",function(e){
            if(self.touchFlag){
                self.update(self.getPosition(e))
            }
            console.log('touchmove')
        },false)

         
        this.ctx.canvas.addEventListener("touchend",function(e){
          if(self.touchFlag){
            self.storePass(self.lastPoint);
            setTimeout(()=>{
              self.reset()
            },300)
          }
            console.log('touchend')
        },false)
    }

    // 画圆内的小圆
    canvasLock.prototype.update=function(po){
        this.ctx.clearRect(0,0,this.ctx.canvas.width,this.ctx.canvas.height)
        for(var k=0;k<this.arr.length;k++){
            // 画圆函数
            this.drawCle(this.arr[k].x,this.arr[k].y)
        }
        // 画圆
        this.drawPoint();
        // 划线
        this.drawLine(po);

        /**
         * 实现自动画圆的效果
         * 1、检测手势移动的位置是否处于圆内
         * 2、如果在圆内则画圆
         * 3、已经画过的圆无需再次绘画
         */
        for(var i=0;i<this.restPoint.length;i++){
          if(Math.abs(po.x-this.restPoint[i].x)<this.r && Math.abs(po.y-this.restPoint[i].y)<this.r){
              this.drawPoint()
              
              // lastPoint存放的是选中圆的圆心坐标
              this.lastPoint.push(this.restPoint[i]);
              this.restPoint.splice(i,1);
              break;
              
          }
      }

    }
    canvasLock.prototype.drawPoint=function(){
      for(var i=0;i<this.lastPoint.length;i++){
        this.ctx.beginPath();
        this.ctx.strokeStyle='slateblue';
        this.ctx.fillStyle='slateblue';
        this.ctx.arc(this.lastPoint[i].x,this.lastPoint[i].y,this.r/2,0,2*Math.PI,true);
        this.ctx.fill()
        this.ctx.stroke()
      }
      
    }
    canvasLock.prototype.drawLine=function(po){
        this.ctx.beginPath();
        this.ctx.linewidth=3
        this.ctx.moveTo(this.lastPoint[0].x,this.lastPoint[0].y);
        for(var i=0;i<this.lastPoint.length;i++){
          this.ctx.lineTo(this.lastPoint[i].x,this.lastPoint[i].y);
        }
        this.ctx.lineTo(po.x,po.y)
        this.ctx.stroke();

    }
    // 获取鼠标/手势坐标
    canvasLock.prototype.getPosition=function(e){
        // getBoundingClientRect 用于获取元素相对于浏览器窗口的位置 
        // 拿到canvas距离浏览器窗口的值
        var rect=e.currentTarget.getBoundingClientRect();
        console.log(rect)
        var po={
            x:e.touches[0].clientX-rect.left,
            y:e.touches[0].clientY-rect.top,           
        }
        console.log(po)
       return po
    }
    
    /** 
     * 实现解锁成功
     * 1、检测路径是否是对的
     * 2、如果是对的就重置,圆圈变绿
     * 3、不对也重置,颜色变红
     * 4、重置
     */
    canvasLock.prototype.storePass=function(){
      if(this.checkPass()){
        document.getElementById('title').innerHTML='解锁成功'
        this.drawStatusPoint('#2cff26');
      }else{
        document.getElementById('title').innerHTML='解锁失败'
        this.drawStatusPoint('red')
      }
    }

    canvasLock.prototype.checkPass=function(){
      //自定义正确的解锁路径
        var p1='123',
        p2='';
        for(var i=0;i<this.lastPoint.length;i++){
          p2+=this.lastPoint[i].index;
        }
        console.log(p2,'p2');
        // debugger
        return p1 === p2
    }

    canvasLock.prototype.drawStatusPoint=function(type){
      for(var i=0;i<this.lastPoint.length;i++){
        this.ctx.strokeStyle=type
        this.ctx.beginPath();
        this.ctx.arc(this.lastPoint[i].x,this.lastPoint[i].y,this.r,0,2*Math.PI,true)
        this.ctx.stroke()
      }
    }

    // 重置
    canvasLock.prototype.reset=function(){
      // debugger
      document.getElementById('title').innerHTML='绘制解锁图案'
      this.createCircle()
    } 
})()


标签: javascript
分享给朋友:

相关文章

前端入门html、css、js知识汇总(1)

前端入门html、css、js知识汇总(1)

注:本文适合需要一点前端知识,如有不懂自行百度或去W3C官网、去菜鸟教程查询1.html不需要编译,直接由浏览器执行   html文件时一个文本文件   h...

es6入门之环境搭建

es6入门之环境搭建

话不多说,首先我也是先学习了然后再总结的。es6入门——es6环境的搭建(原文有个错误,把cmd说成是控制台,以至于评论区有个新手没理解到意思,控制台是浏览器的console,cmd是输入命令行执行的...

使用rem做手机端网页自适应

使用rem做手机端网页自适应

利用原生js做手机端网页自适应解决方案rem布局刚开始我用的是下面这段代码,然后js通过外部链接引入,最后每次用手机刷新网页的时候都会出现缩略图function getRem(pwidth,...

SEO搜索引擎工作原理

SEO搜索引擎工作原理

一、搜索引擎工作原理  当我们在输入框中输入关键词,点击搜索或查询时,然后得到结果。深究其背后的故事,搜索引擎做了很多事情。  在搜索引擎网站,比如百度,在其后台有一个非常庞大的数据库,里面存储了海量...

CSS Flex 盒布局教程

CSS Flex 盒布局教程

参考文章:A Visual Guide to CSS3 Flexbox Properties,W3C CSS Flexible Box Layout Module Level,Flex 布局教程:语法...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

分享:

支付宝

微信