Canvas

作者: 强某某 | 来源:发表于2020-09-24 16:37 被阅读0次

    canvas三要素

    • id:作为唯一的标识
    • width:画布内同宽度的像素大小(与stylr的宽高是有区别的)
    • height:画布内同高度的像素大小

    颜色、样式和阴影

    属性 描述
    fillStyle 设置或返回用于填充绘画的颜色,渐变或模式
    strokeStyle 设置或返回用于笔触的颜色,渐变或模式
    shadowColr 设置或返回用于阴影的颜色
    shadowBlur 设置或返回用于阴影的模糊级别
    shadowOffsetX 设置或返回阴影与形状的水平距离
    shadowOffsetY 设置或返回阴影与形状的垂直距离
    方法 描述
    createLinearGradient() 创建线性渐变(用于画布内容上)
    createPattern() 在指定的方向上重复指定的元素
    createRadialGradient() 创建放射状/环形的渐变(用在画布内容上)
    addColorStop() 规定渐变对象种的颜色和停止位置

    线条样式

    属性 样式
    lineCap 设置或返回线条的结束端点样式
    lineJoin 设置或返回两条线相交时,所创建的拐角类型
    lineWidth 设置或返回当前的线条的宽度
    miterLimit 设置或返回最大斜接长度(值只有1,2,3;三个等级)

    miterLimit:其实就是例如折线交点处,如果太尖锐时候需要截掉尖锐头的一部分,可以设置该值

    miterLimit说明

    矩形

    方法 属性
    rect() 创建矩形
    fillRect() 绘制"被填充"的矩形
    strokeRect() 绘制矩形(无填充)
    clearRect() 再给定的矩形内清除指定的像素

    路径

    方法 描述
    fill() 填充当前绘图(路径)
    stroke() 绘制已定义的路径
    beginPath() 起始一条路径,或重置当前路线
    moveTo() 把路径移动到画布的指定点,不创建线条
    closePath() 创建从当前点回到起始点的路径
    linTo() 添加一个新点,然后再画布种创建从该点到最后指定点的线条
    clip() 从原始画布裁剪任意形状和尺寸的区域
    quadraticCurveTo() 创建二次贝塞尔曲线
    bezierCurveTo() 创建三次贝塞尔曲线
    arc() 创建弧/曲线(用于创建圆形或者部分圆)
    isPointLnPath() 如果指定的点位于当前路径种,则返回true否则返回false

    转换

    方法 描述
    scale() 缩放当前绘图至更大或更小
    rotate() 旋转当前绘图
    translate() 重新映射画布上的(0,0)位置
    transform() 替换绘图的当前转换矩阵
    setTransform() 将当前转换重置为单元矩阵,然后运行transform()

    文本

    属性 描述
    font 设置或返回文本内容的当前字体属性
    textAlign 设置或返回文本内容的当前对齐方式
    textBaseLine 设置或返回在绘制文本时使用的当前文本基线
    方法 描述
    fillText() 在画布上绘制"被填充的"文本
    strokeText() 在画布上绘制文本(无填充)
    measureText() 返回包含指定文本宽度的对象

    图像绘制

    方法 描述
    drawImage() 向画布上绘制图像、画布或视频

    像素操作

    属性 描述
    width 返回ImageData对象的宽度
    height 返回ImageData对象的高度
    data 返回一个对象,其包含指定的ImageData对象的图像数据
    方法 描述
    createImageData() 创建新的、空白的ImageData对象
    getImageData() 返回ImageData对象,该对象为画布上指定的矩形复制像素数据
    putImageData() 把图像数据(从指定的ImageData对象)放回画布上

    getImageData(x0,y0,width,height);起始就是获取一个矩形图像,数据是数组,数组里面数据是四个一条,就是rgba的数据

    合成

    属性 描述
    globalAlpha 设置或返回绘图的当前alpha或透明值
    globalCompositeOperation 设置或返回新图像如何绘制到已有的图像上

    定义和用法

    globalCompositeOperation属性设置或返回如何将一个源(新的)图像绘制到目标(已有的)的图像上。

    • 源图想=打算放置到画布上的绘图
    • 目标图像=已经放置再画布上的绘图
    默认值 source-over
    js语法 context.globalCompositeOperation="source-in"

    属性值

    描述
    source-over 源图像叠加在目标图像上
    source-atop 目标图像顶部显示源图像源图像位于目标图像之外的部分是不可见的。
    source-in 目标图像中显示源图像。只有目标图像之内的源图像部分会显示,目标图像是透明的。
    source-out 目标图像之外显示源图像。只有目标图像之外的源图像部分会显示,目标图像是透明的
    destination-over 源图像上显示目标图像
    destination-atop 源图像顶部显示目标图像目标图像位于源图像之外的部分是不可见的。
    destination-in 源图像中显示目标图像。只有源图像之内的目标图像部分会被显示,源图像是透明的。
    destination-out 源图像之外显示目标图像。只有源图像之外的目标图像部分会被显示,源图像是透明的。
    lighter 显示源图像 + 目标图像
    copy 显示源图像。忽略目标图像
    xor 等同于lighter,使用异或操作对源图像目标图像进行组合。

    其他

    方法 描述
    save() 保存当前环境的状态
    restore() 返回之前保存过的路径状态和属性
    createEvent() 创建一个事件对象。该事件可以是任何合法事件类型,必须在使用前初始化
    getContext() 返回一个用于在画布上绘图的环境。参数("2d")
    toDataURL() 返回一个包含图片展示的 data URI
    var x = document.createEvent("MouseEvent");
    x.initMouseEvent("mouseover", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    document.getElementById("myDiv").dispatchEvent(x);
    
    
    var btn = document.createEvent("BUTTON");   // 创建一个<button>元素
    btn.innerHTML = "CLICK ME";                   // 插入文本
    document.body.appendChild(btn);     
    
    downloadBtn.onclick = function () {
                var url = canvas.toDataURL()
                //console.log(url)
                /* var img = new Image()
                img.src = url; */
                /* lcAlert({
                    title:"请点击图片另存!",
                    content:"<img style='width:auto;height:230px;' src='"+url+"'/>"
                }) */
    
                var aDom = document.querySelector(".download2 a")
                aDom.setAttribute("href", url);
                //自动触发点击事件
                aDom.click()
            }
    

    基本使用demo

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <canvas id="draw"  width="600" height="500" style="border: 1px solid black;"> 
    
        </canvas>
    </body>
    </html>
    <script>
        /** @type {HTMLCanvasElement} */ 
    let draw=document.getElementById('draw');
    // console.log(draw);
    let cvs=draw.getContext("2d");
    
    // console.log(cvs);
    // cvs.fillStyle;//填充的样式
    // cvs.strokeStyle;//笔触的样式(边框的颜色)
    // cvs.lineWidth;//边框宽度
    //绘制图形有两种方式:一个填充一个绘制边框,两个可以合并起来用
    // cvs.fill();//填充
    // cvs.stroke();//边框
    
    
    // 坐标已画布为基准,左上角(0,0)
    // cvs.moveTo();//起始点的坐标
    // cvs.lineTo();//结束点的坐标
    
    //如果没有moveto就把上一个挨着的lineTo作为起始坐标
    // cvs.beginPath();//开始一个新的路径
    // cvs.closePath();//关闭当前的路径,而且会自动闭合
    
    
    
    function draw1() {
        //直线
        cvs.beginPath();
        cvs.moveTo(50,50);
        cvs.lineTo(150,50);
        cvs.closePath();
        cvs.strokeStyle="red";
        cvs.lineWidth=20;
        cvs.stroke();//以边框的形式显示
    }
    // draw1();
    
    function draw2() {
        //三角形
        cvs.beginPath();
        cvs.moveTo(50,50);
        cvs.lineTo(150,50);
        cvs.lineTo(80,80);
        cvs.closePath(); 
        // cvs.fillStyle="red";
        // cvs.lineWidth=2;
        cvs.stroke();
    }
    // draw2();
    
    function draw3() {
        //圆角
        // cvs.lineJoin  三个属性:尖角(默认 miter),斜角(bevel),圆角(round)
        //设置一条线段,两端点的样式
        // cvs.lineCap  三个属性:butt(默认的 平)  round(圆角) square(方角)
    
        cvs.beginPath();
        cvs.moveTo(50,50);
        cvs.lineTo(250,50);
        // cvs.closePath();  加上这句话没有端点的效果,例如圆角消失
        cvs.lineWidth=20;
        cvs.strokeStyle="red";
        cvs.lineCap="round";
        cvs.stroke();
    }
    // draw3();
    function draw4() {
        cvs.beginPath();
        cvs.moveTo(200,100);
        cvs.lineTo(100,250);
        cvs.lineTo(300,250);
        cvs.closePath();
        cvs.lineWidth=20;
        cvs.strokeStyle="red";
        cvs.lineJoin="bevel";
        cvs.stroke();
    }
    // draw4();
    
    function draw5() {
        //圆形
        //cvs.arc(x,y,radius,star,end,n)
        //x,y 圆心的坐标
        //r半径
        //star:起始角,以弧度计算(三点钟方向是0度)
        //end 结束角
        //n: 是否逆时针 默认false(顺时针)
    
        //一、画线条圆形-线-不填充
        // cvs.strokeStyle="red";
        // cvs.beginPath(); 划线的时候一般都需要开始路径结束路径,但是画形状等时候不需要
        // cvs.arc(150,150,100,0,2*Math.PI);
        // cvs.closePath();
        // cvs.stroke();
    
        //二,画形状-填充形式
        cvs.arc(150,150,100,0,2*Math.PI);
        cvs.fillStyle='blue';
        cvs.fill();
        //重点:虽然开启路径和关闭路径在此种形势下可省略,但是实际开发中,可能上下都有逻辑,所以建议也加上
    }
    // draw5();
    
    function draw6() {
        //线性渐变  
        //渐变也可以设置给边框  strokeStyle
        
    
        // let CLG=cvs.createLinearGradient(x0,y0,x1,y1);//创建线性渐变
        // CLG.addColorStop(n,m)
    
        //x0,y0:渐变开始的坐标
        //x1,y1:渐变结束的坐标
        //n:设置颜色偏移量
        //m:颜色
    
        // let CLG=cvs.createLinearGradient(0,0,200,200);//创建线性渐变-斜着渐变
        let CLG=cvs.createLinearGradient(0,0,200,0);//创建线性渐变-这就是只改变了x,横向渐变
        CLG.addColorStop(0,"red");
        CLG.addColorStop(0.25,"yellow");
        CLG.addColorStop(0.5,"#ccc");
        CLG.addColorStop(0.75,"yellow");
        CLG.addColorStop(1,"red");
        cvs.fillStyle=CLG;
        cvs.fillRect(0,0,200,200); //起始坐标0,0 宽高 200
    }
    // draw6();
    
    
    function draw7() {
        //图1-原理图
        //径向渐变,发散型渐变
        // cvs.createRadialGradient(x0,y0,r0,x1,y1,r1); 
         //x0,y0:渐变开始圆心的坐标
        //x1,y1:渐变结束圆心的坐标
        //r0:渐变开始的半径
        //r1:渐变结束的半径
        let CRG= cvs.createRadialGradient(200,200,200,200,200,10); 
        CRG.addColorStop(0,"#000");
        CRG.addColorStop(0.5,"orange");
        CRG.addColorStop(1,"red");
        cvs.fillStyle=CRG;
        cvs.fillRect(100,100,200,200); 
        //图2
        //如果r0小r1大,则就是从里到位渐变
    }
    draw7();
    </script>
    
    1.png 2.png
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    
    <body>
        <canvas id="draw" width="109" height="195" style="border: 1px solid black;">
        </canvas>
    </body>
    
    </html>
    <script>
        /** @type {HTMLCanvasElement} */
        let draw = document.getElementById('draw');
        let cvs = draw.getContext("2d");
    
        function draw1() {
            //阴影
            // cvs.shadowOffsetX;//阴影横向偏移量,默认0
            // cvs.shadowOffsetY;//阴影纵向偏移量,默认0
            // cvs.shadowColor="";//阴影颜色
            // cvs.shadowBlur="";//阴影模糊范围(值越大越模糊)
            cvs.shadowOffsetX = 30;
            cvs.shadowOffsetY = 20;
            cvs.shadowColor = "#0000ff";
            cvs.shadowBlur = 20;
            cvs.fillStyle = "#449FDB";
            cvs.fillRect(50, 50, 100, 100);
            //图3
        }
        // draw1();
    
        function draw2() {
            //设置字体样式  cvs.font="字符大小font-szie  font-family"
            //水平对齐方式  cvs.textAlign=属性值 "start,end,right,center";
            //垂直对齐fanghsi  cvs.textBaseline=属性值 "top,middle,hanging,bottom,alphabetic,ideographic"
            //计算文本宽度   cvs.measureText(str)
            //填充文字  cvs.fillText(text,x,y,maxWidth)   文本内容 文字起始点x  y   最大宽度
            //绘制文字轮廓  cvs.strokeText(text,x,y,maxWidth) 文本内容 文字起始点x  y   最大宽度
            let text = "Hello World";
            cvs.fillStyle = "#ffE470";
            cvs.font = "40px verdana";
            cvs.textAlign = "start";
            cvs.textBaseline = "top";
            cvs.fillText(text, 0, 0, cvs.measureText(text).width);
    
        }
        // draw2();
    
        function draw3() {
            let CLG = cvs.createLinearGradient(0, 150, 450, 250);
            CLG.addColorStop(0, "red");
            CLG.addColorStop(0.25, "yellow");
            CLG.addColorStop(0.5, "green");
            CLG.addColorStop(0.75, "yellow");
            CLG.addColorStop(1, "red");
    
            let text = "Hello World";
            cvs.fillStyle = CLG;
            cvs.font = "40px verdana";
            cvs.textAlign = "start";
            cvs.textBaseline = "top";
            cvs.shadowOffsetX = 5;
            cvs.shadowColor = "#0000ff";
            cvs.shadowOffsetY = 4;
            cvs.shadowBlur = 5;
            cvs.fillText(text, 0, 0, cvs.measureText(text).width);
        }
    
        function draw4() {
            //绘图
            // cvs.drawImage(Image,x,y,w,h);
            //Image 真实图片,可以动态创建,也可以获取页面上的
            //x,y  图片左上角坐标
            //w,h  宽高
    
            // cvs.drawImage(Image,sx,sy,sw,sh,dx,dy,dw,dh);
            //也是绘图但是可以把图部分显示出来
    
            //sx,sy 图片左上角的坐标
            //sw,sh  矩形区域的宽高,用来截图图片
    
            //dx,dy  截取出来需要画在canvas上的坐标
            //dw,dh  画在canvas上面的宽高
    
        }
    
        function draw5() {
            //以下平移,缩放,旋转,其实都是针对画布原点操作的
    
            //平移:cvs.translate(x,y);
            //x: 坐标原点向x轴平移
            //y: 坐标原点向y轴平移
    
            //缩放  cvs.scale(x0,y0)
            //x0:x轴按照x0的比例缩放
            //y0:x轴按照y0的比例缩放
    
            //旋转 cvs.rotate(angle); angle:弧度  坐标轴转的角度
    
    
            cvs.fillStyle = "#0000FF";
            cvs.fillRect(0, 0, 200, 100);
            //上面一个矩形已经画完了,所以这个移动对上面的矩形无效
            cvs.translate(50, 0);
    
            cvs.fillStyle = "#800080";
            cvs.fillRect(0, 0, 100, 50);
            //图3
        }
        function draw6() {
            //图形组合
            // cvs.globalCompositeOperation=type;
            // type的值
            //0. source-cover: 默认值  覆盖  在原来图形上绘制新图
            //1. destination-over  在原来图形下绘制新图
            //2. sourse-in:显示图形和新图的交集,新图再上,颜色是新图的颜色
            //3. source-out:显示和新图的非交集部分,图5
            //4. destination-in: 显示图形和新图的交集,旧图在上,颜色是旧图的颜色
            //5. destination-out:显示和旧图的非交集部分
            //6. source-atop: 显示是旧图和交集的部分,交集是新图的颜色
            //7. destination-atop:显示是新图和交集的部分,交集是旧图的颜色
            //8. lighter:全部显示,交集是二者颜色的叠加\
            //9. xor:显示新旧图的非交集部分
            //10. copy:显示新图
    
    
            cvs.fillStyle = "gold";
            cvs.fillRect(10, 10, 100, 100);
            //注意位置:最好放在这里,才有新旧的设置区分
            cvs.globalCompositeOperation = "copy";
            cvs.fillStyle = "#0000FF";
            cvs.fillRect(50, 50, 100, 100);
            //图四
        }
    
    
        function draw7() {
            //僵尸动画
            let img = new Image;
            img.src = "./haha.png";
            img.onload = function () {
                let width = this.width / 10;
                let height = this.height;
                let i = 0;
                window.setInterval(() => {
                    //每一次都清空下画布
                    cvs.clearRect(0,0,draw.width,draw.height);
                    cvs.drawImage(this, i * width, 0, width, height, 0, 0, width, height);
                    if (i == 9) {
                        i = 0;
                    } else {
                        i++;
                    }
                }, 200);
            }
        }
        draw7();
    </script>
    
    3.png 4.png 5.png haha.png
    • 动态截取视频播放器的内容到画布
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    
    <body>
        <canvas id="draw" width="600" height="500" style="border: 1px solid black;">
    
        </canvas>
        <video width="600" height="500" src="./movie.ogv" controls="controls"></video>
    </body>
    
    </html>
    <script>
        /** @type {HTMLCanvasElement} */
        let draw = document.getElementById('draw');
        let cvs = draw.getContext("2d");
    
        let video = document.querySelector('video');
        let interId;
        video.onplay=function(){
            setInterval(function() {
                // cvs.cl
                interId= cvs.drawImage(video,0,0,500,500);
                cvs.font="50px 微软雅黑";
                cvs.strokeStyle="#999";
                cvs.strokeText("老陈打吗",50,50);
            
    
            },16);
        }
        video.onpause=function(){
            clearInterval(interId);
        }
    </script>
    

    canvas的width,height

    canvas的标签上面可以添加height,widht;同时其style也可以添加height,widht;但是二者不完全相同,下面说明下。

    <canvas id="canvas" width="800" height="600" style="width:400px;height: 300px;"></canvas>
            <video width="800" height="" src="img/mov_bbb.mp4" controls="controls"></video>
    
    2.png
    <canvas id="canvas" width="800" height="600" style="width:800px;height: 400px;"></canvas>
            <video width="800" height="" src="img/mov_bbb.mp4" controls="controls"></video>
    
    1.png

    这两个案例只有style是不同的,对比图可知,style里面的宽高才是canvas真的宽高,至于canvas标签上面直接的宽高属性,其实指的是绘制的内容;例如截取的视频的某一帧设置获取得是500200;那么此时800600就会空出来一部分canvas没占用;如果截取的一帧设置的很大,那么此时canvas只能显示其中一部分

    • 绘制时钟
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title></title>
        </head>
        <body>
            <canvas id="canvas" width="800" height="600"></canvas>
            
            <script type="text/javascript">
                var canvas = document.querySelector("#canvas")
                var cxt = canvas.getContext('2d')
                
                function renderClock(){
                    cxt.clearRect(0,0,800,600)
                    cxt.save()
                    //将坐标移动到画布的中央
                    cxt.translate(400,300)
                    cxt.rotate(-2*Math.PI/4)
                    
                    cxt.save()
                    //绘制表盘
                    cxt.beginPath()
                    cxt.arc(0,0,200,0,2*Math.PI)
                    cxt.strokeStyle = "darkgrey"
                    cxt.lineWidth = 10
                    cxt.stroke()
                    cxt.closePath()
                    
                    //绘制分钟刻度
                    for(var j=0;j<60;j++){
                        cxt.rotate(Math.PI/30)
                        cxt.beginPath()
                        cxt.moveTo(180,0)
                        cxt.lineTo(190,0)
                        cxt.lineWidth = 2;
                        cxt.strokeStyle = "orangered"
                        cxt.stroke()
                        cxt.closePath()
                    }
                    cxt.restore()
                    cxt.save()
                    //绘制时钟刻度
                    for(var i = 0;i<12;i++){
                        cxt.rotate(Math.PI/6);//通过旋转坐标尺,这样就不需要纠结刻度的变化了
                        cxt.beginPath()
                        cxt.moveTo(180,0)
                        cxt.lineTo(200,0)
                        cxt.lineWidth = 10;
                        cxt.strokeStyle = "darkgrey"
                        cxt.stroke()
                        cxt.closePath()
                    }
                    cxt.restore()
                    cxt.save()
                    
                    
                    var time = new Date()
                    
                    var hour =  time.getHours()
                    var min = time.getMinutes()
                    var sec = time.getSeconds()
                    //如果时间是大于12的话,就直接减去12
                    hour = hour>12?hour-12:hour
                    console.log(hour+":"+min+":"+sec)
                    
                    
                    //绘制秒针
                    cxt.beginPath()
                    //根据秒针的时间进行旋转
                    cxt.rotate(2*Math.PI/60*sec)
                    cxt.moveTo(-30,0)
                    cxt.lineTo(170,0)
                    cxt.lineWidth = 2;
                    cxt.strokeStyle = "red"
                    cxt.stroke()
                    cxt.closePath()
                    
                    cxt.restore()
                    cxt.save()
                    
                     
                    //绘制分针
                    cxt.beginPath()
                    //根据分针的时间进行旋转
                    cxt.rotate(2*Math.PI/60*min+2*Math.PI/3600*sec)
                    cxt.moveTo(-20,0)
                    cxt.lineTo(150,0)
                    cxt.lineWidth = 4;
                    cxt.strokeStyle = "darkblue"
                    cxt.stroke()
                    cxt.closePath()
                    
                    cxt.restore()
                    cxt.save()
                    
                    //绘制时针
                    cxt.beginPath()
                    //根据时针的时间进行旋转
                    cxt.rotate(2*Math.PI/12*hour+2*Math.PI/60/12*min + 2*Math.PI/12/60/60*sec)
                    cxt.moveTo(-20,0)
                    cxt.lineTo(140,0)
                    cxt.lineWidth = 6;
                    cxt.strokeStyle = "darkslategray"
                    cxt.stroke()
                    cxt.closePath()
                    
                    //画中间的表芯
                    cxt.beginPath()
                    cxt.arc(0,0,10,0,2*Math.PI)
                    cxt.fillStyle  = "deepskyblue";
                    cxt.fill()
                    cxt.closePath()
                    
                    cxt.restore()
                    cxt.restore()
                }
                
                setInterval(function(){
                    renderClock()
                },1000)
                
            </script>
        </body>
    </html>
    
    • 刮刮卡案例

    其实主要就是globalCompositeOperation,通过显示层级的覆盖关系去实现

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title></title>
            <style type="text/css">
                #ggk{
                    width: 600px;
                    height: 200px;
                    position: relative;
                }
                #ggk .jp{
                    width: 600px;
                    height: 200px;
                    position: absolute;
                    left: 0;
                    top: 0;
                    text-align: center;
                    color: deeppink;
                    font-size: 50px;
                    line-height: 200px;
                }
                #ggk #canvas{
                    width: 600px;
                    height: 200px;
                    position: absolute;
                    left: 0;
                    top: 0;
                }
            </style>
        </head>
        <body>
            <div id="ggk">
                <div class="jp">谢谢惠顾</div>
                <canvas id="canvas" width="600" height="200"></canvas>
            </div>
            <script type="text/javascript">
                var canvas = document.querySelector("#canvas")
                var ggkDom = document.querySelector("#ggk")
                var jpDom = document.querySelector(".jp")
                var ctx = canvas.getContext('2d');
                ctx.fillStyle= "darkgray"
                ctx.fillRect(0,0,600,200)
                ctx.font = "20px 微软雅黑"
                ctx.fillStyle = '#fff'
                ctx.fillText("刮刮卡",260,100)
                var isDraw = false;
                //设置isDraw = true,即为允许绘制
                canvas.onmousedown = function(){
                    isDraw = true
                    console.log(isDraw)
                }
                
                //移动的时候绘制圆形,将源图像内的目标的内容给清除掉
                canvas.onmousemove = function(e){
                    //console.log(e)
                    if(isDraw){
                        var x = e.pageX - ggkDom.offsetLeft;
                        var y = e.pageY - ggkDom.offsetTop
                        ctx.globalCompositeOperation = "destination-out"
                        ctx.arc(x,y,20,0,2*Math.PI)
                        ctx.fill()
                        
                    }
                    
                }
                
                canvas.onmouseup = function(){
                    isDraw = false
                    console.log(isDraw)
                }
                jpDom.onselectstart = function(){
                    return false
                }
                
                var arr = [{content:"一等奖:IphoneXs",p:0.1},{content:"二等奖:娃娃1个",p:0.2},{content:"三等奖:Ipad",p:0.3}]
                var randomNum = Math.random()
                if(randomNum<arr[0].p){
                    jpDom.innerHTML = arr[0].content
                }else if(randomNum<arr[1].p+arr[0].p){
                    jpDom.innerHTML = arr[1].content
                }else if(randomNum<arr[2].p+arr[1].p+arr[0].p){
                    jpDom.innerHTML = arr[2].content
                }
            </script>
        </body>
    </html>
    
    • 画画板办理
    /* 
    args:
    {
        title:'温馨提示',
        content:"是否在页面添加1个蓝色的div?",
        confirmFn:function(){
            var blueDiv = document.createElement("div")
            blueDiv.style.backgroundColor = "blue"
            blueDiv.style.width = "300px"
            blueDiv.style.height = "300px"
            body.appendChild(blueDiv)
        },
        cancelFn:function(){
            
        }
    } 
     
     */
    
    function lcAlert(args){
        var zhezhao = document.createElement('div')
        zhezhao.className = "zhezhao";
        zhezhao.innerHTML = `
        <div class="alert">
            <div class="header"><span class="title">`+args.title+`</span><span class="close">x</span></div>
            <div class="main">
                `+args.content+`
            </div>
            <div class="btnList">
                <div class="btn comfirm">确定</div>
                <div class="btn cancel">取消</div>
            </div>
        </div>
        `
        var body = document.querySelector('body');
        body.appendChild(zhezhao)
        
        //获取close元素
        var closeDiv = document.querySelector(".close")
        closeDiv.onclick = function(){
            
            body.removeChild(zhezhao);
        }
        
        var confirmDiv = document.querySelector(".btn.comfirm");
        confirmDiv.onclick = function(){
            args.confirmFn()
            if(typeof args.confirmFn == 'function'){
                args.confirmFn()
            }else{
                console.error("传入的参数,没有设置确认函数!")
            }
            body.removeChild(zhezhao);
        }
        
        var cancelDiv = document.querySelector(".btn.cancel")
        cancelDiv.onclick = function(){
            if(typeof args.cancelFn == 'function'){
                args.cancelFn()
            }else{
                console.error("传入的参数,没有设置取消函数!")
            }
            
            
            body.removeChild(zhezhao);
        }
    }
    
    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8" />
        <title></title>
        <style>
            * {
                margin: 0;
                padding: 0;
                box-sizing: border-box;
            }
    
            .zhezhao {
                position: fixed;
                left: 0;
                top: 0;
                height: 100vh;
                width: 100vw;
                background-color: rgba(0, 0, 0, 0.5);
                display: flex;
                align-items: center;
                justify-content: center;
            }
    
            .alert {
                width: 600px;
                height: 400px;
                background: #fff;
                display: flex;
                flex-direction: column;
    
            }
    
            .alert>.header {
                height: 80px;
                line-height: 80px;
                border-bottom: 1px solid #ccc;
                display: flex;
                justify-content: space-between;
                padding: 0px 30px;
            }
    
            .alert>.header>.title {
                font-size: 30px;
                font-weight: 900;
            }
    
            .alert>.header>.close {
                font-size: 30px;
                font-weight: 100;
                color: #ccc;
            }
    
            .alert>.header>.close:hover {
                color: orangered;
            }
    
            .alert>.main {
                flex: 1;
                border-bottom: 1px solid #ccc;
            }
    
            .alert>.btnList {
                height: 80px;
                display: flex;
                justify-content: center;
                align-items: center;
                padding: 0 30px;
            }
    
            .alert>.btnList>.btn {
                height: 40px;
                width: 120px;
                text-align: center;
                line-height: 40px;
                color: #fff;
                margin: 10px;
            }
    
            .alert>.btnList>.btn:nth-child(1) {
                background: coral;
            }
    
            .alert>.btnList>.btn:nth-child(2) {
                background: #999;
            }
    
    
            body {
                width: 100vw;
                height: 100vh;
                display: flex;
                flex-direction: column;
                justify-content: flex-start;
            }
    
            .caidan {
                height: 100px;
                width: 100vw;
                display: flex;
                border-bottom: 3px solid #ccc;
                justify-content: space-around;
                align-items: center;
            }
    
            #canvas {
                flex: 1;
                width: 100vw;
            }
    
            .btn,
            .btn2 {
                width: 150px;
                height: 50px;
                border: 1px solid #ccc;
                border-radius: 20px;
                text-align: center;
                line-height: 50px;
                color: #999;
                background-size: auto 100%;
                background-position: center;
                background-repeat: no-repeat;
            }
    
            .btn1 {
                width: 150px;
                height: 50px;
                border: 1px solid #ccc;
                border-radius: 20px;
                text-align: center;
                line-height: 50px;
                color: #999;
                background-size: auto 100%;
                background-position: center;
                background-repeat: no-repeat;
            }
    
            .btn.active {
                box-shadow: 0 0 20px deepskyblue;
                border: 1px solid deepskyblue;
            }
    
            .btn1.active {
                box-shadow: 0 0 20px deepskyblue;
                border: 1px solid deepskyblue;
            }
    
            .line {
                display: flex;
                justify-content: center;
                align-items: center;
            }
    
            .xi:after {
                content: "";
                background: #333;
                width: 6px;
                height: 6px;
                display: block;
                border-radius: 3px;
            }
    
            .normal:after {
                content: "";
                background: #333;
                width: 16px;
                height: 16px;
                display: block;
                border-radius: 8px;
            }
    
            .cu:after {
                content: "";
                background: #333;
                width: 32px;
                height: 32px;
                display: block;
                border-radius: 16px;
            }
        </style>
    </head>
    
    <body>
        <!-- 
             将画笔功能:能够拖动鼠标在页面内绘图,能够设置画笔的粗细,设置画笔的颜色
             能够在任意位置绘制圆形:拖动鼠标即可随意在任意位置绘制圆形,并且可以随意定制大小
             能够在任意位置绘制出矩形:拖动鼠标即可随意在任意位置绘制矩形,并且可以随意定制大小
             -->
    
        <div class="caidan">
            <div class="btn active" id="huabi" style="background-image: url(img/huabi.png);"></div>
            <div class="btn" id="rect">矩形</div>
            <div class="btn">圆形</div>
            <div class="btn">橡皮擦</div>
            <div class="btn2 download">下载图片</div>
            <div class="btn2 download2" style="display: none;">
                <a href="" download="download">下载</a>
            </div>
            <div class="btn1 line xi active"></div>
            <div class="btn1 line normal"></div>
            <div class="btn1 line cu"></div>
            <div class="btn2"><input type="color" name="color" id="color" value="#000000" /></div>
        </div>
        <canvas id="canvas"></canvas>
        <link rel="stylesheet" type="text/css" href="css/alert.css" />
        <script src="js/alert.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            var allBtn = document.querySelectorAll(".btn")
            //获取canvas
            var canvas = document.querySelector("#canvas")
            console.log([canvas])
            var ctx = canvas.getContext('2d')
            console.log(ctx)
    
            //设置canvas的宽度和高度
            canvas.setAttribute("width", canvas.offsetWidth);
            canvas.setAttribute("height", canvas.offsetHeight)
            var huaban = {
                type: "huabi",
                isDraw: false,
                beginX: 0,
                beginY: 0,
                lineWidth: 6,
                imageData: null,
                color: "#000",
                huabiFn: function (e) {
                    var x = e.pageX - canvas.offsetLeft;
                    var y = e.pageY - canvas.offsetTop
                    ctx.clearRect(0, 0, canvas.offsetWidth, canvas.offsetHeight)
                    if (huaban.imageData != null) {
                        ctx.putImageData(huaban.imageData, 0, 0, 0, 0, canvas.offsetWidth, canvas.offsetHeight)
                    }
                    ctx.lineTo(x, y)
                    ctx.strokeStyle = huaban.color;
                    ctx.lineWidth = huaban.lineWidth;
                    ctx.lineCap = "round"
                    ctx.lineJoin = "round"
                    ctx.stroke()
    
                },
                rectFn: function (e) {
                    var x = e.pageX - canvas.offsetLeft;
                    var y = e.pageY - canvas.offsetTop
    
                    ctx.clearRect(0, 0, canvas.offsetWidth, canvas.offsetHeight)
                    if (huaban.imageData != null) {
                        ctx.putImageData(huaban.imageData, 0, 0, 0, 0, canvas.offsetWidth, canvas.offsetHeight)
                    }
    
                    ctx.beginPath()
                    ctx.rect(huaban.beginX, huaban.beginY, x - huaban.beginX, y - huaban.beginY);
                    ctx.strokeStyle = huaban.color;
                    ctx.stroke()
                    ctx.closePath()
                }
            }
    
            var huabiBtn = document.querySelector("#huabi")
            huabiBtn.onclick = function () {
                allBtn.forEach(function (item, i) {
                    item.classList.remove("active")
                })
                huabiBtn.classList.add("active")
                huaban.type = "huabi"
            }
    
            var rectBtn = document.querySelector("#rect")
            rectBtn.onclick = function () {
                allBtn.forEach(function (item, i) {
                    item.classList.remove("active")
                })
                rectBtn.classList.add("active")
                huaban.type = "rect"
            }
    
            //设置粗细的按钮
            var lineDivs = document.querySelectorAll(".line")
            lineDivs.forEach(function (item, i) {
                item.onclick = function () {
                    lineDivs.forEach(function (a, b) {
                        a.classList.remove("active")
                    })
                    item.classList.add('active')
                    if (i == 0) {
                        huaban.lineWidth = 6;
    
                    } else if (i == 1) {
                        huaban.lineWidth = 16;
                    } else {
                        huaban.lineWidth = 32;
                    }
                }
            })
    
            //监听颜色设置改变事件
            var colorInput = document.querySelector("#color")
            colorInput.onchange = function (e) {
                /* console.log(e)
                console.log(colorInput.value) */
                huaban.color = colorInput.value;
            }
    
            //找到下载按钮
            var downloadBtn = document.querySelector(".download")
            downloadBtn.onclick = function () {
                var url = canvas.toDataURL()
                //console.log(url)
                /* var img = new Image()
                img.src = url; */
                /* lcAlert({
                    title:"请点击图片另存!",
                    content:"<img style='width:auto;height:230px;' src='"+url+"'/>"
                }) */
    
                var aDom = document.querySelector(".download2 a")
                aDom.setAttribute("href", url);
                //自动触发点击事件
                aDom.click()
            }
            //监听鼠标按下事件
            canvas.onmousedown = function (e) {
                huaban.isDraw = true;
                if (huaban.type == "rect") {
                    var x = e.pageX - canvas.offsetLeft;
                    var y = e.pageY - canvas.offsetTop;
                    huaban.beginX = x;
                    huaban.beginY = y;
                }
                if (huaban.type == "huabi") {
                    var x = e.pageX - canvas.offsetLeft;
                    var y = e.pageY - canvas.offsetTop;
                    huaban.beginX = x;
                    huaban.beginY = y;
                    ctx.beginPath()
                    ctx.moveTo(x, y)
                }
            }
            //监听鼠标抬起事件
            canvas.onmouseup = function () {
                huaban.imageData = ctx.getImageData(0, 0, canvas.offsetWidth, canvas.offsetHeight)
                huaban.isDraw = false;
                if (huaban.type == "huabi") {
                    ctx.closePath()
                }
            }
            canvas.onmousemove = function (e) {
                if (huaban.isDraw) {
                    var strFn = huaban.type + 'Fn'
                    /* console.log(huaban) */
                    huaban[strFn](e)
                }
            }
        </script>
    </body>
    </html>
    
    image.png

    相关文章

      网友评论

          本文标题:Canvas

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