zoukankan      html  css  js  c++  java
  • canvas学习

    准备

    定义 canvas 元素,以及 css 样式,使用 javascript 进行 canvas 绘制。

    canvas 的绘制步骤:先描述状态,再使用绘制函数绘制。

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>canvas学习</title>
      </head>
      <style type="text/css">
      	#canvas{
      		display: block;
      		margin: 0 auto;
      		border: 1px solid #aaa;
      	}
      </style>
      <body>
        <canvas id="canvas" width="1000" height="800">
        	您的浏览器不支持canvas
        </canvas>
      </body>
      <script type="text/javascript">
      	// 使用context绘制
      	var canvas=document.getElementById("canvas");
      	var context=canvas.getContext("2d");
    
      </script>
    </html>
    
    

    绘制基础

    context设置

    // 使用beginPath()以及closePath()来隔离两段状态
    context.beginPath();
    // 使用closePath()函数时,会自动将最终坐标与最初坐标用直线连接,可以不使用closePath()函数;
    // 如果使用了fill()填充了颜色,closePath()不起作用
    context.closePath();
    
    
    // 设置了context的一些形状操作后,相关值会有叠加;可以保存和恢复context来重置,save()以及restore()
    context.save();
    context.restore();
    
    // 清除canvas的内容
    context.clearRect(x,y,w,h)
    

    设置背景

    简单设置

    context.fillStyle="";
    context.strokeStyle="";
    // 设置以下值
    1. #ffffff
    2. #642
    3. rgb(255,255,0)
    4. rgba(100,100,100,0.6)
    5. hsl(20,60%,60%)
    6. hsla(20,60%,80%,0.6)
    7. red
    

    渐变设置

    • 线性渐变

      // 从(xtart,ystart)坐标到(xend,yend)的线性渐变
      // grd=context.createLinearGradient(xstart,ystart,xend,yend);
      // 在stop处设置color,stop取值 0~1 的浮点值
      // grd.addColorStop(stop,color);
      
      var grd=context.createLinearGradient(0,0,800,0);
      grd.addColorStop(0.0,"red");
      grd.addColorStop(1.0,"yellow");
      context.fillStyle=grd;
      
    • 径向渐变

      // 从圆心坐标(x0,y0)半径为r0的圆到圆心坐标(x1,y1)半径为r1的圆坐标之间的径向渐变
      // grd=context.createRadialGradient(x0,y0,r0,x1,y1,r1);
      // 在stop处设置color,stop取值 0~1 的浮点值
      // grd.addColorStop(stop,color);
      
      var grd=context.createRadialGradient(100,100,0,100,100,100);
      grd.addColorStop(0.0,"red");
      grd.addColorStop(1.0,"yellow");
      context.fillStyle=grd;
      

    设置图片背景

    context.createPattern(img,repeat-style)

    repeat-style 可选值:no-repeat、repeat-x、repeat-y、repeat

    var context=canvas.getContext("2d");
    //将一个图像绘制到canvas中,从(dx,dy)开始绘制 image 图像
    var image=new Image();
    image.src="img/UI-bc-2.png";
    image.onload=function(){
        // 必须在图像加载完之后再绘制
        var pattern = context.createPattern(image,"no-repeat");
        context.fillStyle=pattern;
        context.fillRec(0,0,800,800);
    }
    

    createPattern() 既可以将 image 作为填充,也可以将 canvasvideo 作为填充

    线条属性

    • context.lineWidth 线条宽度

    • context.lineCap 设置线条尾部的突出一部分的形状

      可取值:butt(default---不突出)、round(圆形)、square(方形)

    • context.lineJoin 设置两条线的相交点的形状

      可取值:miter(default---形成尖角)、bevel(不会有尖角)、round(形成圆角)

    • context.miterLimit

      只有当 lineJoin 设置为 miter 时有效,默认是10,代表两条线的相交产生的尖角长度超过10个像素时,会使用 bevel 属性相交特点。

    位移、旋转、缩放操作

    • context.translate(x,y) 将图形 x 轴移动 x , y 轴移动 y

    • context.rotate(deg) 将图形旋转

    • context.scale(sx,sy) 将图形 x 方向缩放 sx 倍,y 方向缩放 sy 倍,会应用到一个图形的所有属性上,例如坐标值,线条宽度等。。。

    • context.transform(a,b,c,d,e,f) 以矩阵方式进行设置

      a :水平缩放 1

      b :水平倾斜 0

      c :垂直倾斜 0

      d :垂直缩放 1

      e :水平位移 0

      f :垂直位移 0

      相当于以下矩阵:

      a c e

      b d f

      0 0 1

    如果进行多次以上操作,这些值会叠加,如果需要清除之前的操作,可以使用以下方法:

    // 保存和恢复context,save()以及restore()
    context.save();
    context.translate(100,100);
    context.restore();
    // 重设transform,可以使用setTransform()
    context.setTransform(1,0,0,1,100,100);
    

    绘制

    直线绘制

    // 使用beginPath()以及closePath()来隔离两段状态
    context.beginPath();
    
    // 从(100,100)画到(700,700)的直线
    context.moveTo(100,100);
    context.lineTo(700,700);
    // 可以使用多个context.lineTo()来绘制多边形,会按照先后定义的坐标值按照先后顺序画
    context.lineTo(100,700);
    context.lineTo(100,100);
    // 使用strokeStyle来绘制线条颜色
    context.strokeStyle="red";
    context.lineWidth=5;
    
    context.closePath();
    // stroke()函数画线条
    context.stroke();
    // 填充画出的区域
    context.fillStyle="blue";
    context.fill();
    

    弧绘制

    基于圆绘制

    context.arc(centerx,centery,radius,startAngle,endAngle,antclockwise=false)

    说明:

    • centerx --- 圆心的x轴坐标

    • centery --- 圆心的y轴坐标

    • radius --- 半径

    • startAngle --- 开始弧度值

    • endAngle --- 结束弧度值

      弧度值从最右边的坐标开始算起,0*Math.PI - 0.5*Math.PI - 1*Math.PI - 2*Math.PI

    • antclockwise --- 弧度绘制方向,false:顺时针;true:逆时针

    context.strokeStyle="red";
    context.lineWidth=3;
    context.arc(300,300,100,0,1.5*Math.PI);
    context.stroke();
    

    弧度绘制

    context.arcTo(x1,y1,x2,y2,radius)

    以上一个绘制出的最后一个点为 (x0,y0) ,必须有上一个绘制的最终点或者moveTo()定点,根据 (x0,y0)、(x1,y1)、(x2,y2) 三个坐标绘制一个三角形,形成一个与 (x0,y0) 和 (x1,y1) 的直线和 (x1,y1) 和 (x2,y2) 的直线相切的半径为 radius 的圆弧。切点不一定是 (x0,y0) 和 (x2,y2)

    !!! 以下贝塞尔曲线需要多次试验才好控制 !!!

    二次贝塞尔曲线

    context.quadraticCurveTo(x1,y1,x2,y2)

    必须有上一个绘制的最终点或者moveTo()定点

    (x1,y1) 作为控制点,(x2,y2) 作为结束点

    三次贝塞尔曲线

    context.bezierCurveTo(x1,y1,x2,y2,x3,y3)

    必须有上一个绘制的最终点或者moveTo()定点

    (x1,y1)、(x2,y2) 作为控制点,(x3,y3) 作为结束点

    矩形绘制

    var context=canvas.getContext("2d");
    //绘制一个红色的方形,左上坐标(100,100),右下坐标(100+400,100+400)
    context.fillStyle="red";
    // 方法一
    context.rect(100,100,400,400);
    context.stroke();
    // 方法二
    context.fillRect(100,100,400,400);
    // 方法三
    context.strokeRect(100,100,400,400);
    
    context.fill();
    

    图像绘制

    简单绘制

    context.drawImage(image,dx,dy)

    var context=canvas.getContext("2d");
    //将一个图像绘制到canvas中,从(dx,dy)开始绘制 image 图像
    var image=new Image();
    image.src="img/UI-bc-2.png";
    image.onload=function(){
        // 必须在图像加载完之后再绘制
        context.drawImage(image,50,50);
    }
    

    改变宽高

    context.drawImage(image,dx,dy,dw,dh)

    var context=canvas.getContext("2d");
    //将一个图像绘制到canvas中,从(dx,dy)开始绘制 image 图像,并修改图片的宽高分别为dw,dh
    var image=new Image();
    image.src="img/UI-bc-2.png";
    image.onload=function(){
        // 必须在图像加载完之后再绘制
        context.drawImage(image,50,50,200,200);
    }
    

    部分图像绘制

    context.drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh)

    将 source 图片的 (sx,sy) 坐标之后的宽为sw,高为sh的图片,根据(dx,dy,dw,dh)参数映射到 canvas 中。

    var context=canvas.getContext("2d");
    //将一个图像绘制到canvas中,从(dx,dy)开始绘制 image 图像,并修改图片的宽高分别为dw,dh
    var image=new Image();
    image.src="img/UI-bc-2.png";
    image.onload=function(){
        // 必须在图像加载完之后再绘制
        // 截取原图片的一部分图片映射到canvas中
      	context.drawImage(image,50,50,500,500,0,0,canvas.width,canvas.height);
    }
    

    缩放绘制

    // 添加 range 滑杆控件以及样式,并通过滑杆值的改变来缩放图片
    // #range{
    // 	display: block;
    // 	margin: 20px auto;
    // 	 300px;
    // }
    //  <input type="range" name="" id="range" min="0.5" max="3.0" step="0.01" value="1.0" />
    
    var slider=document.getElementById("range");
    //获取滑杆的值
    var scale=slider.value;
    //将一个图像绘制到canvas中
    var image=new Image();
    image.src="img/UI-bc-2.png";
    image.onload=function(){
        // 必须在图像加载完之后再绘制
        // 根据缩放比例显示图片
        drawImageByScale(scale,image);
        // 根据滑杆的移动来改变图片的显示比例
        slider.onmousemove=function(){
            scale=slider.value;
            drawImageByScale(scale,image);
        }
    }
    function drawImageByScale(scale,image){
        //清除 canvas 内容
        context.clearRect(0,0,canvas.width,canvas.height);
        // 计算应显示的图片宽高
        var imageWidth=image.width*scale;
        var imageHeight=image.height*scale;
        // 方法一,裁剪图片来放大图片但是缩小图片时需要另写判断程序,以下程序不完全
        // 计算sx,sy
        var sx=imageWidth/2-canvas.width/2;
        var sy=imageHeight/2-canvas.height/2;
        context.drawImage(image,sx,sy,canvas.width,canvas.height, 0,0,canvas.width,canvas.height);
        
        // 方法二,修改图片的(dx,dy)值来缩小放大图片
        var dx=canvas.width/2-imageWidth/2;
        var dy=canvas.height/2-imageHeight/2;
        context.drawImage(image,dx,dy,imageWidth,imageHeight);
    }
    
    

    双canvas绘制

    // 将 canvas_2 的图像绘制在 context 所代表的 canvas 上
    context.drawImage(canvas_2,canvas.width-canvas_2.width,canvas.height-canvas_2.height);
    

    像素绘制

    • 获取一个 canvas 的图像

      imageData=context.getImageData(x,y,w,h);

      可以获取到 imageData 的 width、height、data

    • 将获取到的图像放到 canvas 中

      context.putImageData(imageData,x,y,imageDataX,imageDataY,imageDataW,imageDataH)

    • 创建imageDta

      imageData=context.createImageData(w,h)

    imageData 的data中存储了所有像素,计算方式如下:

    1. 第i个像素:r=imageData.data[4*i+0];g=imageData.data[4*i+1];b=imageData.data[4*i+2];a=imageData.data[4*i+3]
    2. 第x行第y列的像素:i=x*width+y,r/g/b/a的计算方式仍如上所示。

    文字渲染

    • context.font

      可设置font-style(normal、italic---斜体字、oblique---倾斜文字)、font-variant(normal、small-caps---英文小写字母更有效)、font-weight(lighter、normal、bold、bolder、100-900)、font-sizefont-family(支持@font-face),默认"20px sans-serif"

    • context.textAlign 文本水平对齐方式

      left、right、center

    • context.textBaseline 文字垂直对齐方式

      top、middle、bottom

      alphabetic(为拉丁语准备的)、ideographic(为汉字等方块文字准备的)、hanging(为印度语准备的)

    • context.measureText(string).width 文本度量

      获取在canvas中渲染文字所占的宽度

    // 设置文字和位置,显示文字线条和位置
    // context.fillText(string,x,y,[maxlen]);
    // context.strokeText(string,x,y,[maxlen]);
    // 也可以使用fillStyle来设置文字的颜色
    context.font="bold 40px Arial";
    context.fillText("canvas",100,100);
    context.fillText("canvas",100,100,200);
    

    阴影绘制

    • context.shadowColor 阴影颜色
    • context.shadowOffsetX 阴影 x 轴的偏移量
    • context.shadowOffsetY 阴影 y 轴的偏移量
    • context.shadowBlur 阴影的模糊程度

    其他属性

    • context.globalAlpha 这是一个全局变量的透明度设置,取值:0~1

    • context.globalCompositeOperation 图形重叠时的处理方式

      取值:

      source-over(后绘制的覆盖前绘制的---默认)

      destination-over(前覆盖后)

      source-atop(显示前绘制的图形以及处于前绘制的图形中的后绘制图形的部分)

      source-in(只显示处于前绘制的图形中的后绘制图形的部分)

      source-out(只显示处于前绘制的图形之外的后绘制图形的部分)

      destination-atop(显示后绘制的图形以及处于后绘制的图形中的前绘制图形的部分)

      destination-in(只显示处于后绘制的图形中的前绘制图形的部分)

      destination-out(只显示处于后绘制的图形之外的前绘制图形的部分)

      lighter(重叠部分的颜色会混合重叠双方的颜色)

      copy(只绘制后绘制的)

      xor(重叠部分没有颜色)

    • context.clip() 剪辑区域

      使用之前绘制的图形作为剪辑区域

    • 按照非零环绕原则确认路径方向以及封闭区域的内外

    • context.isPointInPath(x,y) (x,y)是否在之前绘制的区域内

    • canvas.getBoundingClientRect() 获取canvas的边距

      示例使用:canvas.getBoundingClientRect().left

    高级拓展

    自定义库函数

    允许将自定义的画图函数添加到context中。

    CanvasRenderingContext2D.prototype.fillStar=function(){
        // ...
    }
    
    context.fillStar();
    
    // 记录MoveTo的坐标
    var originalMoveTo=CanvasRenderingContext2D.prototype.moveTo;
    CanvasRenderingContext2D.prototype.lastMoveToLoc={}
    // 重写函数
    CanvasRenderingContext2D.prototype.moveTo=function(x,y){
        // 调用原函数
        originalMoveTo.apply(context,[x,y]);
        this.lastMoveToLoc.x=x;
        this.lastMoveToLoc.y=y;
    }
    
  • 相关阅读:
    求某个数的位数公式
    ArrayList和lInkedList比较
    队列
    抽象数据结构-栈
    LinkedList的实现
    ArrayList的实现
    Iterator和List的一些问题
    SCHEMA约束
    DTD约束
    XML解析
  • 原文地址:https://www.cnblogs.com/fengzzi/p/10391131.html
Copyright © 2011-2022 走看看