Recently, because the project needed to customize a barrage function, I tried to use canvas to develop components. After testing on some low-end machines, there is no obvious lag. Let me share with you.
Barrage effect Function introductionuse
npm i vue-barrage
Parameter configuration
name | type | default | desc |
---|---|---|---|
barrierList | Array | [] | Barrage data |
speed | Number | 4 | Barrage scrolling speed |
loop | Boolean | true | Whether to scroll in a loop |
channels | Number | 2 | Number of barrage tracks |
html style
<template> <div class=barrage-container> <div class=container :style={height: barrageHeight/2+'px'}> <canvas id=canvas ref=canvas :width=barrageWidth :height=barrageHeight :style= {'width': barrageWidth/2 + 'px','height': barrierHeight/2 + 'px'}/> </div> </div></template>js implementation
Listen to data sources
watch: { barrageList (val) { if (val.length !== 0) { this.initData() // Data initialization this.render() // Start rendering} }}
Data initialization
barrageArray
is used to store barrage data, including the default barrage list and new barrage items.
/** * Data initialization*/initData () { for (let i = 0; i < this.barrageList.length; i++) { // Only 40 characters are displayed here let content = this.barrageList[i]. content.length > 40 ? `${this.barrageList[i].content.substring(0, 40)}...` : this.barrageList[i].content this.pushMessage(content, this.barrageList[i].color) }},/** * Add data* @param content * @param color */pushMessage (content, color) { let position = this.getPosition() / / Determine the runway position let x = this.barrageWidth // Initial position let offsetWidth = 0 for (let i = 0, len = this.barrageArray.length; i < len; i++) { let item = this.barrageArray[i] if (position === item.position) { // If they are on the same track, move to the back offsetWidth += Math.floor(this.ctx.measureText(item.content) .width * 3 + 60) } } this.barrageArray.push({ content: content, // Barrage content x: x + offsetWidth, // Determine the initial position of each comment originX: x + offsetWidth, // Store the current position of the comment so that it can be used during looping position: position, width: this.ctx.measureText(content).width * 3, // Canvas drawing content width color: color || this.getColor() // Custom color})},
What needs to be processed in the initialization data is to calculate the track, position, and width of the current barrage so that it can be used when drawing canvas
.
Draw canvas
/** * Render*/render () { this.ctx.clearRect(0, 0, this.barrageWidth, this.barrageHeight) this.ctx.font = '30px Microsoft YaHei' this.draw() window.requestAnimationFrame(this .render) // Render every 16.6 milliseconds. If you use setInterval, it will be a bit laggy on low-end models},/** * Start drawing text and background*/draw () { for (let i = 0, len = this.barrageArray.length; i < len; i++) { let barrage = this.barrageArray[i] try { barrage.x -= this .speed if (barrage.x < -barrage.width - 100) { // Determine the time when the barrage disappears here if (i === this.barrageArray.length - 1) { // Judgment logic when the last barrage disappears if (!this.loop) { // If it is not a loop, cancel the drawing to determine whether it is a loop, and execute cancelAnimationFrame without loop cancelAnimationFrame(this.render) return } if (this.addArray .length !== 0) { // Determine the logic of adding barrage here this.barrageArray = this.barrageArray.concat(this.addArray) this.addArray = [] } for (let j = 0; j < this.barrageArray.length; j++) { // Give each barrage an initial value of x this.barrageArray[j].x = this.barrageArray[j].originX } } } if (barrage. x <= 2 * document.body.clientWidth + barrage.width) { // Determine when to start drawing. If not, it will cause the barrage scrolling to be stuck // Draw the background this.drawRoundRect(this.ctx, barrage.x - 15, barrage.position - 30, barrage.width + 30, 40, 20, `rgba(0,0,0,0.75)`) // Draw the text this .ctx.fillStyle = `${barrage.color}` this.ctx.fillText(barrage.content, barrage.x, barrage.position) } } catch (e) { console.log(e) } }},
The drawing logic is judged here, including when to cancel, judging when the barrage starts drawing, and judging when the barrage disappears.
Other functions
/** * Get the text position * Use pathWayIndex to confirm the track where each barrage is located * Return the distance from the top * @TODO This can also be optimized to determine the location of the next barrage based on the distance of each track */ getPosition () { let range = this.channels let top = (this.pathWayIndex % range) * 50 + 40 this.pathWayIndex++ return top},/** * Get a random color*/getColor () { return '#' + ('00000' + (Math.random() * 0x1000000 << 0).toString(16)).slice(-6);},/** * Draw a rounded rectangle* @ param context * @param x * @param y * @param width * @param height * @param radius * @param color */drawRoundRect (context, x, y, width, height, radius, color) { context.beginPath() context.fillStyle = color context.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 3 / 2) context.lineTo (width - radius + x, y) context.arc(width - radius + x, radius + y, radius, Math.PI * 3 / 2, Math.PI * 2) context.lineTo(width + x, height + y - radius) context.arc(width - radius + x, height - radius + y, radius, 0, Math.PI / 2) context.lineTo(radius + x, height + y) context.arc (radius + x, height - radius + y, radius, Math.PI / 2, Math.PI) context.fill() context.closePath()}
Here is the barrage service function
use
<barrage ref=barrage class=barrage :barrage-list=barrageList :speed=speed :loop=loop :channels=channels/> import Barrage from 'vue-barrage'// Barrage data initialization this.barrageList = [{ content: 'Test data test number test data number test data', color: 'white'}]// Add new barrage this.$refs.barrage.add({ content: 'Add a new barrageAdd a new barrage', color: 'white'})Conclusion
Overall, this component still has room for optimization, and I will continue to improve it in the future.
The above is the entire content of this article. I hope it will be helpful to everyone’s study. I also hope everyone will support VeVb Wulin Network.