最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 假如只剩下canvas标签

    正文概述 掘金(执鸢者)   2021-05-06   477

    一、背景

    假如只剩下canvas标签

    二、绘制流程

    2.1 基本元素

    2.1.1 加载图片

    class DrawImage {
        constructor(ctx, imageObj) {
            this.ctx = ctx;
            this.imageObj = imageObj;
        }
    
        draw() {
            const {centerX, centerY, src, sx = 1, sy = 1} = this.imageObj;
            const img = new Image();
            img.onload = () => {
                const imgWidth = img.width;
                const imgHeight = img.height;
                this.ctx.save();
                this.ctx.scale(sx, sy);
                this.ctx.drawImage(img, centerX - imgWidth * sx / 2, centerY - imgHeight * sy / 2);
                this.ctx.restore();
            };
            img.src = src;
        }
    }
    

    2.1.2 绘制文字

    class DrawText {
        constructor(ctx, textObj) {
            this.ctx = ctx;
            this.textObj = textObj;
        }
    
        draw() {
            const {x, y, font, content, lineHeight = 20, width, fillStyle = '#000000', textAlign = 'start', textBaseline = 'middle'} = this.textObj;
            const branchsContent = this.getBranchsContent(content, width);
            this.ctx.save();
            this.ctx.fillStyle = fillStyle;
            this.ctx.textAlign = textAlign;
            this.ctx.textBaseline = textBaseline;
            this.ctx.font = font;
            branchsContent.forEach((branchContent, index) => {
                this.ctx.fillText(branchContent, x, y + index * lineHeight);
            });
            this.ctx.restore();
        }
    
        getBranchsContent(content, width) {
            if (!width) {
                return [content];
            }
            const charArr = content.split('');
            const branchsContent = [];
            let tempContent = '';
            charArr.forEach(char => {
                if (this.ctx.measureText(tempContent).width < width && this.ctx.measureText(tempContent + char).width <= width) {
                    tempContent += char;
                }
                else {
                    branchsContent.push(tempContent);
                    tempContent = '';
                }
            });
            branchsContent.push(tempContent);
            return branchsContent;
        }
    }
    

    2.1.3 绘制矩形

    class DrawRect {
        constructor(ctx, rectObj) {
            this.ctx = ctx;
            this.rectObj = rectObj;
        }
    
        draw() {
            const {x, y, width, height, fillStyle, lineWidth = 1} = this.rectObj;
            this.ctx.save();
            this.ctx.fillStyle = fillStyle;
            this.ctx.lineWidth = lineWidth;
            this.ctx.fillRect(x, y, width, height);
            this.ctx.restore();
        }
    }
    

    2.1.4 绘制圆

    class DrawCircle {
        constructor(ctx, circleObj) {
            this.ctx = ctx;
            this.circleObj = circleObj;
        }
    
        draw() {
            const {x, y, R, startAngle = 0, endAngle = Math.PI * 2, lineWidth = 1, fillStyle} = this.circleObj;
            this.ctx.save();
            this.ctx.lineWidth = lineWidth;
            this.ctx.fillStyle = fillStyle;
            this.ctx.beginPath();
            this.ctx.arc(x, y, R, startAngle, endAngle);
            this.ctx.closePath();
            this.ctx.fill();
            this.ctx.restore();
        }
    }
    

    2.2 AST树

    2.2.1 静态部分AST树

    const graphicAst = [
        {
            type: 'rect',
            x: 0,
            y: 0,
            width: 1400,
            height: 400,
            fillStyle: '#cec9ae'
        },
        {
            type: 'img',
            centerX: 290,
            centerY: 200,
            sx: 0.9,
            sy: 0.9,
            src: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_match%2F0%2F11858683821%2F0.jpg&refer=http%3A%2F%2Finews.gtimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1622015341&t=cc1bd95777dfa37d88c48bb6e179778e'
        },
        {
            type: 'text',
            x: 600,
            y: 60,
            textAlign: 'start',
            textBaseline: 'middle',
            font: 'normal 40px serif',
            lineHeight: 50,
            width: 180,
            fillStyle: '#000000',
            content: '灰太狼是最好的一头狼,它每天都在梦想着吃羊,一直没有实现,但是从不气馁。'
        },
        {
            type: 'text',
            x: 600,
            y: 170,
            textAlign: 'start',
            textBaseline: 'middle',
            font: 'normal 30px serif',
            lineHeight: 50,
            width: 180,
            fillStyle: '#7F7F7F',
            content: '为灰太狼加油、为灰太狼喝彩,?'
        },
        {
            type: 'text',
            x: 1200,
            y: 360,
            textAlign: 'start',
            textBaseline: 'ideographic',
            font: 'normal 30px serif',
            lineHeight: 50,
            width: 180,
            fillStyle: '#949494',
            content: '阅读'
        },
        {
            type: 'text',
            x: 1260,
            y: 363,
            textAlign: 'start',
            textBaseline: 'ideographic',
            font: 'normal 30px serif',
            lineHeight: 50,
            width: 180,
            fillStyle: '#949494',
            content: '520'
        }
    ];
    

    2.2.2 动态部分AST树

    function getMarqueeAst(startX, endX, count, options = {}) {
        const {y = 15, R = 15} = options;
        if (!(endX >= startX && count > 0)) {
            return [];
        }
        const interval = (endX - startX) / count;
        const marqueeAstArr = [];
        for (let i = 0; i < count; i++) {
            const RValue = Math.random() * 255;
            const GValue = Math.random() * 255;
            const BValue = Math.random() * 255;
            const fillStyle = `rgb(${RValue}, ${GValue}, ${BValue})`;
            marqueeAstArr.push({
                type: 'circle',
                x: startX + i * interval,
                y,
                R,
                fillStyle
            });
        }
    
        return marqueeAstArr;
    }
    

    2.3 主函数类

    class Draw {
        constructor(canvasDom) {
            this._canvasDom = canvasDom;
            this.ctx = this._canvasDom.getContext('2d');
            this.width = this._canvasDom.width;
            this.height = this._canvasDom.height;
        }
    
        // 绘制函数
        draw(ast) {
            ast.forEach(elementObj => {
                this.drawFactory(elementObj);
                const {children} = elementObj;
                // 递归调用
                if (children && Array.isArray(children)) {
                    this.draw(children);
                }
            });
        }
    
        // 工厂模型绘制对应基本元素
        drawFactory(elementObj) {
            const {type} = elementObj;
            switch(type) {
                case 'img': {
                    this.drawImage(elementObj);
                    break;
                }
                case 'text': {
                    this.drawText(elementObj);
                    break;
                }
                case 'rect': {
                    this.drawRect(elementObj);
                    break;
                }
                case 'circle': {
                    this.drawCircle(elementObj);
                    break;
                }
            }
        }
    
        drawImage(imageObj) {
            const drawImage = new DrawImage(this.ctx, imageObj);
            drawImage.draw();
        }
    
        drawText(textObj) {
            const drawText = new DrawText(this.ctx, textObj);
            drawText.draw();
        }
    
        drawRect(rectObj) {
            const drawRect = new DrawRect(this.ctx, rectObj);
            drawRect.draw();
        }
    
        drawCircle(circleObj) {
            const drawCircle = new DrawCircle(this.ctx, circleObj);
            drawCircle.draw();
        }
    
        clearCanvas() {
            this.ctx.clearRect(0, 0, this.width, this.height);
        }
    }
    

    2.4 内容绘制

    2.4.1 静态内容绘制

    const basicCanvasDom = document.getElementById('basicCanvas');
    const drawBasicInstance = new Draw(basicCanvasDom);
    drawBasicInstance.draw(graphicAst);
    

    假如只剩下canvas标签

    2.4.2 绘制动画跑马灯

    const animationCanvasDom = document.getElementById('animationCanvas');
    const drawAnimationInstance = new Draw(animationCanvasDom);
    
    let renderCount = 0;
    function animate() {
        if (renderCount % 5 === 0) {
            drawAnimationInstance.clearCanvas();
            drawAnimationInstance.draw(getMarqueeAst(20, 1440, 22));
            drawAnimationInstance.draw(getMarqueeAst(20, 1440, 22, {
                y: 380
            }));
        }
        window.requestAnimationFrame(animate);
        renderCount++;
    }
    animate();
    

    假如只剩下canvas标签

    1. 本文对应源码,关注公众号“执鸢者”,回复“canvas”获取

    2. 如果觉得这篇文章还不错,来个分享、点赞吧,让更多的人也看到


    起源地下载网 » 假如只剩下canvas标签

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元