• canvas入门基础,七巧板、五角星、粒子时钟等


    创建一个canvas

    HTML

    创建canvas元素

    <canvas id="canvas"></canvas>
    

    设置宽高使用标签width,height属性,注意不能使用css或style样式

    display默认为inline

    <canvas id="canvas" width="1024" height="768" style="border: 1px solid #ccc; display: block; margin: 0 auto;">当前浏览器不支持canvas,请更换浏览器后再试</canvas>
    

    JavaScript

    获取canvas

    //获取canvas元素
    var canvas  = document.getElementById('canvas')
    //使用context进行绘制
    var context = canvas.getCountext('2d');
    

    除了通过上面HTML属性设置canvas宽高之外,当然也可以用javascript来设置

    canvas.width = 1024
    canvas.height = 768
    

    也可以使用javascript检测浏览器是否支持canvas

    if(canvas.getContext('2d')){
      var context = canvas.getCountext('2d');
    }else{
      alert('当前浏览器不支持canvas,请更换浏览器后再试')
    }
    

    补充——解决vscode编辑canvas没有代码提示问题

    在定义canvas之前加入如下注释即可

    /** @type {HTMLCanvasElement} */ 
    var canvas = document.getElementById('canvas')
    

    画一条直线

    画布左上角坐标为默认为(0,0),那么我想画一条坐标从(100,100)到(700,700)的直线,该怎么画呢?

    //起笔
    context.beginPath()
    //路径
    context.moveTo(100, 100)
    context.lineTo(700, 700)
    //落笔
    context.closePath()
    //绘制路径
    context.stroke()
    

    beginPath(),closePath()

    beginPath()重新规划一条路线

    closePath()结束当前的路线,如果当前的路线没有封闭则会自动封闭路线

    只绘制一个图形时可以省略这两个方法,但是如果当你再画第二个图形时,下面的context.stroke()会把上面的覆盖,所以注意beginPath(),closePath()的使用

    closePath()的另外一个作用就是封闭图形,如果绘制多个图形又不想封闭图形该怎么做呢?这里可以只写beginPath()省略后面的closePath(),从而绘制多个图形时都不会产生影响,beginPath(),closePath()不一定要成对出现

    beginPath()后的moveTo()可以被lineTo()代替,即可以不写moveTo(),详见下面画五角星中的应用。

    线条属性

    linewidth

    线条宽度,属性值为数字

    lineCap

    线条的边角,注意这个属性的头是突出的,所以比默认线条长度两边各多出一个半径的长度。lineCap只有线条首尾有效果,线条衔接处无效。衔接处使用lineJoin

    描述
    butt 默认。向线条的每个末端添加平直的边缘。
    round 向线条的每个末端添加圆形线帽。
    square 向线条的每个末端添加正方形线帽。
    lineJoin

    当两条线条交汇时,创建边角

    描述
    bevel 创建斜角。
    round 创建圆角。
    miter 默认。创建尖角。
    miterLimit

    w3school教程

    画一个三角形

    context.beginPath()
    //路径
    context.moveTo(100, 100)
    context.lineTo(700, 700)
    context.lineTo(100, 700)
    //封闭
    context.closePath()
    context.stroke()
    

    把线条粗细改成5个像素,颜色为红色

    context.lineWidth = 5
    context.strokeStyle = 'red'
    

    填充封闭空间

    //填充颜色
    context.fillStyle = '#38f'
    context.fill();
    

    补充——stroke和fill调用先后顺序对绘图的影响

    先调用stroke在调用fill,绘制的效果看上去lineWidth只绘制出来一半,这是因为先填充会把边框覆盖掉一半,正确顺序是先调用fill在调用stroke,用边框颜色去覆盖填充颜色就能达到理想效果。

    补充——canvas的”状态“和”绘制“代码书写技巧

    canvas是基于状态进行绘制的,在编程中可以把状态和绘制分开写,这样会更加直观简洁。例如:

    // 路径
    context.beginPath()
    context.moveTo(100, 100)
    context.lineTo(700, 700)
    context.lineTo(100, 700)
    context.closePath()
    // 状态
    context.lineWidth = 5
    context.fillStyle = '#38f'
    context.strokeStyle = 'red'
    // 绘制
    context.fill();
    context.stroke()
    

    绘制七巧板

    参考代码如下,注意beginPath(),closePath()的位置

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>canvas-七巧板</title>
    </head>
    <body>
        <canvas id="canvas" style="border: 1px solid #ccc; display: block; margin: 0 auto;">
            当前浏览器不支持canvas,请更换浏览器后再试
        </canvas>
        <script>
            var tangram = [
                { trajectory: [ {x: 0, y: 0}, {x: 800, y: 0}, {x: 400, y: 400} ], color: '#caff67' },
                { trajectory: [ {x: 0, y: 0}, {x: 400, y: 400}, {x: 0, y: 800} ], color: '#67becf' },
                { trajectory: [ {x: 800, y: 0}, {x: 800, y: 400}, {x: 600, y: 600}, {x: 600, y: 200} ], color: '#ef3d61' },
                { trajectory: [ {x: 600, y: 200}, {x: 600, y: 600}, {x: 400, y: 400} ], color: '#f9f51a' },
                { trajectory: [ {x: 400, y: 400}, {x: 600, y: 600}, {x: 400, y: 800}, {x: 600, y: 600} ], color: '#a594c0' },
                { trajectory: [ {x: 200, y: 600}, {x: 400, y: 800}, {x: 0, y: 800} ], color: '#fa8ecc' },
                { trajectory: [ {x: 800, y: 400}, {x: 800, y: 800}, {x: 400, y: 800} ], color: '#f6ca29' }
            ]
            // 绘制
            function draw(piece, cxt){
                cxt.beginPath()
                cxt.moveTo(piece.trajectory[0].x, piece.trajectory[0].y)
                for(var j = 1; j < piece.trajectory.length; j ++){
                    cxt.lineTo(piece.trajectory[j].x, piece.trajectory[j].y)
                }
                cxt.closePath()
                cxt.fillStyle = piece.color
                cxt.fill();
            }
            window.onload = function(){
                /** @type {HTMLCanvasElement} */ 
                var canvas = document.getElementById('canvas'),
                    context = canvas.getContext('2d')
                // 画布宽高
                canvas.width = 800
                canvas.height = 800
                for(var i = 0; i < tangram.length; i ++){
                    draw(tangram[i], context)
                }
            }
        </script>
    </body>
    </html>
    

    画一个圆弧

    //x:圆的中心的 x 坐标
    //y:圆的中心的 y 坐标
    //r:圆的半径
    //sAngle:起始角,以弧度计。(弧的圆形的三点钟位置是 0 度)
    //eAngle:结束角,以弧度计
    //counterclockwise:可选。规定应该逆时针还是顺时针绘图。False = 顺时针,true = 逆时针。默认顺时针
    context.arc(x,y,r,sAngle,eAngle,counterclockwise);
    

    画一个圆弧

    context.beginPath()
    context.arc(400, 400, 100, 0, 1.5*Math.PI, false)
    context.closePath()
    context.stroke()
    

    如果不想封闭,删除context.closePath()即可

    画一个圆

    弧度从0到2π即可

    context.beginPath()
    context.arc(400, 400, 100, 0, 2*Math.PI, false)
    context.stroke()
    

    小球落体运动

    参考代码

    注意:测试时最好注释render()中的第一行代码 cxt.clearRect(0, 0, WIDTH, HEIGHT) ,这样可以显示出运动轨迹。

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>ball-fall</title>
    </head>
    <body>
        <canvas id="canvas" style="border: 2px solid #ccc; display: block; margin: 20px auto 0;">
            当前浏览器不支持canvas,请更换浏览器后再试
        </canvas>
        <script>
            var ball = {x: 900, y: 200, vx: -4, vy: 0, g: 1.5}
            var WIDTH = 1000, HEIGHT = 700, RIDIUS = 15
            window.onload = function(){
                /** @type {HTMLCanvasElement} */ 
                var canvas = document.getElementById('canvas'),
                    context = canvas.getContext('2d')
                // 画布宽高
                canvas.width = WIDTH
                canvas.height = HEIGHT
                setInterval(function(){
                    render(context)
                    update()
                }, 50)
            }
            function render(cxt){
                cxt.clearRect(0, 0, WIDTH, HEIGHT)
                cxt.beginPath()
                cxt.arc(ball.x, ball.y, RIDIUS, 0, 2*Math.PI)
                cxt.closePath()
                cxt.fillStyle = '#f0f'
                cxt.fill();
            }
            function update(){
                ball.x += ball.vx
                ball.y += ball.vy
                if(ball.y >= HEIGHT-RIDIUS){
                    ball.y = HEIGHT-RIDIUS
                    ball.vy = -ball.vy*0.7
                }else{
                    ball.vy += ball.g
                }
            }
        </script>
    </body>
    </html>
    

    代码中首先定义了小球的基本属性:横坐标,纵坐标,水平速度,垂直速度,加速度

    update()中用到了一个摩擦系数为0.7

    update()

    这里的重点是update函数部分,为什么会这样写?示例代码用到了摩擦系数0.7,运动轨迹看起来差别不大。如果没有摩擦,观察下面几种写法有什么不同。

    // 方法一
    function update(){
      ball.x += ball.vx
      ball.y += ball.vy
      ball.vy += ball.g
      if(ball.y >= HEIGHT-RIDIUS){
        ball.y = HEIGHT-RIDIUS
        ball.vy = -ball.vy
        // 测试打印出最大垂直速度
        console.log(ball.vy)
      }
    }
    // 方法二
    function update(){
      ball.x += ball.vx
      ball.y += ball.vy
      if(ball.y >= HEIGHT-RIDIUS){
        ball.y = HEIGHT-RIDIUS
        ball.vy = -ball.vy
        // 测试打印出最大垂直速度
        console.log(ball.vy)
      }
      ball.vy += ball.g
    }
    // 方法三
    function update(){
      ball.x += ball.vx
      ball.y += ball.vy
      if(ball.y >= HEIGHT-RIDIUS){
        ball.y = HEIGHT-RIDIUS
        ball.vy = -ball.vy
        // 测试打印出最大垂直速度
        console.log(ball.vy)
      }else{
        ball.vy += ball.g
      }
    }
    

    这几种方法都没有摩擦系数,仅仅只是 ball.vy += ball.g 的位置不同而已,经过测试你会发现:方法一弹跳后最高点会越来越高,方法二弹跳后最高点会越来越低,而方法三则都在同一最高点。通过打印出的最大垂直速度不难发现,方法一造成的原因是每次小球落到最低点都多加了一次 ball.g ,方法二同理。方法三是在水平线以上才会累加垂直速度。

    上抛效果

    其实上抛效果很简单,只需要将 ball.vy 的初始值设置为负值即可,这里需要注意 ball.vy 的值尽量按照加速度的值来设定,最好是加速度的倍数,这样能够保证最高点的垂直速度为0,运动轨迹都有统一的焦点。

    这里还有一个问题:设置过上抛效果后,第一个最高点可能和之后的最高点不同,造成这个原因是因为小球落到最低处时的位置不一定刚好等于HEIGHT-RIDIUS,示例代码中是强制不让小球出界。如下

     if(ball.y >= HEIGHT-RIDIUS){
        ball.y = HEIGHT-RIDIUS
      }
    

    如果注释ball.y = HEIGHT-RIDIUS这行代码你会发现路径的最高点都一样了。

    这里最简单的解决方法就是调整ball的初始位置,使其下落到最低点时刚好是边界的高度,即ball.y == HEIGHT-RIDIUS

    动态粒子时钟效果

    参考代码 演示digit.js文件地址

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>canvas-clock</title>
        <style>
            * {margin: 0; padding: 0;}
        </style>
    </head>
    <body>
        <canvas id="canvas" style="display: block;background-color: black;">当前浏览器不支持canvas,请更换浏览器后再试</canvas>
        <script>
            var WIDTH, HEIGHT, LEFT, TOP, RADIUS, timeSeconds, balls = [], timer
            window.onload = function () {
                /** @type {HTMLCanvasElement} */
                var canvas = document.getElementById('canvas'),
                    context = canvas.getContext('2d')
                // 自适应窗口大小
                WIDTH = document.documentElement.clientWidth
                HEIGHT = document.documentElement.clientHeight
                // 边距(先计算RADIUS)
                RADIUS = Math.round(WIDTH / 170)
                LEFT = Math.round((WIDTH - 107 * RADIUS) / 2)
                TOP = Math.round((HEIGHT - 20 * RADIUS) / 3)
                timeSeconds = getTime()
                // 画布宽高
                canvas.width = WIDTH
                canvas.height = HEIGHT
                animation(context)
                // 监听当前页面是否被隐藏
                document.addEventListener('visibilitychange', function () {
                    if (document.visibilityState == 'hidden') {
                        clearInterval(timer)
                    } else if (document.visibilityState == 'visible') {
                        animation(context)
                    }
                })
            }
            // 小球下落动画
            function animation(context) {
                timer = setInterval(function () {
                    render(context)
                    update()
                }, 50)
            }
            // 渲染页面
            function render(cxt) {
                var hours = parseInt(timeSeconds / 3600),
                    minutes = parseInt((timeSeconds - hours * 3600) / 60)
                seconds = timeSeconds % 60
                // 首先清空画布
                cxt.clearRect(0, 0, WIDTH, HEIGHT)
                renderDigit(LEFT, TOP, parseInt(hours / 10), cxt)
                renderDigit(LEFT + 15 * RADIUS, TOP, parseInt(hours % 10), cxt)
                renderDigit(LEFT + 30 * RADIUS, TOP, 10, cxt)
                renderDigit(LEFT + 39 * RADIUS, TOP, parseInt(minutes / 10), cxt)
                renderDigit(LEFT + 54 * RADIUS, TOP, parseInt(minutes % 10), cxt)
                renderDigit(LEFT + 69 * RADIUS, TOP, 10, cxt)
                renderDigit(LEFT + 78 * RADIUS, TOP, parseInt(seconds / 10), cxt)
                renderDigit(LEFT + 93 * RADIUS, TOP, parseInt(seconds % 10), cxt)
                // 渲染下落的小球
                for (var i = 0; i < balls.length; i++) {
                    cxt.fillStyle = balls[i].color
                    cxt.beginPath()
                    cxt.arc(balls[i].x, balls[i].y, RADIUS, 0, 2 * Math.PI, true)
                    cxt.closePath()
                    cxt.fill()
                }
            }
            // 更新画布
            function update() {
                var nextTimeSeconds = getTime(),
                    nextHours = parseInt(nextTimeSeconds / 3600),
                    nextMinutes = parseInt((nextTimeSeconds - nextHours * 3600) / 60),
                    nextSeconds = nextTimeSeconds % 60,
                    curHours = parseInt(timeSeconds / 3600),
                    curMinutes = parseInt((timeSeconds - curHours * 3600) / 60),
                    curSeconds = timeSeconds % 60
                if (nextSeconds !== curSeconds) {
                    // 判断被改变的数字,判断小球位置
                    if (parseInt(curHours / 10) != parseInt(nextHours / 10)) {
                        addBalls(LEFT + 0, TOP, parseInt(curHours / 10))
                    }
                    if (parseInt(curHours % 10) != parseInt(nextHours % 10)) {
                        addBalls(LEFT + 15 * RADIUS, TOP, parseInt(curHours / 10))
                    }
                    if (parseInt(curMinutes / 10) != parseInt(nextMinutes / 10)) {
                        addBalls(LEFT + 39 * RADIUS, TOP, parseInt(curMinutes / 10))
                    }
                    if (parseInt(curMinutes % 10) != parseInt(nextMinutes % 10)) {
                        addBalls(LEFT + 54 * RADIUS, TOP, parseInt(curMinutes % 10))
                    }
                    if (parseInt(curSeconds / 10) != parseInt(nextSeconds / 10)) {
                        addBalls(LEFT + 78 * RADIUS, TOP, parseInt(curSeconds / 10))
                    }
                    if (parseInt(curSeconds % 10) != parseInt(nextSeconds % 10)) {
                        addBalls(LEFT + 93 * RADIUS, TOP, parseInt(nextSeconds % 10))
                    }
                    // 同步显示时间
                    timeSeconds = nextTimeSeconds
                }
                updateBalls()
            }
            // 按照数字添加小球个数
            function addBalls(x, y, num) {
                for (var i = 0; i < digit[num].length; i++){
                    for (var j = 0; j < digit[num][i].length; j++){
                        if (digit[num][i][j] == 1) {
                            var aBall = {
                                x: x + j * 2 * RADIUS + RADIUS,
                                y: y + i * 2 * RADIUS + RADIUS,
                                g: 1.5 + Math.random(),
                                vx: Math.pow(-1, Math.ceil(Math.random() * 1000)) * 4,
                                vy: -5,
                                color: getRandomColor()
                            }
                            balls.push(aBall)
                        }
                    }
                }
            }
            // 更新下落小球的位置
            function updateBalls() {
                for (var i = 0; i < balls.length; i++) {
                    balls[i].x += balls[i].vx
                    balls[i].y += balls[i].vy
                    // 反弹效果
                    if (balls[i].y >= HEIGHT - RADIUS) {
                        balls[i].y = HEIGHT - RADIUS
                        balls[i].vy = - Math.abs(balls[i].vy) * 0.75
                    }else{
                    	balls[i].vy += balls[i].g
                    }
                }
                // 删除超出界面外的小球
                for (var i = 0; i < balls.length; i++) {
                    if (balls[i].x + RADIUS < 0 || balls[i].x - RADIUS > WIDTH) {
                        balls.splice(i, 1)
                    }
                }
            }
            // 获取时间
            function getTime() {
                var curTime = new Date()
                return curTime.getHours() * 3600 + curTime.getMinutes() * 60 + curTime.getSeconds()
            }
            // 渲染数字
            function renderDigit(x, y, num, cxt) {
                cxt.fillStyle = "rgb(0,102,153)"
                for (var i = 0; i < digit[num].length; i++) {
                    for (var j = 0; j < digit[num][i].length; j++) {
                        if (digit[num][i][j] == 1) {
                            cxt.beginPath()
                            cxt.arc(x + j * 2 * RADIUS + RADIUS, y + i * 2 * RADIUS + RADIUS, RADIUS, 0, 2 * Math.PI)
                            cxt.closePath()
                            cxt.fill()
                        }
                    }
                }
            }
            // 获取随机颜色
            function getRandomColor() {
                return '#' +
                    (function (color) {
                        return (color += '5678956789defdef'[Math.floor(Math.random() * 16)]) &&
                            (color.length == 6) ? color : arguments.callee(color)
                    })('')
            }
        </script>
        <script src="./digit.js"></script>
    </body>
    </html>
    

    画一个矩形

    通过上面的方法,已经可以用线条画出一个封闭矩形,除此之外canvas还为我们提供了直接绘制矩形的方法。调用即可

    context.rect(x,y,width,height)
    context.fillRect(x,y,width,height)
    context.strokeRect(x,y,width,height)
    

    画一个五角星

    参考代码

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>start</title>
    </head>
    <body>
        <canvas id="canvas" style="border: 2px solid #ccc; display: block; margin: 20px auto 0;">
            当前浏览器不支持canvas,请更换浏览器后再试
        </canvas>
        <script>
            window.onload = function(){
                /** @type {HTMLCanvasElement} */ 
                var canvas = document.getElementById('canvas'),
                    context = canvas.getContext('2d')
                // 画布宽高
                canvas.width = 800
                canvas.height = 700
    
                context.lineWidth = 10
                drawStart(context, 150, 300, 400, 400)
            }
            // 小圆半径,大圆半径,x,y坐标,顺时针旋转角度(默认0)
            function drawStart(cxt, r, R, x, y, rot = 0){
                cxt.beginPath()
                for(var i = 0; i < 5; i ++){
                    cxt.lineTo(Math.cos((18 + i*72 - rot)/180 * Math.PI) * R + x, 
                               -Math.sin((18 + i*72 - rot)/180 * Math.PI) * R + y)
                    cxt.lineTo(Math.cos((54 + i*72 - rot)/180 * Math.PI) * r + x, 
                               -Math.sin((54 + i*72 - rot)/180 * Math.PI) * r + y)
                }
                cxt.closePath()
                cxt.stroke()
            }
        </script>
    </body>
    </html>
    

    思路:五角星的五个内顶点在小圆上,外顶点在大圆上。以圆心为坐标原点,五角星上顶点在y轴,建立坐标系,注意canvas中y轴方向向下。五角星中每个顶点坐标相差72度,简单计算即可得到五角星各个顶点的位置。

    图解

    star

    星空效果

    参考代码

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>starts</title>
        <style>*{margin: 0; padding: 0;}</style>
    </head>
    <body>
        <canvas id="canvas" style="display: block; background-color: black;">
            当前浏览器不支持canvas,请更换浏览器后再试
        </canvas>
        <script>
            var WIDTH, HEIGHT 
            window.onload = function(){
                /** @type {HTMLCanvasElement} */ 
                var canvas = document.getElementById('canvas'),
                    context = canvas.getContext('2d')
                // 画布宽高
                WIDTH = document.documentElement.clientWidth
                HEIGHT = document.documentElement.clientHeight
                canvas.width = WIDTH
                canvas.height = HEIGHT
    
                for(var i = 0; i < 100; i ++){
                    var r = Math.random()*10 + 10,
                        x = Math.random()*(WIDTH - 2*r) + r,
                        y = Math.random()*(HEIGHT - 2*r) + r,
                        a = Math.random()*360
                    drawStart(context, x, y, r/2, r, a)
                }
            }
            function drawStart(cxt, x, y, r, R, rot = 0){
                cxt.beginPath()
                for(var i = 0; i < 5; i ++){
                    cxt.lineTo(Math.cos((18 + i*72 - rot)/180 * Math.PI) * R + x,
                               -Math.sin((18 + i*72 - rot)/180 * Math.PI) * R + y)
                    cxt.lineTo(Math.cos((54 + i*72 - rot)/180 * Math.PI) * r + x, 
                               -Math.sin((54 + i*72 - rot)/180 * Math.PI) * r + y)
                }
                cxt.closePath()
                cxt.fillStyle = 'yellow'
                cxt.fill()
            }
        </script>
    </body>
    </html>
    

    线性渐变

    示例代码

    <!DOCTYPE html>
    <html lang="zh_CN">
    <head>
        <meta charset="UTF-8">
        <title>linear-gradient</title>
    </head>
    <body>
        <canvas id="canvas" style="display: block; border: 2px solid #ccc; margin: 30px auto 0;">
            当前浏览器不支持canvas,请更换浏览器后再试
        </canvas>
        <script>
            window.onload = function () {
                /** @type {HTMLCanvasElement} */
                var canvas = document.getElementById('canvas'),
                    context = canvas.getContext('2d')
                // 画布宽高
                canvas.width = 700
                canvas.height = 700
    
                var linearGrad = context.createLinearGradient(0, 0, 700, 700)
                linearGrad.addColorStop(0.0, 'red')
                linearGrad.addColorStop(0.25, 'yellow')
                linearGrad.addColorStop(0.5, 'green')
                linearGrad.addColorStop(0.75, 'blue')
                linearGrad.addColorStop(1.0, 'coral')
                context.fillStyle = linearGrad
                context.fillRect(0, 0, 700, 700)
            }
        </script>
    </body>
    </html>
    

    径向渐变

    示例代码

    <!DOCTYPE html>
    <html lang="zh_CN">
    <head>
        <meta charset="UTF-8">
        <title>radial-gradient</title>
    </head>
    <body>
        <canvas id="canvas" style="display: block; border: 2px solid #ccc; margin: 30px auto 0;">
            当前浏览器不支持canvas,请更换浏览器后再试
        </canvas>
        <script>
            window.onload = function () {
                /** @type {HTMLCanvasElement} */
                var canvas = document.getElementById('canvas'),
                    context = canvas.getContext('2d')
                // 画布宽高
                canvas.width = 700
                canvas.height = 700
    
                var radialGrad = context.createRadialGradient(350, 350, 0, 350, 350, 400)
                radialGrad.addColorStop(0.0, 'red')
                radialGrad.addColorStop(0.25, 'yellow')
                radialGrad.addColorStop(0.5, 'green')
                radialGrad.addColorStop(0.75, 'blue')
                radialGrad.addColorStop(1.0, 'coral')
                context.fillStyle = radialGrad
                context.fillRect(0, 0, 700, 700)
            }
        </script>
    </body>
    </html>
    

    使用图片、画布、或者video

    createPattern(img, repeat-style)
    createPattern(canvas, repeat-style)
    createPattern(video, repeat-style)
    // repeat-style: no-repeat
    // 				repeat-x
    // 				repeat-x
    // 				repeat-y
    // 				repeat
    
    完结~
  • 相关阅读:
    最短路(Floyed、Dijkstra、Bellman-Ford、SPFA)
    查找技术
    简单线段树
    dfs
    bfs
    插件工具集合
    Web前端代码规范
    Javascript 判断手机横竖屏状态
    Git 笔记2
    git 笔记 1
  • 原文地址:https://www.cnblogs.com/lwlblog/p/12346205.html
Copyright © 2020-2023  润新知