CSS基础12-canvas

canvas

介绍

H5新特性,canvas被用来绘制图形,制作图片集合,甚至用来实现动画效果

属性值

只有width和height属性

画线

  1. 通过const cvs = document.querySelector(‘canvas’)拿到DOM元素
  2. 通过const ctx = cvs.getcontext(“2d”)拿到CanvasRenderingContext2D的类型对象
  3. 开启一条路径ctx.beginPath()
  4. 开始位置ctx.moveTo(x,y)
  5. 结束位置ctx.lineTo(x,y)
  6. 进行上色ctx.stroke()
  7. 关闭路径ctx.closePath()
  8. 设置绘线的粗细ctx.lineWidth,默认值为1.0
  9. 设置线段端点显示的样子,butt,round 和 square
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>Document</title>
    <style>
        canvas{
      
      
            margin: 0 auto;
            border: 1px solid #000;
            display: block;
        }
    </style>
</head>
<body>
    <canvas width="500" height="500"></canvas>
    <script>
        const canvas = document.querySelector('canvas');
        const ctx = canvas.getContext('2d');
		// 画虚线
        for (let i = 0; i < 20; i++) {
      
      
            drawLine(100+10*i,100,105+10*i,100,'green',2)
        }
		
        function drawLine(x1,y1,x2,y2,color,width){
      
      
            ctx.beginPath();
            ctx.moveTo(x1,y1);
            ctx.lineTo(x2,y2);
            ctx.strokeStyle=color;
            ctx.lineWidth=width;
            ctx.stroke();
            ctx.closePath();
        }
    </script>
</body>
</html>

画矩形

  • rect(x,y,width,height)
    • x,y矩形坐标
    • width,height宽高
  • strokeRect(x,y,width,height)
    • 描边矩形
  • fillRect(x,y,width,height)
    • 填空矩形
    • 会自动闭合路径
  • clearRect(x,y,width,height)
    • 清除矩形
    • 清空画布,类似与橡皮檫

画圆

  • arc(x,y,radius,startAngle,endAngle,counterclockwise)
    • x,y描述圆心坐标
    • radius圆形半径
    • startAngle,endAngle起始角度和结束角度
    • counterclockwise顺时针和逆时针

绘制文字

  • fillText()绘制无填充文字
  • strokeText()绘制有填充文字
  • measureText()返回文本宽度对象
  • font='red’CSS样式
  • textBaseline='bottom’设置底线对齐绘制基线
  • textAlign='left’设置文字对齐方式
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>Document</title>
    <style>
        canvas{
      
      
            margin: 0 auto;
            border: 1px solid #000;
            display: block;
        }
    </style>
</head>
<body>
    <canvas width="600" height="600"></canvas>
    <script>
   		// 绘制饼状图并显示比例
        const canvas = document.querySelector('canvas');
        const ctx = canvas.getContext('2d');

        const data = [{
      
      
            value:'苹果',
            color:'red',
            num:0.1,
        },{
      
      
            value: '香蕉',
            color:'yellow',
            num:0.3,
        },{
      
      
            value: '梨子',
            color: 'green',
            num:0.4,
        },{
      
      
            value: '橘子',
            color: 'orange',
            num:0.2
        }]
        let temAngle=-90;
        for (let i = 0; i < data.length; i++) {
      
      
            const angle=data[i].num*360;
            drawArc(300,300,200,angle,data[i].color,data[i].num)
        }
        function drawArc(x1,y1,radius,angle,color,num){
      
      
            ctx.beginPath();
            ctx.moveTo(x1,y1);
            ctx.fillStyle=color;
            const startAngle=temAngle*Math.PI/180;
            const endAngle=(temAngle+angle)*Math.PI/180;
            ctx.arc(x1,y1,radius,startAngle,endAngle);
            // 绘制文字
            const text=num*100+'%';
            const textAngle=temAngle+1/2*angle;
            const x=x1+Math.cos(textAngle*Math.PI/180)*(radius+20);
            const y=y1+Math.sin(textAngle*Math.PI/180)*radius;
            if(textAngle>90&&textAngle<270){
      
      
                ctx.textAlign='end'
            }
            ctx.fillText(text,x,y)
            ctx.fill();
            temAngle+=angle;
        }
    </script>
</body>
</html>

绘制图片

  • context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height)
    • imgDOM对象||也可以是画布,也就是把一个画布整体的渲染到另外一个画布上
    • sx,sy裁剪框左上角X和Y坐标
    • swidth,sheight裁剪宽高
    • x,y图片坐标
    • width,height图片宽高
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>Document</title>
    <style>
        canvas{
    
    
            margin: 0 auto;
            border: 1px solid #000;
            display: block;
        }
    </style>
</head>
<body>
    <canvas width="500" height="500"></canvas>
    <script>
    	// 绘制帧动画
        const canvas = document.querySelector('canvas');
        const ctx = canvas.getContext('2d');

        const img=new Image();
        img.src='./imgs/ying.jpeg';
        img.onload=function (){
    
    
            let frameIndex=0;
            let dirIndex=0;
            setInterval(()=>{
    
    
                ctx.clearRect(0,0,canvas.width,canvas.height);
                ctx.drawImage(
                    img,
                    frameIndex*130,
                    dirIndex*164,
                    130,
                    164,
                    100,
                    100,
                    130*2,
                    164*2
                )
                frameIndex++;
                frameIndex%=3;
                console.log(frameIndex)
                if(frameIndex===2){
    
    
                    dirIndex++
                }
                dirIndex%=2;
            },1000/4)
        }
    </script>
</body>
</html>

阴影与线性渐变和圆形渐变

阴影

  • shadowColor : 设置或返回用于阴影的颜色
  • shadowBlur : 设置或返回用于阴影的模糊级别,大于 1 的正整数,数值越高,模糊程度越大
  • shadowOffsetX: 设置或返回阴影距形状的水平距离
  • shadowOffsetY: 设置或返回阴影距形状的垂直距离

线性渐变

  • ctx.createLinearGradient(x0,y0,x1,y1);
    • x0,y0 起始坐标
    • x1,y1 结束坐标

圆形渐变

  • context.createRadialGradient(x0,y0,r0,x1,y1,r1)
    • x0: 渐变的开始圆的 x 坐标
    • y0: 渐变的开始圆的 y 坐标
    • r0: 开始圆的半径
    • x1: 渐变的结束圆的 x 坐标
    • y1: 渐变的结束圆的 y 坐标
    • r1: 结束圆的半径
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>Document</title>
    <style>
        canvas{
      
      
            margin: 0 auto;
            border: 1px solid #000;
            display: block;
        }
    </style>
</head>
<body>
    <canvas width="500" height="500"></canvas>
    <script>
        const canvas = document.querySelector('canvas');
        const ctx = canvas.getContext('2d');

        ctx.fillStyle='rgba(255,0,0,0.9)';
        ctx.shadowColor='teal';
        ctx.shadowBlur=10;
        ctx.shadowOffsetX=10;
        ctx.shadowOffsetY=10;
        // 创建线性渐变
        const grd=ctx.createLinearGradient(0,0,170,0);
        grd.addColorStop(0,'black'); // 添加渐变颜色
        grd.addColorStop(0.5,'red')
        grd.addColorStop(1,'white');
        ctx.fillStyle=grd;
        ctx.fillRect(0,0,300,300)
    </script>
</body>
</html>

位移画布

移动

ctx.translate(x,y) 方法重新映射画布上的 (0,0) 位置

旋转

context.rotate(angle); 方法旋转当前的绘图

缩放

context.scale(scalewidth,scaleheight)

保存

ctx.save() 保存当前环境的状态
可以把当前绘制环境进行保存到缓存中。

重置

ctx.restore() 返回之前保存过的路径状态和属性
获取最近缓存的 ctx;需要和save()配合使用

将图片输出为base64格式

  • canvas.toDataURL(type, encoderOptions)
    • type,设置输出的类型,比如 image/png image/jpeg
    • encoderOptions: 0-1 之间的数字,用于标识输出图片的质量,1 表示无损压缩,类型为: image/jpeg 或者 image/webp 才起作用

cnavas对图片裁剪

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>裁剪图片</title>
    <style>
        *{
      
      
            margin: 0;
            padding: 0;
        }
        .wrap{
      
      
            width: 800px;
            margin: 0 auto;
        }
        .canvasBox{
      
      
            width: 600px;
            height: 600px;
            background-color: #eee;
            position: relative;
        }
        .mark{
      
      
            width: 50%;
            height: 50%;
            background-color: rgba(0,0,0,0.5);
            position: absolute;
            top: 150px;
            left: 150px;
            /*display: none;*/
        }
        ul{
      
      
            display: flex;
            width: 600px;
            justify-content: space-between;
        }
        li{
      
      
            list-style: none;
        }
    </style>
</head>
<body>
    <div class="wrap">
        <div class="canvasBox">
            <canvas></canvas>
            <div class="mark"></div>
        </div>
        <ul>
            <li>
                <label for="file">选择图片</label>
                <input
                        id="file"
                        type="file"
                        accept="image/*"
                        style="display: none"
                />
            </li>
            <li onclick="scale(1)">放大</li>
            <li onclick="scale(0)">缩小</li>
            <li onclick="save()">保存</li>
        </ul>
        <img src="" id="img"/>
    </div>
    <script>
        /**
         * 准备数据
         * 1. 画布大小,遮罩大小和位置,上传大小和位置
         */
        let img;
        let imgW;
        let imgH;
        let imgOriginW;
        let imgOriginH;
        let startX;
        let startY;
        const canvasW=600;
        const canvasH=600;

        const fileNode=document.querySelector('#file');
        const canvas = document.querySelector('canvas');
        const ctx = canvas.getContext('2d');
        const canvasBoxNode=document.querySelector('.canvasBox');
        const imgNode=document.querySelector('#img');
        // 拿到file文件
        fileNode.onchange=function (e){
      
      
            const file=e.target.files[0];
            if(!file) return;
            canvas.width=canvasW;
            canvas.height=canvasH;
            // 文件读取
            const fileExample=new FileReader();
            fileExample.readAsDataURL(file);
            fileExample.onload=(e)=>{
      
      
                img=new Image();
                img.src=e.target.result;
                img.onload=()=>{
      
      
                    imgW=img.width;
                    imgH=img.height;
                    imgOriginW=100;
                    imgOriginH=100;
                    drawImage()
                }
            }
            fileNode.value='';
        }
        // 绘制canvas
        function drawImage(){
      
      
            ctx.clearRect(0,0,canvas.width,canvas.height);
            ctx.drawImage(img,imgOriginW,imgOriginH,imgW,imgH)
        }
        // 缩放
        function scale(flag){
      
      
            if(!img) return;
            let n=imgW/imgH;
            const n1=20;
            const n2=n1/n;
            if(flag){
      
      
                imgW+=n1;
                imgH+=n2;
            }else {
      
      
                imgW-=n1;
                imgH-=n2;
            }
            drawImage()
        }
        // 刚移入记录位置
        canvasBoxNode.ontouchstart=function (e){
      
      
            const point=e.changedTouches[0];
            startX=point.clientX;
            startY=point.clientY;
        }
        // 移动记录位置
        canvasBoxNode.ontouchmove=function (e){
      
      
            if(!img) return;
            const point=e.changedTouches[0];
            const x=point.clientX-startX;
            const y=point.clientX-startY;
            console.log(x,y)
            if(Math.abs(x)<20||Math.abs(y)<20) return;
            imgOriginW+=x;
            imgOriginH+=y;
            drawImage();
            startX=point.clientX;
            startY=point.clientY;
        }
        // 保存遮罩内图片
        function save(){
      
      
            if(!img) return;
            const imageData=ctx.getImageData(150,150,300,300);
            const canvas2=document.createElement('canvas');
            const canvas2Ctx=canvas2.getContext('2d');
            canvas2.width=300;
            canvas2.height=300;
            canvas2Ctx.putImageData(imageData,0,0,0,0,300,300);
            imgNode.src=canvas2.toDataURL('image/png')
            console.log(canvas2.toDataURL('image/png'))
        }
    </script>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/weixin_64925940/article/details/126680910
今日推荐