美文网首页
canvas常用API 总结

canvas常用API 总结

作者: infi_ | 来源:发表于2018-07-08 15:52 被阅读0次

    getContext 获取canvas绘图的上下文环境
    之后在绘图环境上有以下API
    lineJoin 线头线尾的形状 round为圆角
    lineWidth 线的宽度
    font 设置字体
    fillText 填充文字 第一个参数是文本 第二个参数是X坐标,第三个参数是Y坐标
    strokeRect 空心矩形,接收四个参数
    fillStyle 填充样式 可以接受rgba或渐变
    渐变例子

    var gradient=can2_context.createLinearGradient(0,500,0,700);
    gradient.addColorStop(0,'blue')
    gradient.addColorStop(0.25,'white')
    gradient.addColorStop(1,'blue')
    can2_context.fillStyle=gradient;
    can2_context.fillRect(0,500,canvas_2.width,700)
    

    createLinearGradient的四个参数表示渐变的方向 0,500,0,700表示的是垂直方向渐变
    addColorStop 第一个参数填0~1之间的数 第二个参数添颜色
    fillRect 实心矩形


    放射性渐变
    这里用到了createRadialGradient这个API 这个API接收6个参数,前三个表示底下的圆,后三个表示上面的圆,返回的实例依然可以用addColorStop

    function Radia(bottom_x,bottom_y,bottom_r,top_x,top_y,top_r){
      this.bottom_x=bottom_x;
      this.bottom_y=bottom_y;
      this.bottom_r=bottom_r;
      this.top_x=top_x;
      this.top_y=top_y;
      this.top_r=top_r;
      this.gradient=can2_context.createRadialGradient(this.bottom_x,this.bottom_y,this.bottom_r,this.top_x,this.top_y,this.top_r)
    }
    Radia.prototype.addColor=function(){
      
      for(var i=0;i<arguments.length;i++){
        this.gradient.addColorStop(arguments[i].num,arguments[i].color)
     }
    
    }
    Radia.prototype.draw=function(x1,y1,x2,y2){
       can2_context.fillStyle=this.gradient;
       can2_context.fillRect(x1,y1,x2,y2)
    }
    
    var some1=new Radia(canvas_2.width/2, canvas_2.height-100, 0, canvas_2.width/2, 0, 300)
    some1.addColor({num:0.2,color:"blue"},{num:1,color:"yellow"},{num:0.7,color:"white"})
    some1.draw(0, 0, canvas_2.width, canvas_2.height) 
    

    图像填充 createPattern
    图像填充也是一种fillStyle
    该方法的第一个参数指定了图案所用图像,它可以是images元素,canvas元素或者video元素.第2个参数告诉浏览器,对图形进行扫描或填充时,应该如何重复该图案,这个参数的有效值是repeat,repeat-x,repeat-y,no-repeat

    var canvas_2=document.getElementById("canvas_2");
    var can2_context=canvas_2.getContext("2d");
    var img=new Image();
    img.src='./images/hover2.png'
    
    function fillimage(){
        var pattern=can2_context.createPattern(img,'no-repeat')
        can2_context.fillStyle=pattern;
        can2_context.fillRect(0,0,canvas_2.width,canvas_2.height)
        
    
    }
    img.onload=function(e){
      fillimage()
    }
    

    canvas阴影
    尽量不要用canvas做出阴影 因为效率并不是那么高

    shadowBlur表示阴影效果如何延伸double值。浏览器在阴影智商运用高斯模糊时,将会用到该值,它与像素无关,只会被用到高斯模糊方程之中,其默认值为0
    shadowColor CSS格式的颜色字符串,默认值是rgba(0,0,0,0)
    shadowOffsetX 阴影在X轴方向的偏移量,以像素为单位,默认值为0
    shadowOffsetY 阴影在Y轴方向的偏移量,以像素为单位,默认值是0

    var canvas_2=document.getElementById("canvas_2");
    var can2_context=canvas_2.getContext("2d");
    
    var SHADOW_COLOR='rgba(0,0,0,0.7)'
    function setShadow(){
      can2_context.shadowColor=SHADOW_COLOR;
      can2_context.shadowOffsetX=3;
      can2_context.shadowOffsetY=3; 
      can2_context.shadowBlur=5
    }
    setShadow();
    can2_context.fillStyle="blue"
    can2_context.fillRect(0,0,100,100)
    

    关于beginPath

    can2_context.beginPath();
     can2_context.rect(10,10,100,100)
     can2_context.stroke();
    
    //  can2_context.beginPath()
     can2_context.rect(50,50,100,100)
     can2_context.stroke()
    

    先调用beginPath()来清楚当前路径中的所有子路径,然后调用rect()来创建一条包含矩形4个点的子路径,再调用stroke()方法使得这个矩形出现在canvas上。
    接下来这段代码再次调用rect()方法,不过这一次,由于没有调用beginPath()方法清除原有的路径,所以第二次对rect()的方法的调用,会向当前中增加一条子路径。最后该段代码再一次调用stroke()方法。这次stroke()方法的调用,将会使得当前路径中的两条子路径都被描边,这意味着它会重绘第一个矩形


    关于非零环绕原则

    “非零环绕规则”是这么来判断有自我交叉情况的路径的:
    对于路径中的任意给定区域,从该区域内部画一条足够长的线段
    使此线段的终点完全落在路径范围之外。
    接下来,将计数器初始化为0,然后,每当这条线段与路径上的直线或曲线相交时,就
    改变计数器的值。如果是与路径顺时针部分相交,则加1,如果是与路径逆时针部分相交就
    减一。若计数器的最终值不是0,那么此区域就在路径里面,在调用fill()方法时,浏览器就会对其进行填充。如果最终值是0,那么此区域就不在路径内部,浏览器也就不会对其进行填充


    剪纸漏洞效果主要是利用了canvas的非零环绕规则
    简单来说就是canvas fill填充的是同一路径顺时针和逆时针中间的部分,简称
    非零环绕

    var canvas_2=document.getElementById("canvas_2");
    var can2_context=canvas_2.getContext("2d");
    var width_2=canvas_2.width
    var height_2=canvas_2.height
    var testx=300
    var testy=300
    function drawCutouts(){
    
        can2_context.beginPath();
        addOurterRectanglePath()
        addrect()
        addTrianglePath()
        addarc()
        can2_context.fill()
    }
    
    function addOurterRectanglePath(){
         can2_context.rect(110,25,370,335)
         can2_context.closePath()
    }
    
    
    function rect(x,y,w,h,direction){
    
        if(direction){
            can2_context.moveTo(x,y);
            can2_context.lineTo(x,y+h)
            can2_context.lineTo(x+w,y+h)
            can2_context.lineTo(x+w,y)
        }else{
            can2_context.moveTo(x,y)
            can2_context.lineTo(x+w,y)
            can2_context.lineTo(x+w,y+h)
            can2_context.lineTo(x,y+h)
    
        }
        can2_context.closePath()
    }
    function addrect(){
        rect(310,55,70,35,true)  //true为逆时针
    }
    function addTrianglePath(){
       
       can2_context.moveTo(400,200)
       can2_context.lineTo(250,115)
       can2_context.lineTo(200,200)
       can2_context.closePath()
    
    }
    
    
    
    function addarc(){
        if(testy>335){testy=25}
        testy=testy+1
        
        can2_context.arc(testx,testy,40,0,Math.PI*2,true)
       
    }
    
    function hi(){
       can2_context.clearRect(0,0,width_2,height_2)
       drawCutouts()
    
       requestAnimationFrame(hi)
    
    }
    hi()
    

    getBoundingClientRect,getImageData,putImageData
    //getBoundingClientRect 返回元素的6个值 left top right bottom width height
    注意这里的left top right bottom 都是相对于可视窗口的左上角的
    width是元素的宽度
    height是元素的高度
    var bbox=canvas.getBoundingClientRect()
    bbox.left

    bbox.right

    //getImageData() 方法返回 ImageData 对象,该对象拷贝了画布指定矩形的像素数据。
    //context.getImageData(0,0,canvas.width,canvas.height)

    //putImageData() 方法将图像数据(从指定的 ImageData 对象)放回画布上。
    //context.putImageData(drawingSurfaceImageData,0,0)


    canvas橡皮筋式线段绘制

    context.save() 设置绘图环境存档
    context.restore() 读取绘图环境存档
    Math.abs()求绝对值

    var canvas=document.getElementById("canvas"),
       context=canvas.getContext("2d"),
       eraseAllButton=document.getElementById("eraseAllButton"),
       strokeStyleSelect=document.getElementById("strokeStyleSelect"),
       guidewireCheckbox=document.getElementById("guidewireCheckbox"),
       drawingSurfaceImageData,
       mousedown={},
       rubberbandRect={},
       dragging=false,
       guidewires=guidewireCheckbox.checked;
    
    
        function windowToCanvas(x,y){
            var bbox=canvas.getBoundingClientRect()//getBoundingClientRect 返回元素的6个值 left top right bottom width height
         
            return {
                x:x-bbox.left*(canvas.width/bbox.width),
                y:y-bbox.top*(canvas.height/bbox.height)
            }
        }
    
        function saveDrawingSurface(){
            drawingSurfaceImageData=context.getImageData(0,0,canvas.width,canvas.height) 
         //getImageData() 方法返回 ImageData 对象,该对象拷贝了画布指定矩形的像素数据。
        }
        
        function restoreDrawingSurface(){
            context.putImageData(drawingSurfaceImageData,0,0)
            //putImageData() 方法将图像数据(从指定的 ImageData 对象)放回画布上。
        }
    
       function updateRubberbandRectangle(loc){
           rubberbandRect.width=Math.abs(loc.x-mousedown.x)  //用绝对值求线段的长度
           rubberbandRect.height=Math.abs(loc.y-mousedown.y)  //用绝对值求线段的高度
    
           if(loc.x>mousedown.x){rubberbandRect.left=mousedown.x}else{
               rubberbandRect.left=loc.x
           }
           if(loc.y>mousedown.y){rubberbandRect.top=mousedown.y}else{
               rubberbandRect.top=loc.y
           }
       }
       function drawRubberbandShape(loc){
    
           context.beginPath()
           context.moveTo(mousedown.x,mousedown.y)
           context.lineTo(loc.x,loc.y)
           context.stroke()
       }
       function updataRubberband(loc){  //loc是鼠标点在canvas上的坐标集合对象
          // updateRubberbandRectangle(loc)
           drawRubberbandShape(loc)
       }
    //这三个函数式辅助线函数
       function drawHorizontalLine(y){
           context.beginPath()
           context.moveTo(0,y+0.5)
           context.lineTo(context.canvas.width,y+0.5)
           context.stroke()
       }
       function drawVerticalLine(x){
           context.beginPath()
           context.moveTo(x+0.5,0)
           context.lineTo(x+0.5,context.canvas.height)
           context.stroke()
    
       }
       function drawGuidewires(x,y){
           context.save()
           context.strokeStyle="rgba(0,0,230,0.4)"
           context.lineWidth=0.5;
           drawVerticalLine(x)
           drawHorizontalLine(y)
           context.restore()
       }
    //这三个函数式辅助线函数
       canvas.onmousedown=function(e){  //只执行一次
         var loc=windowToCanvas(e.clientX,e.clientY); //获取鼠标点在canvas的点坐标
         e.preventDefault();
         saveDrawingSurface()                         //复制canvas画布的像素
         mousedown.x=loc.x;                          //鼠标点击的x轴坐标  这里mousedown记录的是初始位置
         mousedown.y=loc.y;                          //鼠标点击的y轴坐标   这里mousedown记录的是初始位置
         dragging=true;
     }
    canvas.onmousemove=function(e){
           var loc;
           if(dragging){
               e.preventDefault()
               loc=windowToCanvas(e.clientX,e.clientY);
               restoreDrawingSurface()
               updataRubberband(loc)  //loc是鼠标点在canvas上的坐标集合对象
               if(guidewires){        //辅助线
                   drawGuidewires(loc.x,loc.y)
               }
           }
       }
       canvas.onmouseup=function(e){
           loc=windowToCanvas(e.clientX,e.clientY)
           restoreDrawingSurface()
           updataRubberband(loc)
           dragging=false
       }
       strokeStyleSelect.onchange=function(){
    
           context.strokeStyle=strokeStyleSelect.value
       }
    

    三次方贝塞尔曲线的绘制

    bezierCurveTo
    创建一条代表三次方贝塞尔曲线的路径。你需要向该方法传入三个点的坐标
    ,前两个点是该曲线的控制点,最后一个是锚点


    canvas画多边形

    由于canvas只提供了画矩形和圆形的方法,
    所以涉及到多边形的话,只能自己写方法
    其中涉及到 三角函数的API 比如
    Math.PI圆周率
    Math.sin
    Math.cos
    这俩就不多介绍了 sin cos 中学学的
    大致思路就是只要有中心点 半径 就可以想画几边形就画几边形,
    废话不多说,上代码

    var canvas=document.getElementById("canvas");
    var context=canvas.getContext("2d");
    
    var Point = function (x, y) {
       this.x = x;
       this.y = y;
    };
    
    var Polygon=function(centerX,centerY,radius,sides,startAngle,strokeStyle,fillStyle,filled){
    
        this.x=centerX;
        this.y=centerY;
        this.radius=radius;
        this.sides=sides;
        this.startAngle=startAngle;
        this.strokeStyle=strokeStyle;
        this.fillStyle=fillStyle;
        this.filled=filled;
    }
    Polygon.prototype={
       getPoints:function(){
         var points=[];
         var angle=this.startAngle||0;
         for(var i=0;i<this.sides;i++){
             points.push(new Point(this.x+this.radius*Math.cos(angle),this.y-this.radius*Math.sin(angle)))
             angle+=2*Math.PI/this.sides
    
         }
        return points
    
       },
       createPath:function(){
          var points=this.getPoints()
          context.beginPath()
          context.moveTo(points[0].x,points[0].y);
          for(var i=1;i<points.length;i++){
              context.lineTo(points[i].x,points[i].y)
          }
          context.closePath()
       },
       stroke:function(){
           context.save()
           this.createPath()
           context.strokeStyle=this.strokeStyle;
           context.stroke();
           context.restore();
       },
       fill:function(){
          context.save();
          context.fillStyle=this.fillStyle;
          this.createPath()
          context.fill()
          context.restore()
    
       },
    
       move: function (x, y) {
              this.x = x;
               this.y = y;
        }
    
    }
    var test1=new Polygon(50,50,30,8,0,"red","red")
    test1.stroke()
    
    var test2=new Polygon(150,150,30,4,0,"red","red")
    test2.fill()
    
    

    isPointInPath
    isPointInPath表示某个点在当前路径中就会返回true 反之返回false

    var edite=false
    var mousedown={}//记录鼠标按下起始点
    var imageData1=null;
    var mouseIn=null;//记录鼠标是否按了下去
    var line_list={} //记录鼠标的终点
    
    var Graphical=[];//存放图形引用的数组
    var edit_list={}//记录在编辑模式下按的点
    var map_name=null//每个生成图形的名称
    var foucsIndex=null //被选中移动图形的下标
    
    
    function saveImage(){  //储存此刻画布数据
          imageData1= context.getImageData(0,0,canvas.width,canvas.height)
    }
    function loadingImage(){ //导入画布数据
      context.putImageData(imageData1,0,0)
    }
    
    
    
    editCheckbox.onchange=function(){
      if(this.checked){
       console.log("进入编辑模式")
       edite=true
      }else{
       console.log("进入画图模式")
       edite=false
      }
    
    }
    
    function windowToCanvas(event){  //算出你点击在canvas画布的坐标 并返回
       var rect=canvas.getBoundingClientRect()
       return {
          x:event.clientX-rect.left,
          y:event.clientY-rect.top
       } 
    }
    function line_width(){
      var x_width=Math.abs(line_list.x-mousedown.x)
      var y_width=Math.abs(line_list.y-mousedown.y)
      
      return Math.sqrt(x_width*x_width+y_width*y_width) 
    }
    
    
    
    canvas.onmousedown=function(event){
        saveImage()
        var some=windowToCanvas(event)
       
        mousedown.x=some.x;
        mousedown.y=some.y
        
        mouseIn=true
        
        Graphical.forEach(function(el,index){
            el.createPath(context)
            if(context.isPointInPath(mousedown.x,mousedown.y)){
                edit_list.x=some.x;
                edit_list.y=some.y
                foucsIndex=index
             
            }
    
       
        })
       
    }
    canvas.onmousemove=function(event){
    
         if(mouseIn&&edite){//如果按下鼠标并拖行 如果是编辑模式
            loadingImage()
               
                
                var offset_list=windowToCanvas(event);
                var offsetX=offset_list.x-edit_list.x;
                var offsetY=offset_list.y-edit_list.y;
                context.clearRect(0,0,canvas.width,canvas.height)
                Graphical[foucsIndex].move(mousedown.x+offsetX,mousedown.y+offsetY)
                Graphical.forEach(function(el){
                    el.createPath(context)
                    el.fill(context)
                })
         } 
    
    
      
        if(mouseIn&&!edite){//如果按下鼠标并拖行 如果不是编辑模式
            loadingImage()
            line_list=windowToCanvas(event)
            context.beginPath()
    
            var r=line_width()
    
            map_name=new Polygon(mousedown.x,mousedown.y,r,sidesSelect.value,0,"red","red")
            map_name.fill(context)
       
            
        }
    }
    
    canvas.onmouseup=function(){
    
    
        mouseIn=false //鼠标抬起来了
        if(!edite){
            Graphical.push(map_name)
        }
    
    }
    

    globalCompositeOperation
    利用修改globalCompositeOperation改变canvas图像默认合成行为
    <select name="" id="compositingSelect" size="11">
    <option value="source-atop">source-atop</option>
    <option value="source-in">source-in</option>
    <option value="source-out">source-out</option>
    <option value="source-over">source-over</option>
    <option value="destination-atop">destination-atop</option>
    <option value="destination-in">destination-in</option>
    <option value="destination-out">destination-out</option>
    <option value="destination-over">destination-over</option>
    <option value="lighter">lighter</option>
    <option value="copy">copy</option>
    <option value="xor">xor</option>
    </select>

    11个合成行为


    clip()剪切区域

    这里有个坑要十分注意 调用clip()方法的时候,所定义的剪辑区域总是局限于期初的那个剪辑区域范围。
    简单来说 clip()方法总是在上一次的剪辑区域基础上进行操作,所以说我们要把clip()方法放在save()和restore()方法中
    clip 是对已有路径的剪切

    var canvas=document.getElementById("canvas")
    var context=canvas.getContext("2d")
    
    function windowToCanvas(x,y){
    
        var bbox=canvas.getBoundingClientRect()
        return {
            x:x-bbox.left,
            y:y-bbox.top
        }
    }
    
    function drawText(){
    
        context.save()
        context.shadowColor="rgba(100,100,150,0.8)"
        context.shadowOffsetX=5;
        context.shadowOffsetY=5;
        context.shadowBlur=10;
    
        context.fillStyle="cornflowerblue"
        context.fillText("HTML5",20,250)
        context.strokeStyle="yellow"
        context.strokeText("HTML5",20,250)
        context.restore()
    
    }
    
    function setClippingRegion(radius){
        context.beginPath()
        context.arc(canvas.width/2,canvas.height/2,radius,0,Math.PI*2,false)
        context.clip()
    }
    
    function fillCanvas(color){
        context.fillStyle=color
        context.fillRect(0,0,canvas.width,canvas.height)
    }
    
    function endAnimation(loop){
    
        clearInterval(loop)
        setTimeout(function(e){
            context.clearRect(0,0,canvas.width,canvas.height)
            drawText()
        },1000)
    }
    
    function drawAnimationFrame(radius){
       setClippingRegion(radius);
       fillCanvas('lightgray')
       drawText()
    
    }
    function animate(){
       var radius=canvas.width/2,
           loop;
        loop=window.setInterval(function(){
            radius-=canvas.width/100
            fillCanvas('charcoal')
            if(radius>0){
                context.save()
                drawAnimationFrame(radius)
                context.restore()
            }else{
                endAnimation(loop)
            }
        },16)   
    
    }
    
    canvas.onmousedown=function(){
        animate()
    }
    context.lineWidth=0.5
    context.font='128pt Comic-sans'
    drawText()
    

    canvas制造渐变和图案填充文字.

    这里主要是利用了 context的createPattern的方法
    这个方法接受两个参数 第一个参数是要填充的图案,第二个参数是图案重复方式

    制造颜色渐变的方法是createLinearGradient

    var canvas=document.getElementById("canvas")
    var context=canvas.getContext("2d")
    var image=new Image();
    var gradient=context.createLinearGradient(0,0,canvas.width,canvas.height)
    var text="Canvas"
    var pattern;
    function drawGradientText(){
      context.fillStyle=gradient
      context.fillText(text,65,200)
      context.strokeText(text,65,200)
    
    }
    function drawPatternText(){
        context.fillStyle=pattern
        context.fillText(text,65,450)
        context.strokeText(text,65,450)
    }
    image.onload=function(e){
        pattern=context.createPattern(image,"repeat")
        drawPatternText()
    }
    image.src="./images/hover2.png"
    context.font="256px Palation"
    context.strokeStyle="cornflowerblue"
    
    
    
    context.shadowColor="rgba(100,100,150,0.8)"
    context.shadowOffsetX=5
    context.shadowOffsetY=5
    context.shadowBlur=10
    
    gradient.addColorStop(0,"blue")
    gradient.addColorStop(0.25,"blue")
    gradient.addColorStop(0.5,"white")
    gradient.addColorStop(0.75,'red')
    gradient.addColorStop(1.0,'yellow')
    
    drawGradientText()
    

    canvas在圆弧周围绘制文本的两种写法

        var canvas=document.getElementById("canvas")
        var context=canvas.getContext("2d")
    
        var TEXT_FILL_STYLE="rgba(100,130,240,0.5)"
        var TEXT_STROKE_STYLE="rgba(200,0,0,0.7)"
        var TEXT_SIZE=64;
        circle={
            x:canvas.width/2,
            y:canvas.height/2,
            radius:200
        }
        function drawCircularText(string,startAngle,endAngle){
          var radius=circle.radius //圆的半径
          var angleDecrement=(startAngle-endAngle)/(string.length-1)//每个字母占的弧度
          var angle=parseFloat(startAngle) //转一下数字
          var index=0;
          var character;
    
          context.save()
          context.fillStyle=TEXT_FILL_STYLE;
          context.strokeStyle=TEXT_STROKE_STYLE;
          context.font=TEXT_SIZE+"px Lucida Sans"
    
          while(index<string.length){
            character=string.charAt(index)
            context.save()
            context.beginPath()
            context.translate(circle.x+Math.cos(angle)*radius,circle.y-Math.sin(angle)*radius)
            context.rotate(Math.PI/2-angle)   //Math.PI/2为旋转90度  Math.PI/180*X为旋转多少度
            context.fillText(character,0,0)
            context.strokeText(character,0,0)
            angle-=angleDecrement
            index++
            context.restore()
    
          }
          context.restore()
    
    
    
    
        }
        context.textAlign="center"
        context.textBaseLine="middle"
       drawCircularText("clockwise around the circle",Math.PI*2,Math.PI/8)
    

    canvas实现图像的缩放

    这里需要注意的是如果你向canvas之中绘制的图像有一部分落在canvas之外,
    那么浏览器就会将canvas范围外的那部分图像忽略掉

    var canvas=document.getElementById("canvas")
    var context=canvas.getContext("2d")
    
    var image=new Image()
    var scaleSlider=document.getElementById("scaleSlider")
    var scale=1.0
    var MINIMUM_SCALE=1.0
    var MAXIMUN_SCALE=3.0
    
    function drawImage(){
     var w=canvas.width
     var h=canvas.height
     var sw=w*scale
     var sh=h*scale
     context.clearRect(0,0,canvas.width,canvas.height)
     context.drawImage(image,-sw/2+w/2,-sh/2+h/2,sw,sh)
    
    }
    function drawScaleText(value){
      var text=parseFloat(value).toFixed(2)
    
      scaleOutput.innerText=text
    
    
    
    }
    scaleSlider.onchange=function(e){
      scale=e.target.value
      if(scale<MINIMUM_SCALE){scale=MINIMUM_SCALE}
        else if(scale>MAXIMUN_SCALE){scale=MAXIMUN_SCALE}
          drawScaleText(scale)
        drawImage()
    
    }
    image.src="./timg.jpg"
    image.onload=function(e){
       drawImage()
       drawScaleText(scaleSlider.value)
    }
    

    利用离屏canvas提高复制图像放大的效率并添加水印

    <!DOCTYPE html>
    <html>
    <head>
        <title>图像与视频</title>
        <meta charset="utf-8">
        <style type="text/css">
      *{padding: 0;margin: 0}
      a{text-decoration: none}
      img{border: none}
      ul,ol{list-style: none}
      br{font-size: 0;line-height: 0;clear: both}
      body{text-align: center;background: rgba(100,145,250,0.3)}
      canvas{border: 1px solid blue}
      #scaleSlider{
        vertical-align: 10px;
        width: 100px;
        margin-left: 90px;
      }
      #canvas{
        margin:10px 20px 0px 20px;
        border: thin solid #aaaaaa;
        cursor:crosshair;
      }
      #controls{
        margin-left: 15px;
        padding: 0
      }
      #scaleOutput{
        position: absolute;
        width: 60px;
        height: 30px;
        margin-left: 10px;
        vertical-align: center;
        text-align:center;
        color: blue;
        font:18px Arial;
        text-shadow: 2px 2px 4px rgba(100,140,250,0.8)
      }
        </style>
    </head>
    <body>
    <div id="controls">
        <output id="scaleOutput">1.0</output>
        <input type="range" name="" id="scaleSlider" min="1" max="3.0" step="0.01" value="1.0">
    </div>
    <canvas id="canvas" id="canvas" width="454" height="512"></canvas>
    
    </body>
    </html>
    <script type="text/javascript">
    var canvas=document.getElementById("canvas")
    var context=canvas.getContext("2d")
    var offscreenCanvas=document.createElement("canvas")  //创建离屏canvas
    var offscreenContext=offscreenCanvas.getContext("2d")
    offscreenCanvas.width=canvas.width
    offscreenCanvas.height=canvas.height
    
    
    
    var image=new Image()
    var scaleSlider=document.getElementById("scaleSlider")
    var scaleOutput=document.getElementById("scaleOutput")
    
    //var scale=scaleSlider.value
    var scale=1.0
    var MINIMUM_SCALE=1.0
    var MAXIMUN_SCALE=3.0
    
    function drawScaled(){  //从离屏canvas复制过来图像并放大
      var w=canvas.width;
      var h=canvas.height;
      var sw=w*scale;
      var sh=h*scale;
    context.drawImage(offscreenCanvas,0,0,offscreenCanvas.width,offscreenCanvas.height,-sw/2+w/2,-sh/2+h/2,sw,sh)
    }
    function drawScaleText(value){  //显示放大倍率
    var text=parseFloat(value).toFixed(2) 
    scaleOutput.innerText=text
    
    }
    function drawWatermark(context){ //添加水印
      var lineOne='Copyright'
      var lineTwo='Acme Inc'
      var textMetrics
      var FONT_HEIGHT=128
      context.save()
      context.font=FONT_HEIGHT+"px Arial"
      textMetrics=context.measureText(lineOne)
      context.globalAlpha=0.6
      context.fillStyle="cornflowerblue"
      context.strokeStyle="yellow"
      context.shadowColor='rgba(50,50,50,1.0)'
      context.shaowOffsetX=5
    
      context.translate(canvas.width/2,canvas.height/2-FONT_HEIGHT/2)
      context.fillText(lineOne,-textMetrics.width/2,0)
      context.strokeText(lineOne,-textMetrics.width/2,0)
    
      textMetrics=context.measureText(lineTwo)
      context.fillText(lineTwo,-textMetrics.width/2,FONT_HEIGHT)
      context.strokeText(lineTwo,-textMetrics.width/2,FONT_HEIGHT)
    
      context.restore()
    }
    
    scaleSlider.onchange=function(e)
       scale=e.target.value
    
       if (scale<MINIMUM_SCALE){scale=MINIMUM_SCALE}
       else if(scale>MAXIMUN_SCALE){scale=MAXIMUN_SCALE}
       drawScaled()
       drawScaleText(scale)
    
    }
    
    image.src="./timg.jpg"
    image.onload=function(){
      context.drawImage(image,0,0,canvas.width,canvas.height)
      offscreenContext.drawImage(canvas,0,0,canvas.width,canvas.height)
      drawWatermark(context)
      drawWatermark(offscreenContext)
      drawScaleText(scale)
    
    }
    
    
    
    
    
    
    
    </script>
    

    利用离屏canvas 手动放大图片任意局部位置效果
    这里最重要的就是rubberbandEnd这个函数 它会判断鼠标从按下到松开 有没有位移过 如果没有就return 最后把离屏的图片选取局部复制到可见的canvas之中

    <!DOCTYPE html>
    <html>
    <head>
        <title>图像与视频</title>
        <meta charset="utf-8">
        <style type="text/css">
      *{padding: 0;margin: 0}
      a{text-decoration: none}
      img{border: none}
      ul,ol{list-style: none}
      br{font-size: 0;line-height: 0;clear: both}
      body{text-align: center;background: rgba(100,145,250,0.3)}
      canvas{border: 1px solid blue}
      #scaleSlider{
        vertical-align: 10px;
        width: 100px;
        margin-left: 90px;
      }
      #canvas{
        margin:10px 20px 0px 20px;
        border: thin solid #aaaaaa;
        cursor:crosshair;
      }
      #controls{
        margin-left: 15px;
        padding: 0
      }
      #scaleOutput{
        position: absolute;
        width: 60px;
        height: 30px;
        margin-left: 10px;
        vertical-align: center;
        text-align:center;
        color: blue;
        font:18px Arial;
        text-shadow: 2px 2px 4px rgba(100,140,250,0.8)
      }
        </style>
    </head>
    <body>
          <div id='controls'>
             <input type='button' id='resetButton' value='Reset'/>
          </div>
    <canvas id="canvas" id="canvas" width="454" height="512"></canvas>
    
    </body>
    </html>
    <script type="text/javascript">
    console.log("start")
    var canvas=document.getElementById("canvas")
    var context=canvas.getContext("2d")
    var offscreenCanvas=document.createElement("canvas")  //创建离屏canvas
    var offscreenContext=offscreenCanvas.getContext("2d")
    offscreenCanvas.width=canvas.width
    offscreenCanvas.height=canvas.height
    var mousedown={}
    var rubberbandRectangle={}
    var dragging=false;
    var start_data;
    
    
    context.fillStyle='rgba(155,187,89,0.3)'
    context.lineWidth=2
    function windowToCanvas(canvas,x,y){
      var bbox=canvas.getBoundingClientRect()
      return {
         x:x-bbox.left,
         y:y-bbox.top
      }
    
    
    }
    
    
    function rubberbandStretch(x,y){
    
       rubberbandRectangle.left=Math.min(x,mousedown.x)
       rubberbandRectangle.top=Math.min(y,mousedown.y)
       rubberbandRectangle.width=Math.abs(x-mousedown.x)
       rubberbandRectangle.height=Math.abs(y-mousedown.y)
    
       
       context.fillRect(rubberbandRectangle.left+context.lineWidth,
                        rubberbandRectangle.top+context.lineWidth,
                        rubberbandRectangle.width-2*context.lineWidth,
                        rubberbandRectangle.height-2*context.lineWidth)
    
    
    }
    function rubberbandEnd(x,y){
      if(x==rubberbandRectangle.left||y==rubberbandRectangle.top){
        dragging=false;
    
    
        return
      }
    
      context.clearRect(0,0,canvas.width,canvas.height)
      context.drawImage(offscreenCanvas,rubberbandRectangle.left+context.lineWidth*2,
                               rubberbandRectangle.top+context.lineWidth*2,
                              rubberbandRectangle.width-4*context.lineWidth,
                              rubberbandRectangle.height-4*context.lineWidth,
                               0,0,canvas.width,canvas.height)
    
      offscreenContext.drawImage(canvas,0,0,canvas.width,canvas.height)
      dragging=false;
    
      
    
    }
    canvas.onmousedown=function(e){
     var loc=windowToCanvas(canvas,e.clientX,e.clientY) //获取鼠标点击在canvas的坐标
      e.preventDefault()
     
    
      mousedown.x=loc.x
      mousedown.y=loc.y;
      rubberbandRectangle.left=mousedown.x
      rubberbandRectangle.top=mousedown.y
      dragging=true
    
    }
    canvas.onmousemove=function(e){
     var loc
     if(dragging){
    
       context.clearRect(0,0,canvas.width,canvas.height)
       context.drawImage(offscreenCanvas,0,0,canvas.width,canvas.height) //把离屏canvas上的数据复制到当前canvas
       loc=windowToCanvas(canvas,e.clientX,e.clientY)
       rubberbandStretch(loc.x,loc.y)   //计算出选中的矩形坐标
     }
    
    }
    
    
    canvas.onmouseup=function(e){
      var loc=windowToCanvas(canvas,e.clientY,e.clientY)
      
      rubberbandEnd(loc.x,loc.y)  //鼠标抬起 开始从离屏canvas复制数据
    }
    resetButton.onclick=function(e){
        dragging=false;
    
       context.clearRect(0,0,canvas.width,canvas.height)
    
       context.putImageData(start_data,0,0)
       offscreenContext.putImageData(start_data,0,0)
       
    }
    function start(){
    var src="./timg.jpg"
    var img=new Image()
    img.src=src
    window.onload=function(){
          context.drawImage(img,0,0,canvas.width,canvas.height)
          start_data=context.getImageData(0,0,canvas.width,canvas.height)    //记录初始数据以备还原使用
          offscreenContext.drawImage(img,0,0,offscreenCanvas.width,offscreenCanvas.height)  //离屏canvas储存图像
          }
    
    }
    start()
    
    
    
    
    
    
    
    
    
    
    
    </script>
    

    canvas利用requestNextAnimationFrame做动画及碰撞检测

    <!DOCTYPE html>
       <head>
         <title>Video</title>
    
          <style> 
             body {
                background: #dddddd;
             }
    
             #canvas {
                background: #ffffff;
                cursor: pointer;
                margin-left: 10px;
                margin-top: 10px;
                -webkit-box-shadow: 3px 3px 6px rgba(0,0,0,0.5);
                -moz-box-shadow: 3px 3px 6px rgba(0,0,0,0.5);
                box-shadow: 3px 3px 6px rgba(0,0,0,0.5);
             }
    
             #controls {
                margin-top: 10px;
                margin-left: 15px;
             }
          </style>
       </head>
    
      <body>
          <div id='controls'>
             <input id='animateButton' type='button' value='Animate'/>
          </div>
    
          <canvas id='canvas' width='750' height='500'>
             Canvas not supported
          </canvas>
    
    
      </body>
    </html>
    <script type="text/javascript" src="./js/requestNextAnimationFrame.js"></script>
    <script type="text/javascript">
       var canvas=document.getElementById("canvas")
       var context=canvas.getContext("2d")
       var paused=true
    
       var discs=[
        {x:150,
          y:250,
          lastX:150,
          lastY:250,
          velocityX:-3.2,  //横坐标速率
          velocityY:3.5,   //纵坐标速率
          radius:25,
          innerColor:"rgba(255,255,0,1)",
          middleColor:"rgba(255,255,0,0.7)",
          outerColor:"rgba(255,255,0,0.5)",
          strokeStyle:"gray"
    
        },
          { 
             x: 50,
             y: 150,
             lastX: 50,
             lastY: 150,
             velocityX: 2.2,  //横坐标速率
             velocityY: 2.5,  //纵坐标速率
             radius: 25,
             innerColor: 'rgba(100,145,230,1.0)',
             middleColor: 'rgba(100,145,230,0.7)',
             outerColor: 'rgba(100,145,230,0.5)',
             strokeStyle: 'blue'
          },
    
          { 
             x: 150,
             y: 75,
             lastX: 150,
             lastY: 75,
             velocityX: 1.2,
             velocityY: 1.5,
             radius: 25,
             innerColor: 'rgba(255,0,0,1.0)',
             middleColor: 'rgba(255,0,0,0.7)',
             outerColor: 'rgba(255,0,0,0.5)',
             strokeStyle: 'orange'
          }
    
    
       ]
      var numDiscs=discs.length; //圆的个数
      var animateButton=document.getElementById("animateButton")
    
     function update(){
        var disc=null
        for(var i=0;i<discs.length;i++){
           disc=discs[i]
           if(disc.x+disc.velocityX+disc.radius>canvas.width||disc.x-disc.radius+disc.velocityX<0){ //碰撞检测
            disc.velocityX=-disc.velocityX
           }
           if(disc.y+disc.velocityY+disc.radius>canvas.height||disc.y-disc.radius+disc.velocityY<0){ //碰撞检测
              disc.velocityY=-disc.velocityY
           }
           
          disc.x+=disc.velocityX
          disc.y+=disc.velocityY
    
        }
    
    
    
     }
    function draw(){
       var disc=null
    
       for(var i=0;i<discs.length;i++){
            disc=discs[i]
            gradient=context.createRadialGradient(disc.x,disc.y,0,disc.x,disc.y,disc.radius)
            gradient.addColorStop(0.3,disc.innerColor)
            gradient.addColorStop(0.5,disc.middleColor)
            gradient.addColorStop(1.0,disc.outerColor)
            context.save()
            context.beginPath()
            context.arc(disc.x,disc.y,disc.radius,0,Math.PI*2,false)
            context.fillStyle=gradient
            context.strokeStyle=disc.strokeStyle
            context.fill()
            context.stroke()
            context.restore()
       }
    
    
    }
    function animation(time){
      if(!paused){
        context.clearRect(0,0,canvas.width,canvas.height)
        draw()
        update()
        
        window.requestNextAnimationFrame(animation)
      }
     
    
    
    }
    
    animateButton.onclick=function(e){
     paused=!paused
     if(paused){
      animateButton.value="Animation"
     }else{
      window.requestNextAnimationFrame(animation)
      animateButton.value="Pause"
    
     }
    
    
    }
    
    
    
    
    
    
    
        
    
    
    </script>
    

    canvas制作无限视差滚动背景图

    <!DOCTYPE html>
    <html>
    <head>
        <title>背景滚动</title>
       <meta charset="utf-8">
            <style> 
               body {
                    background: #dddddd;
                }
    
                #canvas {
                position: absolute;
                top: 30px;
                left: 10px;
                background: #ffffff;
                cursor: crosshair;
                margin-left: 10px;
                margin-top: 10px;
                -webkit-box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
                -moz-box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
                box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
                }
    
             input {
                margin-left: 15px;
                }
    
            </style>
    
    </head>
    <body>
        <canvas id='canvas' width='1024' height='512'>
          Canvas not supported
        </canvas>
    
        <input id='animateButton' type='button' value='Animate'/>
    
        <script src='./js/requestNextAnimationFrame.js'></script>
       
    </body>
    </html>
    
    
    <script type="text/javascript">
    var canvas=document.getElementById("canvas")
    var context=canvas.getContext("2d")
    var animateButton=document.getElementById("animateButton")
    
    var sky=new Image()
    var person=new Image()
    
    
    var paused=true
    var lastTime=0
    var fps=0
    var skyOffset=0
    var skyOffset1=500
    var SKY_VELOCITY=30
    
    function erase(){
        context.clearRect(0,0,canvas.width,canvas.height)
    }
    function getfps(){
      var now=(+new Date)
      fps=1000/(now-lastTime)
      lastTime=now
      return fps
    
    }
    function draw(){
     
    
      context.save()
      skyOffset=skyOffset>canvas.width?0:skyOffset+SKY_VELOCITY/getfps()
      context.translate(skyOffset,0)
      context.drawImage(sky,0,0,canvas.width,canvas.height)
      context.drawImage(sky,-canvas.width+2,0,canvas.width,canvas.height)
      context.restore()
    
       context.save()
       skyOffset1=skyOffset1-3
       if(skyOffset1<-144){skyOffset1=canvas.width-144}
       context.translate(0,0)
       context.drawImage(person,skyOffset1,50)
       context.drawImage(person,canvas.width+skyOffset1,50)
       context.restore()
    
    
    
    }
    
    sky.src="./images/hover2.png"
    
    
    person.src="./images/hover1.png"
    
    window.onload=function(){
    draw()
    
    }
    
    
    function animate(){
    
        if(paused){
         erase()
         draw()
       
        }
    
        requestNextAnimationFrame(animate)
    
    }
    
    
    window.requestNextAnimationFrame(animate)
    animateButton.onclick=function(){
      paused=!paused
      
    }
    
    
    
    </script>
    

    canvas制作随机粒子移动特效

    <!DOCTYPE html>
    <html>
    <head>
        <title>背景滚动</title>
       <meta charset="utf-8">
            <style> 
               body {
                    background: #dddddd;
                }
    
                #canvas {
                position: absolute;
                top: 30px;
                left: 10px;
                background: #ffffff;
                cursor: crosshair;
                margin-left: 10px;
                margin-top: 10px;
                -webkit-box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
                -moz-box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
                box-shadow: 4px 4px 8px rgba(0,0,0,0.5);
                }
    
             input {
                margin-left: 15px;
                }
    
            </style>
    
    </head>
    <body>
        <canvas id='canvas' width='1024' height='512'>
          Canvas not supported
        </canvas>
    
        <input id='animateButton' type='button' value='Animate'/>
    
        <script src='./js/requestNextAnimationFrame.js'></script>
       
    </body>
    </html>
    
    
    <script type="text/javascript">
    var canvas=document.getElementById("canvas")
    var context=canvas.getContext("2d")
    
    var Sprite=function(name,painter,behaviors){
      if(name!==undefined){this.name=name}
        if(painter!==undefined){this.painter=painter}
          this.top=0
          this.left=0
          this.width=0
          this.height=0
          this.velocityX=0
          this.velocityY=0
          this.visible=true
          this.animating=false
          this.behaviors=behaviors||[]
          this.RADIUS=0
          return this
    
    
    }
    Sprite.prototype={
       paint:function(context){
        if(this.painter!==undefined&&this.visible){this.painter.paint(this,context)}
       },
       update:function(context,time){
        for(var i=0;i<this.behaviors.length;i++){
          this.behaviors[i].excute(this,context,time)
        }
       }
    }
    
    // var RADIUS=5
    var pai={
            paint:function(sprite,context){
    
                 context.save()
    
                 context.beginPath()
                 sprite.left=sprite.left+sprite.velocityX
                 sprite.top=sprite.top+sprite.velocityY
    
                 if(sprite.left+sprite.RADIUS>canvas.width||sprite.left-sprite.RADIUS<0){
                    sprite.velocityX=-sprite.velocityX
                 }
                 if(sprite.top+sprite.RADIUS>canvas.height||sprite.top-sprite.RADIUS<0){
                    sprite.velocityY=-sprite.velocityY
                 }
    
    
                 
                 context.arc(sprite.left+sprite.width/2,sprite.top+sprite.height/2,sprite.RADIUS,0,Math.PI*2,false)
                 context.clip()
    
                 context.shadowBlur=8
                 context.lineWidth=2
                 context.strokeStyle="rgb(100,100,195)"
                 context.fillStyle="rgba(30,144,255,0.15)"
                 context.fill()
                 context.stroke()
                 context.restore()
    
    
            }
    
    }
    var star_list=[]
    for(var i=0;i<100;i++){
      var star=new Sprite("star"+i,pai)
       star.left=parseInt(19+(Math.random()*800))
       star.top=parseInt(19+(Math.random()*450))
    
      if(i%2==0){
        star.velocityY=parseInt(Math.random()*15+1)
      star.velocityX=parseInt(Math.random()*15+1)
    
      }else{
    
           star.velocityY=-(parseInt(Math.random()*15+1))
      star.velocityX=-(parseInt(Math.random()*15+1))
      }
    
      
    
    
      star.RADIUS=parseInt(Math.random()*20+1)
      star_list.push(star)
    }
    function animate(){
           context.clearRect(0,0,canvas.width,canvas.height)
           context.fillStyle="rgb(0,0,0)"
           context.fillRect(0,0,canvas.width,canvas.height)
           
           for(var i=0;i<star_list.length;i++){
    
               star_list[i].paint(context)
           }
    
           window.requestAnimationFrame(animate)
    }
    
    window.requestAnimationFrame(animate)
    
    
    </script>
    

    canvas精灵图制作人物左右移动

    var velocityX=10  //X轴的位移速度
    var left1=100     //X轴的起始位置 这个值控制人物的横坐标
    var img_start=imgid //最开始的精灵贴图
    var advance_or="left" //最开始向左移动
    SpriteSheetPainter=function(cells){
       this.cells=cells||[]
       this.cellIndex=0
    
    }
    
    SpriteSheetPainter.prototype={
    
       advance:function(){
    
        if(this.cellIndex==(this.cells.length-1)){this.cellIndex=0}else{
                  this.cellIndex++
                 }
       },
       advance2:function(){
            
            if(this.cellIndex==0){this.cellIndex=(this.cells.length-1)}else{
                  this.cellIndex--
                 }
    
       },
       paint:function(context,canvas){
        var cell=this.cells[this.cellIndex]
        left1=canvas.left-velocityX
    
        if(left1<0){ //人物左移临界点判断
           advance_or="right"
           velocityX=-velocityX
           img_start=imgid2
           
           context.drawImage(img_start,cell.x,cell.y,cell.w,cell.h,canvas.left,canvas.top,canvas.w,canvas.h)
          
        }
         if(left1+canvas.w>1024){ //人物右移临界点判断
          advance_or="left"
          velocityX=-velocityX
          img_start=imgid
        
          context.drawImage(img_start,cell.x,cell.y,cell.w,cell.h,canvas.left,canvas.top,canvas.w,canvas.h)
         }
    
         else{
         if(advance_or=="left"){
    
          img_start=imgid
          this.advance()
         }
         if(advance_or=="right"){
          img_start=imgid2
          this.advance2()
         }
    
         context.drawImage(img_start,cell.x,cell.y,cell.w,cell.h,canvas.left,canvas.top,canvas.w,canvas.h)
         }
    
        
       }
    }
    
    window.onload=function(){
       //bomb.paint(context)
       var some=new SpriteSheetPainter([{x:0,y:0,w:41,h:64},
                                        {x:53,y:0,w:41,h:64},
                                        {x:106,y:0,w:41,h:64},
                                        {x:159,y:0,w:41,h:64},
                                        {x:212,y:0,w:41,h:64},
                                        {x:265,y:0,w:41,h:64},
                                        {x:318,y:0,w:41,h:64},
                                        {x:371,y:0,w:41,h:64},
                                        {x:424,y:0,w:41,h:64}
                                        ])
    
        some.paint(context,{left:100,top:100,w:53,h:64})
    
       var now=0
       var last=0
       
    
       function animate(){
         now=(+new Date) 
         var hi=now-last
        
         if(parseInt(hi)>100){
          
          
          last=now
    
         context.clearRect(0,0,canvas.width,canvas.height)
         // some.advance()
         some.paint(context,{left:left1,top:100,w:53,h:64})
    
         }
         
         
       
         requestAnimationFrame(animate)
        }
    
    requestAnimationFrame(animate)
    
    
    }
    
    

    相关文章

      网友评论

          本文标题:canvas常用API 总结

          本文链接:https://www.haomeiwen.com/subject/bddouftx.html