首页 > 其他分享 >HTML5新特性之Canvas

HTML5新特性之Canvas

时间:2024-08-15 10:26:39浏览次数:11  
标签:Canvas const fillRect ctx canvas 特性 HTML5 100 绘制

<canvas>是⼀个HTML元素,我们可以将它简单理解为⼀个画板,通过Canvas提供的绘制api我们就可以绘制出各种图形。

一、基础

1、渲染上下文

● getContext('2d')

● getContext('webgl')

<body>
    <canvas id="canvas" width="800" height="800" style="background-color: aliceblue;margin: 20px;"></canvas>

    <script>
        const c = document.getElementById('canvas')
        const ctx = c.getContext('2d') //画笔
    </script>
</body>

2、绘制图形

坐标系:

a、线(线,三⻆形,矩形):

  • 绘制: moveTo, lineTo,stroke
  • 设置样式:lineWidth,strokeStyle
  • 路径: beginPath,closePath
<body>
    <canvas id="canvas" width="800" height="800" style="background-color: aliceblue;margin: 20px;"></canvas>

    <script>
        const c = document.getElementById('canvas')
        const ctx = c.getContext('2d') //画笔

        //绘制线段 
        ctx.beginPath() //新建路径,两条线不会互相干扰
        ctx.moveTo(0,10)  //线段起点
        ctx.lineTo(200,10)   //终点
        ctx.strokeStyle = 'orange' //颜色
        ctx.lineWidth = 10
        ctx.stroke() //绘制

        ctx.beginPath()
        ctx.moveTo(0,50)  
        ctx.lineTo(200,50)  
        ctx.strokeStyle = 'green'
        ctx.lineWidth = 10
        ctx.stroke() //绘制

        //绘制三角形
        ctx.beginPath() 
        ctx.moveTo(10,70)  
        ctx.lineTo(200,70)  
        ctx.lineTo(50,200)  
        //ctx.lineTo(10,70)  //图形是闭合的,所以最后一个坐标,等于起始坐标
        ctx.closePath() //让路径闭合
        ctx.fillStyle = 'yellow'
        ctx.fill() //用黄色填充内部
        ctx.lineWidth = 1
        ctx.strokeStyle = 'red'
        ctx.stroke() 

        //绘制矩形 rect()
        ctx.beginPath() 
        ctx.strokeRect(0,220,200,100)
        ctx.fillStyle ='red'
        ctx.fillRect(0,220,200,100)
    </script>
</body>

b、弧线(弧、圆弧/圆)

arc(x, y, radius, startAngle, endAngle, anticlockwise);

<body>
    <canvas id="canvas" width="800" height="800" style="background-color: aliceblue;margin: 20px;"></canvas>

    <script>
        const c = document.getElementById('canvas')
        const ctx = c.getContext('2d') 

        //arc 画弧
        ctx.beginPath()
        //圆心x坐标,圆心y坐标,半径,开始角度,结束角度,顺时针
        ctx.arc(400,400,100,0,Math.PI / 3,false) 
        ctx.strokeStyle = '#9013FE'
        ctx.stroke()
    </script>
</body>

 

c、贝塞尔曲线:

  • 二阶贝塞尔曲线

参数:控制点坐标 ,结束点坐标

⼆阶贝塞尔曲线:quadraticCurveTo(cpx, cpy, x, y);

二阶贝塞尔曲线调试工具:Canvas Quadratic Curve Example (site ointstatic.com)

<body>
    <canvas id="canvas" width="800" height="800" style="background-color: aliceblue;margin: 20px;"></canvas>

    <script>
        const c = document.getElementById('canvas')
        const ctx = c.getContext('2d') 

        //绘制贝塞尔曲线 二阶
        ctx.beginPath()
        // 起点
        ctx.moveTo(100,100)
        //控制点,结束点
        ctx.quadraticCurveTo(200,500,400,400)
        ctx.stroke()

        //绘制辅助线
        ctx.fillStyle =  'red'
        ctx.fillRect(100,100,10,10)
        ctx.fillRect(200,500,10,10)
        ctx.fillRect(400,400,10,10)
    </script>
</body>
  • 三阶贝塞尔曲线

三阶贝塞尔曲线:bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

三阶比二阶多了一个控制点

 三阶贝塞尔曲线调试工具:Canvas Bézier Curve Example (sitepointstatic.com)

<body>
    <canvas id="canvas" width="800" height="800" style="background-color: aliceblue;margin: 20px;"></canvas>

    <script>
        const c = document.getElementById('canvas')
        const ctx = c.getContext('2d') 

        //绘制贝塞尔曲线 二阶
        ctx.beginPath()
        // 起点
        ctx.moveTo(100,100)
        //控制点,结束点
        ctx.quadraticCurveTo(200,500,400,400)
        ctx.stroke()

        //绘制辅助线
        ctx.fillStyle =  'red'
        ctx.fillRect(100,100,10,10)
        ctx.fillRect(200,500,10,10)
        ctx.fillRect(400,400,10,10)
    </script>
</body>

效果:

3、绘图样式

a、线条样式:

  • lineWidth(设置线段的宽度)
  • lineCap(设置线段两端的形状)

  • setLineDash(虚线)

b、渐变

沿着某个方向:

  • 线性渐变 ctx.createLinearGradient(x0, y0, x1, y1);

放射状:

  • 径向渐变 ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);

c、纹理样式

  • ctx.createPattern(image,repetition)
<body>
    <canvas id="canvas" width="800" height="800" style="background-color: aliceblue;margin: 20px;"></canvas>
    <script>
        const c = document.getElementById('canvas')
        const ctx = c.getContext('2d') 

        // ctx.lineWidth = 15 //宽度15
        ctx.lineCap = "round" //两端形状为圆角
        ctx.beginPath()
        ctx.moveTo(50,50)
        ctx.lineTo(300,50)
        //参数是一个数组,表示实线和虚线的长度
        ctx.setLineDash([20,40,50]) //绘制虚线
        ctx.stroke()

        //线性渐变
        //前两个参数:起始点坐标,后两个参数:结束点坐标
        var gradient = ctx.createLinearGradient(0,0,200,0)  
        //在起始位置是绿色,0代表起始
        gradient.addColorStop(0,"green") 
        //在终止位置是蓝色,1代表终止
        gradient.addColorStop(1,"blue")
        ctx.fillStyle = gradient
        ctx.fillRect(50,200,200,100)
        
        //径向渐变
        //圆1圆心坐标,圆1半径,圆2圆心坐标,圆2半径
        var gradient2 = ctx.createRadialGradient(150,450,150,150,450,0)
        gradient2.addColorStop(0,"white") 
        gradient2.addColorStop(1,"green")
        ctx.fillStyle = gradient2
        ctx.fillRect(50,350,200,200)

        //纹理样式
        let img = new Image()
        img.src = './images/pattern.png'
        img.onload = function(){
            var pattern = ctx.createPattern(img,'repeat')
            ctx.fillStyle = pattern
            ctx.fillRect(50,600,300,100)
        }
    </script>
</body>

4、绘制文本

绘制方式:

  • 描边:stokeText()
  • 填充:fillText()

绘制样式:

font、textAlign、direction、textBaseline

阴影:shadowOffsetX和shadowOffsetY、shadowBlur、shadowColor

<body>
    <canvas id="canvas" width="800" height="800" style="background-color: aliceblue;margin: 20px;"></canvas>
    <script>
        const c = document.getElementById('canvas')
        const ctx = c.getContext('2d')
        //88像素 罗马字体 
        ctx.font = "88px Times New Roman"
        //设置阴影
        ctx.shadowOffsetX = 2 //阴影往下偏移两个像素
                ctx.shadowOffsetY = 2 //引用往右偏移两个像素
        ctx.shadowBlur = 2 //模糊值
        ctx.shadowColor = "rgba(255,0,0,0.5)" //颜色
        //第一个参数使绘制的文本内容 第二个和第三个参数是绘制的位置坐标
        // ctx.fillText("hello canvas",100,100)

        //用纹理
        let img = new Image()
        img.src = './images/pattern.png'
        img.onload = function(){
            var pattern = ctx.createPattern(img,'repeat')
            ctx.fillStyle = pattern
            ctx.fillText("hello canvas",100,100)
        }

    </script>
</body>

5、绘制图片

drawImage用法

  • drawImage(image,dx,dy);
  • drawImage(image,dx,dy,dWidth,dHeight);
  • drawImage(image,sx,sy,sWidth,sHeight,dx,dy,dWidth,dHeight);

        param1:要绘制的图选购对象

        param2、param3:从原图像中开始裁剪的坐标

        param4、param5:从原图像裁剪的宽度、高度

        param6、param7:在目标canvas上绘制的坐标

        param8、param9:在目标canvas上绘制的宽度、高度

<body>
    <canvas id="canvas" width="800" height="800" style="background-color: aliceblue;margin: 20px;"></canvas>
    <script>
        const c = document.getElementById('canvas')
        const ctx = c.getContext('2d') 
        let img = new Image()
        img.src = './images/pattern.png'
        //图片加载完成时触发
        img.onload = function(){
            //第一个参数是绘制的图片,
            //第二个和第三个参数是绘制的位置
            //第四个和第五个参数是绘制的大小
            ctx.drawImage(img,0,0,400,200)
        }
        
    </script>
</body>

二、进阶

1、变形

a、平移(translate)、旋转(rotate)、缩放(scale) ——指的是坐标系的平移和旋转

b、状态的保存与恢复

<body>
    <canvas id="canvas" width="800" height="800" style="background-color: aliceblue;margin: 20px;"></canvas>
    <script>
        const c = document.getElementById('canvas')
        const ctx = c.getContext('2d') 

        ctx.fillStyle = "red"
        ctx.fillRect(0,0,100,100)
        //将当前的所有状态进行保存
        ctx.save()
        //translate 平移--给坐标系向下、向右平移了400像素
        ctx.translate(400,400)
        ctx.fillRect(0,0,100,100)

        //恢复状态--相当于坐标系又回到(0,0)
        ctx.restore()
        ctx.fillStyle = "black"
        ctx.fillRect(0,0,50,50)

        //旋转
        ctx.save()
        ctx.fillStyle = "yellow"
        ctx.rotate(Math.PI/6) //旋转30°
        ctx.fillRect(300,0,100,100)
        ctx.restore()

        //缩放
        ctx.save()
        ctx.fillStyle = "blue"
        ctx.scale(0.5,0.5) //缩小一半
        ctx.fillRect(400,400,100,100)
        ctx.restore()

    </script>
</body>

c、transform、setTransform

<body>
    <canvas id="canvas" width="800" height="800" style="background-color: aliceblue;margin: 20px;"></canvas>
    <script>
        const c = document.getElementById('canvas')
        const ctx = c.getContext('2d') 

        //矩阵变换 默认值:ctx.transform(1,0,0,1,0,0)
        //平移 只更改e、f的值
        ctx.save()
        ctx.transform(1,0,0,1,400,400)
        ctx.fillStyle = 'pink'
        ctx.fillRect(0,0,100,100)
        ctx.restore()

        //缩放 只更改a、d的值
        ctx.save()
        ctx.transform(0.5,0,0,0.5,0,0)
        ctx.fillStyle = 'orange'
        ctx.fillRect(0,0,100,100)
        ctx.restore()

        //倾斜 只更改b、c的值
        ctx.save()
        ctx.transform(1,-0.5,-0.5,1,0,0)
        ctx.fillStyle = 'purple'
        ctx.fillRect(100,100,100,100)
        ctx.restore()
    </script>
</body>

2、合成(重要)

  • destination-over: 先绘制的图形盖在后绘制的图形上
  • destination-out :后绘制的图形会把先绘制的图形进行挖空,形成一个镂空效果
<body>
    <canvas id="canvas" width="800" height="800" style="background-color: aliceblue;margin: 20px;"></canvas>
    <script>
        const c = document.getElementById('canvas')
        const ctx = c.getContext('2d') 

        ctx.globalCompositeOperation = 'destination-over';

        ctx.fillStyle = 'blue'
        ctx.fillRect(10,10,100,100)
        ctx.fillStyle = 'red'
        ctx.fillRect(50,50,100,100)
    </script>
</body>

3、裁剪——clip():

  • 需要配合路径去使用(例如:context.arc()、context.rect()),路径所绘制出的图形就是裁剪出的范围,任何后续的绘图操作只会在裁剪范围内显示
  • 在裁剪之前要保存一下当前状态,在裁剪之后恢复状态,以免影响其他绘制
<body>
    <canvas id="canvas" width="800" height="800" style="background-color: aliceblue;margin: 20px;"></canvas>
    <script>
        const c = document.getElementById('canvas')
        const ctx = c.getContext('2d') 

        //裁剪
        ctx.rect(0,0,225,100)
        ctx.clip()

        //绘制文字
        ctx.fillStyle = "green"
        ctx.font = "44px Times New Roman"
        ctx.fillText('hello canvas',50,50)

    </script>
</body>


三、实战

1、放大镜或缩小镜(探照灯/望远镜)

技术点:离屏渲染

将一个canvas对象绘制到另一个canvas对象上

实现思路:

  • 准备两个canvas,将两个图片分别绘制在这两个canvas上,一大一小,大的canvas对用户不可见;
  • 在小图点击鼠标时,计算出在大图上相应的点击坐标,这个坐标就是是圆心;
  • 根据圆心的坐标,减去放大镜的半径,能计算出大图左上角的坐标;
  • 在小图中,根据小图的圆心,和放大镜的半径,裁剪出一个圆;
  • 把大图上的图片进行裁剪,绘制到小图上;
<body>
    <!-- 展示的canvas -->
    <canvas id="canvas" style="display:block;margin:0 auto;border:1px solid #aaa;">
        您的浏览器尚不支持canvas
    </canvas>
    <!-- 不可见的canvas -->
    <canvas id="offCanvas" style="display: none">
    </canvas>

    <script>
        //准备两个画布
        var canvas = document.getElementById("canvas")
        var context = canvas.getContext("2d")

        var offCanvas = document.getElementById("offCanvas")
        var offContext = offCanvas.getContext("2d")

        //设置两个canvas的宽高,大图是小图的2倍(相当于放大2倍)
        canvas.width = 920 / 2
        canvas.height = 1598 / 2

        offCanvas.width = 920
        offCanvas.height = 1598
        
        //在每个canvas中绘制一张图片
        var image = new Image()
        image.src = "./images/3.jpg"
        image.onload = function () {
            context.drawImage(image, 0, 0, canvas.width, canvas.height)
            offContext.drawImage(image, 0, 0, offCanvas.width, offCanvas.height)
        }

        //缩放比
        var scale = 2
        var isMouseDown = false //鼠标是否按下

        //鼠标点下去触发事件
        canvas.onmousedown = function (e) {
            e.preventDefault() //阻止默认的鼠标按下行为
            isMouseDown = true
            //记录鼠标点击位置的坐标
            point = {
                x: e.offsetX,
                y: e.offsetY
            }
            drawCanvasWithMagnifier(true, point)
        }

        //鼠标抬起触发事件
        canvas.onmouseup = function (e) {
            e.preventDefault()
            isMouseDown = false
            drawCanvasWithMagnifier(false)
        }

        //鼠标移出
        canvas.onmouseout = function (e) {
            e.preventDefault()
            isMouseDown = false
            drawCanvasWithMagnifier(false)
        }

        //鼠标移动的时候
        canvas.onmousemove = function (e) {
            e.preventDefault()
            if (isMouseDown == true) {
                point = {
                    x: e.offsetX,
                    y: e.offsetY
                }
                console.log(point.x, point.y)
                drawCanvasWithMagnifier(true, point)
            }
        }

        //画放大镜
        function drawCanvasWithMagnifier(isShowMagnifier, point) {
            // 清空画布上的所有内容
            context.clearRect(0, 0, canvas.width, canvas.height)
            // 在画布上绘制图像
            context.drawImage(image, 0, 0, canvas.width, canvas.height)
            //是否绘制放大镜
            if (isShowMagnifier == true) {
                drawMagnifier(point)
            }
        }

        //画放大镜
        function drawMagnifier(point) {

            // 放大镜的半径
            var mr = 200

            //点击的坐标 * 缩放值 = 大的canvas点的坐标
            var imageLG_cx = point.x * scale
            var imageLG_cy = point.y * scale

            //(sx,sy)是大的canvas左上角的坐标
            var sx = imageLG_cx - mr
            var sy = imageLG_cy - mr

            //(dx,dy)是小的canvas的左上角坐标
            var dx = point.x - mr
            var dy = point.y - mr

            context.save() 
            context.lineWidth = 10.0
            context.strokeStyle = "#ccc"

            //定义一个圆形的裁剪区域,
            context.beginPath()
            context.arc(point.x, point.y, mr, 0, Math.PI * 2, false)
            context.stroke()
            context.clip()

            //绘制图形,但是只在裁剪区域中可见
            context.drawImage(offCanvas, sx, sy, 2 * mr, 2 * mr, dx, dy, 2 * mr, 2 * mr)
            context.restore() 
        }

    </script>
</body>

效果:

<iframe allowfullscreen="true" data-mediaembed="csdn" frameborder="0" id="zYLxLoDU-1723599309241" src="https://live.csdn.net/v/embed/417263"></iframe>

1

2、彩票刮刮乐

技术点:图像合成

利用图像合成让绘制的内容与与原矩形重合部分清空

<body>
    <div id="ggl"
        style=" background: url(../images/ggl.png);background-position: center center;background-size: cover;">
        <div class="wrapper">
            <div class="text">特等奖</div>
            <canvas id="myCanvas" width="400px" height="200px"></canvas>
        </div>

    </div>
    <script type="text/javascript">

        let canvas = document.getElementById('myCanvas');
        let ctx = canvas.getContext('2d');
        
        let isClick = false;
        
        // 绘制灰色涂层
        ctx.fillStyle = '#909399';
        ctx.fillRect(0, 0, 400, 200);
        
        //定义画笔是圆角
        ctx.lineCap = 'round'
        ctx.lineJoin = 'round'
        ctx.lineWidth = 20

        // 鼠标点击按下事件
        canvas.addEventListener('mousedown', (e) => {
            let x = e.offsetX;
            let y = e.offsetY;
            ctx.beginPath();
            // 设置绘制的起点为当前点击的位置
            ctx.moveTo(x, y)
            isClick = true
        })

        // 鼠标移动事件
        canvas.addEventListener('mousemove', (e) => {
            if (!isClick) {
                return
            }
            let x = e.offsetX;
            let y = e.offsetY;
            // 绘制的内容与原矩形重合部分清空
            ctx.globalCompositeOperation = 'destination-out'
            ctx.lineTo(x, y)
            ctx.stroke()
        })

        canvas.addEventListener('mouseup', (e) => {
            isClick = false
        })
    </script>
</body>
<style>
    * {
        margin: 0;
        padding: 0;
    }

    #ggl {
        position: relative;
        width: 729px;
        height: 1073px;
        background-color: yellow;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .wrapper {
        background-color: white;
        position: relative;
        width: 400px;
        height: 200px;
        border-radius: 50px;
        overflow: hidden;
    }

    .text {
        text-align: center;
        line-height: 150px;
        font-size: 28px;
        font-weight: bold;
        color: brown;
    }

    #myCanvas {
        position: absolute;
        top: 0;
        left: 0;
        width: 400px;
        height: 200px;
        margin: 0 auto;

    }
</style>

效果:

<iframe allowfullscreen="true" data-mediaembed="csdn" frameborder="0" id="kKj3sUAa-1723599335813" src="https://live.csdn.net/v/embed/417264"></iframe>

2

标签:Canvas,const,fillRect,ctx,canvas,特性,HTML5,100,绘制
From: https://blog.csdn.net/lxy19980718/article/details/140955713

相关文章

  • canvas实现手动绘制矩形
    开场白虽然在实际的开发中我们很少去绘制流程图就算需要,我们也会通过第3方插件去实现下面我们来简单实现流程图中很小的一部分手动绘制矩形绘制一个矩形的思路我们这里绘制矩形会使用到canvas.strokeRect(x,y,w,h)方法绘制一个描边矩形x:矩形起点的x轴坐标。y:矩形起......
  • 【动画进阶】神奇的卡片 Hover 效果与 Blur 的特性探究
    本文,我们将一起探讨探讨,如下所示的一个卡片Hover动画,应该如何实现:这个效果的几个难点:鼠标移动的过程中,展示当前卡片边缘的border以及发光效果;效果只出现在鼠标附近?这一块的实现方法就有很多种了,可以计算鼠标附近的范围,在范围内去实现的效果,但是这样成本太高了。转换一......
  • IntelliJ IDEA全新版的0个新特性【送源码】
    jetBrains刚刚发布了最新IntelliJIDEA 2024.2版本,做了不少优化性能方面的优化,同时新的ui也默认为启动ui。感兴趣的小伙伴可以下载体验,以下为官方本次介绍:借助IntelliJIDEA2024.2Ultimate,您可以直接在IDE中运行SpringDataJPA方法进行即时仓库查询验证。它还通过提......
  • 详解C++的四大特性(封装,继承,多态,抽象)
    C++的四大特性是面向对象编程(OOP)的核心概念,分别是封装、继承、多态和抽象。这些特性共同构成了C++作为面向对象编程语言的基础。1.封装(Encapsulation)概念:封装是将数据和操作数据的方法绑定在一起,限制对数据的直接访问。通过将数据隐藏在类内部,只暴露必要的接口(如public成......
  • uniapp中如何使用uni.canvasToTempFilePath方法上传Canvas内容为图片,并理解其工作原理
    1.主函数uni.canvasToTempFilePath({ canvasId:'canvasid', fileType:'png', quality:1,//图片质量 success(res){ uni.uploadFile({ url:that.baseUrl+'/file/upload',//后端接口地址 name:'file&......
  • 为什么自动控制原理中要采用对数频率特性曲线(伯德图)进行绘制?
    什么是伯德图?伯德图是系统频率响应的一种图示方法。也称为开环对数频率特性曲线。可以根据伯德图系统频率的角度分析系统性能,包括稳定性,动态品质,稳态误差。伯德图分为两张图,幅频特性和相频特性。1.幅频特性图横坐标为lgw:实际工程中低频成分较多,采用此坐标形式可以扩展低频......
  • [HTML5] 一文读懂H5新特性的应用
    文章目录一、HTML5新增语义化标签1.`<header>`标签语法使用场景常用属性示例代码2.`<footer>`标签语法使用场景常用属性示例代码3.`<nav>`标签语法使用场景常用属性示例代码4.`<article>`标签语法使用场景常用属性示例代码5.`<section>`标签语法使用场景......
  • Box-Cox变换 改善数据的分布特性 实践
    Box-Cox变换改善数据的分布特性实践flyfishBox-Cox变换是一种用于数据变换的技术,常用于改善数据的分布特性。使用Box-Cox变换的情况数据不服从正态分布在许多统计分析和建模方法中,正态性假设是一个重要的前提。例如,线性回归、t检验和ANOVA分析通常假设误差项服从正......
  • Maya 2025.2版本新特性:携手云渲染,释放创作潜能
    Autodesk近期推出了Maya2025.2,这一重大更新为视觉特效、动画制作和游戏开发领域的专业创作者带来了一系列创新功能。同时,MayaCreative2025.2以其用户友好的设计,为小型工作室的艺术家们提供了更轻松的入门体验。现在,结合云渲染技术,Maya2025.2版本不仅带来了技术上的突破,更......
  • HTML5
    HTML5初识HTML网页基本标签图像,超链接,网页布局列表,表格,媒体元素表单及表单应用表单初级验证1.1什么是HTMLHyperTextMarkupLanguage(超文本标记语言)超文本包括:文字,图片,音频,视频,动画等Html5+Css3—>现在使用的版本Html5提供了一些新的元素和一些有趣的新特性,同时也......