Pay attention to the public number “kite”, reply to “Canvas” to get the corresponding source code, reply to “information” to get 500G information (all “arms”), there are professional communication groups waiting for you to come together.

The background,

If all you have left is the Canvas tag, how do you draw the content on the page? This may be a false proposition, but using canvas facts can help accomplish a lot. Today we will use the Canvas +AST syntax tree to build an information flow style.

Second, drawing process

The whole drawing process is divided into three parts: basic elements, AST syntax tree and main function class. Basic elements are pictures, text, rectangles, circles, etc. The AST syntax tree in this case is a JS object that contains some attributes; The main function class refers to the exposed interface that is ultimately drawn through calls.

2.1 Basic Elements

Anything, no matter how complex, must be made up of a series of simple elements. For example, a car must be made up of simple mechanical parts. Computers are also made up of components such as resistors and capacitors. Web pages are no exception, also through text, pictures, rectangles and so on.

2.1.1 Loading Images

Images are the soul element of a page and occupy most of the space on the page.

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; }}Copy the code

2.1.2 Drawing text

Text improves the readability of a page and makes the ideas on the page instantly accessible to anyone looking at it.

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; }}Copy the code

2.1.3 Drawing a Rectangle

Rectangular elements can be combined with elements such as text to achieve unexpected effects.

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(); }}Copy the code

2.1.4 draw round

Circles and rectangles play the same role and are more important on the page.

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(); }}Copy the code

2.2 the AST tree

The AST abstract syntax tree is an abstract representation of the syntax structure of the source code. It represents the syntactic structure of a programming language as a tree, with each node in the tree representing a structure in the source code. For example, in Vue, template syntax is converted into AST abstract syntax tree, and then into HTML structure. When drawing a page with Canvas, AST abstract syntax tree is also used to represent the content in the page. The types implemented are rect (rectangle), IMG (image), text (text), circle (circle).

The content to be drawn this time includes the static page part and the animation part, so two canvas will be used to achieve, and each canvas will correspond to an AST tree, namely the static part AST tree and the dynamic part AST tree.

2.2.1 Static Partial AST tree

The AST tree of the static part of the page is shown as follows, including rectangles, images, and text.

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=h Ttp%3A%2F%2Finews.gtimg.com & app = 2002 & size = f9999, 10000 & q = a80 & n = 0 & g = 0 n & FMT = jpeg? = 1622015341 & t = cc1bd95777dfa37d88c48bb6e the SEC 179778e' }, { 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: 'Cheer for the Grey Wolf, cheer for the Grey Wolf, 😄'}, {type: 'text', x: 1200, Y: 360, textAlign: 'start', textBaseline: 'ideographic', font: 'normal 30px serif', lineHeight: 50, width: 180, fillStyle: '#949494', content: 'read ', {type: 'text', x: 1260, y: 363, textAlign: 'start', textBaseline: 'ideographic', font: 'normal 30px serif', lineHeight: 50, width: 180, fillStyle: '#949494', content: '520' } ];Copy the code

2.2.2 Dynamic Part AST tree

The AST tree of the animated part of the page drawn this time is dynamically generated, consisting of a series of circles with dynamic colors.

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; }Copy the code

2.3 Main function classes

In addition to the basic element classes described above, it is exposed through a main function class.

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); }}); Const {type} = 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); }}Copy the code

2.4 Content Rendering

Now that the preparation is complete, let’s link each function to the AST tree to achieve the desired effect.

2.4.1 Static Content rendering

Start by drawing the content of the static section as the cornerstone of the page.

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

2.4.2 Drawing animation running lantern

Give this part of the content a little animation effect, more exciting.

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();
Copy the code

  1. This article corresponds to the source code, pay attention to the public number “Kite bearer”, reply to “canvas” to obtain

  2. If you think this article is good, share and like it so that more people can see it