前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >HTML5 Canvas开发详解(实战一)

HTML5 Canvas开发详解(实战一)

作者头像
爱学习的程序媛
发布2022-04-07 15:56:42
发布2022-04-07 15:56:42
90700
代码可运行
举报
文章被收录于专栏:学习/读书笔记学习/读书笔记
运行总次数:0
代码可运行

针对 HTML5 Canvas开发详解(基础一)的基础知识,写了一些实战案例,本节的案例代码是写在vue搭建的项目中的,引用了element-ui的按钮组件,如果大家要运行本节代码,以组件的形式引到自有vue项目的某个父组件即可。

案例效果:

http://mpvideo.qpic.cn/0bf2tiaaaaaaimap63n5a5pfbgwdacnaaaaa.f10002.mp4?dis_k=65ce2c5d6982464365e2468e01b46790&dis_t=1649318155&vid=wxv_1340798768203251715&format_id=10002&support_redirect=0&mmversion=false

案例代码:

代码语言:javascript
代码运行次数:0
运行
复制
my-canvas.vue

<template>
    <div class="container">
        <div class="opt-btn">
            <el-button type="primary" size="mini" v-for="(item, index) in optBtnData" :key="index" @click="item.clickBtnFunc">{{item.text}}</el-button>
        </div>
        <canvas ref="myCanvas" class="my-canvas" width="300" height="300"></canvas>
    </div>
</template>

<script>
    export default {
        data(){
            return {
                timer: null,//定时器
                cnvObj: null,//canvas对象
                cxtObj: null,//上下文环境对象
                optBtnData: [// 操作按钮数据
                    {text: '绘制箭头', clickBtnFunc: () => {this.drawArrows(this.arrowsData, this.cxtObj)}},
                    {text: '绘制正多边形', clickBtnFunc: () => {this.drawEqPolygon(3)}},
                    {text: '绘制多角星', clickBtnFunc: () => {this.drawPolyStar(5)}},
                    {text: '绘制方格调色板', clickBtnFunc: () => {this.drawCheckPallet()}},
                    {text: '绘制渐变调色板', clickBtnFunc: () => {this.drawGradualChangePallet()}},
                    {text: '绘制圆角矩形', clickBtnFunc: () => {this.drawCircleAngleRectangle()}},
                    {text: '绘制气泡', clickBtnFunc: () => {this.drawBubble(this.cxtObj)}},
                    {text: '绘制心形', clickBtnFunc: () => {this.drawHeart(this.cxtObj)}},
                    {text: '绘制N叶草', clickBtnFunc: () => {this.drawLeaf(4)}},
                    {text: '绘制扇形', clickBtnFunc: () => {this.drawSector()}}
                ],
                arrowsData: {//绘制箭头数据
                    moveToObj: {x: 40, y: 60},
                    lineToArr: [
                        {x: 100, y: 60}, {x: 100, y: 30}, {x: 150, y: 75},
                        {x: 100, y: 120}, {x: 100, y: 90}, {x: 40, y: 90}
                    ]
                },
                bubbleData: {//绘制气泡数据
                    moveToObj: {x: 75, y: 25},
                    quadCurveToArr: [
                        {cx: 25, cy: 25, x: 25, y: 62},
                        {cx: 25, cy: 100, x: 50, y: 100},
                        {cx: 50, cy: 120, x: 30, y: 125},
                        {cx: 60, cy: 120, x: 65, y: 100},
                        {cx: 125, cy: 100, x: 125, y: 62},
                        {cx: 125, cy: 25, x: 75, y: 25}
                    ]
                },
                heartData: {//绘制心形数据
                    moveToObj: {x: 75, y: 40},
                    bezierCurveToArr: [
                      {cx1: 75, cy1: 37, cx2: 70, cy2: 25, x: 50, y: 25},
                      {cx1: 20, cy1: 25, cx2: 20, cy2: 62.5, x: 20, y: 62.5},
                      {cx1: 20, cy1: 80, cx2: 40, cy2: 102, x: 75, y: 120},
                      {cx1: 110, cy1: 102, cx2: 130, cy2: 80, x: 130, y: 62.5},
                      {cx1: 130, cy1: 62.5, cx2: 130, cy2: 25, x: 100, y: 25},
                      {cx1: 85, cy1: 25, cx2: 75, cy2: 37, x: 75, y: 40}
                    ]
                }
            }
        },
        mounted(){
            this.initData();
        },
        methods: {
            //初始化数据
            initData(){
                this.cnvObj = this.$refs.myCanvas;
                this.cxtObj = this.cnvObj.getContext('2d');
            },
            //清空画布
            clearCanvas(){
                this.cxtObj.clearRect(0, 0, this.cnvObj.width, this.cnvObj.height);
                this.cxtObj.beginPath();
            },
            //清除定时器
            clearTimer(){
                clearInterval(this.timer);
            },
            //绘制箭头
            drawArrows(arrowsData, cxt){
                this.clearTimer();
                this.clearCanvas();
                let moveToObj = arrowsData.moveToObj;
                let lineToArr = arrowsData.lineToArr;
                this.cxtObj.moveTo(moveToObj.x, moveToObj.y);
                lineToArr.forEach(val => cxt.lineTo(val.x, val.y));
                cxt.closePath();
                cxt.stroke();
            },
            /*
            * 绘制正多边形
            * n:表示n边
            * dx、dy:表示n边形中心坐标
            * l:表示边长
            * */
            drawEqPolygon(n){
                this.clearTimer();
                this.timer = setInterval(() => {
                    this.clearCanvas();
                    this._drawEqPolygon(this.cxtObj, n++, this.cnvObj.width/2, this.cnvObj.height/2, 60);
                    if(n > 10){
                        this.clearTimer();
                    }
                }, 500);
            },
            _drawEqPolygon(cxt, n, dx, dy, l){
                let degree = (2 * Math.PI) / n;
                for(let i = 0; i < n; i++){
                    let x = Math.cos(i * degree);
                    let y = Math.sin(i * degree);
                    cxt.lineTo(x * l + dx, y * l + dy);
                }
                cxt.closePath();
                cxt.stroke();
            },
            /*
            * 绘制多角星
            * n:表示n角
            * dx、dy:表示n角星中心坐标
            * r1、 r2 表示内半径和外半径
            * */
            drawPolyStar(n){
                this.clearTimer();
                this.timer = setInterval(() => {
                    this.clearCanvas();
                    this._drawPolyStar(this.cxtObj, n++, this.cnvObj.width/2, this.cnvObj.height/2, 15, 50);
                    if(n > 10){
                        clearInterval(this.timer)
                    }
                }, 500);
            },
            _drawPolyStar(cxt, n, dx, dy, r1, r2){
                for(let i = 0; i < n; i++){
                    let p1 = (r1 + i * 360 / n) * Math.PI / 180;
                    let p2 = (r2 + i * 360 / n) * Math.PI / 180;
                    cxt.lineTo(Math.cos(p1) * r1 + dx, -Math.sin(p1) * r1 + dy);
                    cxt.lineTo(Math.cos(p2) * r2 + dx, -Math.sin(p2) * r2 + dy);
                }
                cxt.closePath();
                cxt.stroke();
            },
            /*
            * 绘制方格调色板
            * n:表示n行n列
            * blue:表示b的值,0-255
            * w:表示每格的宽度
            * */
            drawCheckPallet(){
                this.clearTimer();
                this.clearCanvas();
                this._drawCheckPallet(this.cxtObj, 60, 120, 5);
            },
            _drawCheckPallet(cxt, n, blue, w){
                for(let i = 0; i < n; i++){
                    for(let j = 0; j < n; j++){
                        let r = Math.floor(255 - 255 / n * i);
                        let g = Math.floor(255 - 255 / n * j);
                        let b = Math.floor(blue);
                        cxt.fillStyle = `rgb(${r}, ${g}, ${b})`;
                        cxt.fillRect(j * w, i * w, w, w);
                    }
                }
            },
            //绘制渐变调色板
            drawGradualChangePallet(){
                this.clearTimer();
                this.clearCanvas();
                this._drawGradualChangePallet(this.cnvObj, this.cxtObj, 160, 3, 10);
            },
            _drawGradualChangePallet(cnv, cxt, n, w, step){
                let r = 255, g = 0, b = 0;
                let n_8 = n / 8;
                let n_4 = n / 4;
                let n_2 = n / 2;
                for(let i = 0; i < n; i++){
                    if(i < n_8){
                        g += step;
                    } else if(i > n_8 && i < n_4){
                        r -= step;
                    } else if(i > n_4 && i < n_2){
                        g -= step;
                        b += step;
                    } else if(i >= n_2 && i < n){
                        r += step;
                    }else {
                        b -= step;
                    }
                    cxt.fillStyle = `rgb(${r}, ${g}, ${b})`;
                    cxt.fillRect(w * i, 0, w, cnv.height);
                }
            },
            /*
            * 绘制圆角矩形
            * width、height:分别表示宽和高
            * r:表示圆角半径
            * offsetX、 offsetY:分别表示左上角顶点坐标
            * */
            drawCircleAngleRectangle(){
                this.clearTimer();
                this.clearCanvas();
                this._drawCircleAngleRectangle(this.cxtObj, 100, 100, 20, 20, 20);
            },
            _drawCircleAngleRectangle(cxt, width, height, r, offsetX, offsetY){
                cxt.moveTo(offsetX + r, offsetY);
                cxt.lineTo(offsetX + width - r, offsetY);
                cxt.arcTo(offsetX + width, offsetY, offsetY + width, offsetY + r, r);
                cxt.lineTo(offsetX + width, offsetY + height - r);
                cxt.arcTo(offsetX + width, offsetY + height, offsetX + width -r, offsetY + height, r);
                cxt.lineTo(offsetX + r, offsetY + height);
                cxt.arcTo(offsetX, offsetY + height, offsetX, offsetY + height - r, r);
                cxt.lineTo(offsetX, offsetY + r);
                cxt.arcTo(offsetX, offsetY, offsetX + r, offsetY, r);
                cxt.closePath();
                cxt.stroke();
            },
            //绘制气泡
            drawBubble(cxt){
                this.clearTimer();
                this.clearCanvas();
                let moveToObj = this.bubbleData.moveToObj;
                let quadCurveToArr = this.bubbleData.quadCurveToArr;
                cxt.moveTo(moveToObj.x, moveToObj.y);
                quadCurveToArr.forEach(val => cxt.quadraticCurveTo(val.cx, val.cy, val.x, val.y))
                cxt.stroke();
            },
            //绘制心形
            drawHeart(cxt){
                this.clearTimer();
                this.clearCanvas();
                let moveToObj = this.heartData.moveToObj;
                let bezierCurveToArr = this.heartData.bezierCurveToArr;
                cxt.moveTo(moveToObj.x, moveToObj.y);
                bezierCurveToArr.forEach(val => cxt.bezierCurveTo(val.cx1, val.cy1, val.cx2, val.cy2, val.x, val.y));
                cxt.fillStyle = 'red';
                cxt.fill();
            },
            /*
            * 绘制N叶草
            * n:表示n片叶子
            * dx、dy:表示叶子中心位置的坐标
            * size:表示叶子的大小
            * length:表示叶子的长度
            * */
            drawLeaf(n){
                this.clearTimer();
                this.timer = setInterval(() => {
                    this.clearCanvas();
                    this._drawLeaf(this.cxtObj, n++, this.cnvObj.width/2, this.cnvObj.height/2, 20, 80);
                    if(n > 10){
                        clearInterval(this.timer)
                    }
                }, 500);
            },
            _drawLeaf(cxt, n, dx, dy, size, length){
                cxt.moveTo(dx, dy + size);
                let degree = 2 * Math.PI / n;
                for(let i = 1; i < n + 1; i++){
                    //计算控制点坐标
                    let cx1 = Math.sin((i - 1) * degree) * length + dx;
                    let cy1 = Math.cos((i - 1) * degree) * length + dy;
                    let cx2 = Math.sin(i * degree) * length + dx;
                    let cy2 = Math.cos(i * degree) * length + dy;
                    //计算结束点的坐标
                    let x = Math.sin(i * degree) * size + dx;
                    let y = Math.cos(i * degree) * size + dy;
                    cxt.bezierCurveTo(cx1, cy1, cx2, cy2, x, y);
                }
                cxt.closePath();
                cxt.fillStyle = '#0f9';
                cxt.fill();
            },
            //绘制扇形
            drawSector(){
                this.clearTimer();
                this.clearCanvas();
                this._drawSector(this.cxtObj, this.cnvObj.width/2, this.cnvObj.height/2, 50, 30, 120);
            },
            _drawSector(cxt, x, y, r, angle1, angle2){
                cxt.moveTo(x, y);
                cxt.arc(x, y, r, angle1 * Math.PI/180, angle2 * Math.PI/180, true);
                cxt.closePath();
                cxt.stroke();
            }
        }
    }
</script>

<style scoped>
  .opt-btn {
      width: 400px;
  }
  .el-button {
      margin: 0 0 10px 10px;
  }
  .my-canvas {
      border: 1px dashed #ccc;
  }
</style>
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 爱学习的程序媛 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档