当前位置: 首页 > news >正文

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>

相关文章:

  • javascript时钟的开发制作
  • 应用层协议 —— HTTP(二)
  • Qt之QCompleter的简单使用(自动补全、文本框提示、下拉框提示含源码+注释)
  • MyBatis-Plus(二)
  • Linux-常见命令(三)
  • 【国庆活动】Spring Boot 必知必会的核心理念(二)
  • c++:程序流程结构,顺序结构,选择结构if else,三目运算符
  • 使用 Amazon Rekognition API 进行文本检测和 OCR
  • 内核驱动踩坑记录
  • 半导体中的杂质和缺陷能级
  • SSM毕设项目大学生心理咨询系统792l6(java+VUE+Mybatis+Maven+Mysql)
  • 嵌入式学习的第二天
  • R语言(4) plot函数介绍
  • JVM -- 垃圾回收器7种(四)
  • 模型调优:验证集的作用(就是为了调整超参数)
  • Asm.js的简单介绍
  • CSS实用技巧干货
  • Cumulo 的 ClojureScript 模块已经成型
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • Js基础——数据类型之Null和Undefined
  • leetcode388. Longest Absolute File Path
  • php面试题 汇集2
  • python3 使用 asyncio 代替线程
  • Python3爬取英雄联盟英雄皮肤大图
  • Python实现BT种子转化为磁力链接【实战】
  • ⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)
  • unity如何实现一个固定宽度的orthagraphic相机
  • vue-router的history模式发布配置
  • vue从创建到完整的饿了么(18)购物车详细信息的展示与删除
  • Wamp集成环境 添加PHP的新版本
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 从零开始在ubuntu上搭建node开发环境
  • 浮动相关
  • 跨域
  • 聊聊springcloud的EurekaClientAutoConfiguration
  • 收藏好这篇,别再只说“数据劫持”了
  • 在Unity中实现一个简单的消息管理器
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • "无招胜有招"nbsp;史上最全的互…
  • #QT(TCP网络编程-服务端)
  • (02)vite环境变量配置
  • (C语言)逆序输出字符串
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第2节(共同的基类)
  • (二十四)Flask之flask-session组件
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (十)T检验-第一部分
  • (转)甲方乙方——赵民谈找工作
  • .mat 文件的加载与创建 矩阵变图像? ∈ Matlab 使用笔记
  • .mysql secret在哪_MySQL如何使用索引
  • .net 7 上传文件踩坑
  • .net FrameWork简介,数组,枚举
  • .NET MAUI学习笔记——2.构建第一个程序_初级篇