최근 프로젝트에서 탄막 기능을 맞춤화해야 했기 때문에 캔버스를 사용하여 컴포넌트를 개발해 보았습니다. 일부 저가형 컴퓨터에서 테스트한 결과 뚜렷한 지연이 없었습니다.
사격 효과 기능 소개사용
npm i vue-barrage
매개변수 구성
이름 | 유형 | 기본 | 설명 |
---|---|---|---|
장벽 목록 | 정렬 | [] | 사격 데이터 |
속도 | 숫자 | 4 | 사격 스크롤 속도 |
고리 | 부울 | 진실 | 루프에서 스크롤할지 여부 |
채널 | 숫자 | 2 | 사격 트랙 수 |
HTML 스타일
<template> <div class=barrage-container> <div class=container :style={height: barrageHeight/2+'px'}> <canvas id=canvas ref=canvas :width=barrageWidth :height=barrageHeight :style= {'너비': barrageWidth/2 + 'px','height': 장벽 높이/2 + 'px'}/> </div> </div></template>JS 구현
데이터 소스 듣기
watch: { barrageList (val) { if (val.length !== 0) { this.initData() // 데이터 초기화 this.render() // 렌더링 시작} }}
데이터 초기화
barrageArray
는 기본 사격 목록 및 새 사격 항목을 포함하여 사격 데이터를 저장하는 데 사용됩니다.
/** * 데이터 초기화*/initData () { for (let i = 0; i < this.barrageList.length; i++) { // 여기에는 40자만 표시됩니다. let content = this.barrageList[i]. 길이 > 40 ? `${this.barrageList[i].content.substring(0, 40)}...` : this.barrageList[i].content this.pushMessage(content, this.barrageList[i].color) }},/** * 데이터 추가* @param content * @param color */pushMessage (content, color) { let position = this.getPosition() / / 활주로 위치 결정 let x = this.barrageWidth // 초기 위치 let offsetWidth = 0 for (let i = 0, len = this.barrageArray.length; i < len; i++) { let item = this.barrageArray[i] if (position === item.position) { // 같은 트랙에 있으면 뒤로 이동 offsetWidth += Math.floor(this.ctx.measureText( item.content) .width * 3 + 60) } } this.barrageArray.push({ content: content, // 사격 콘텐츠 x: x + offsetWidth, // 각 주석의 초기 위치를 결정합니다.originX: x + offsetWidth, //루핑 중에 사용할 수 있도록 주석의 현재 위치를 저장합니다. position: position, width: this.ctx.measureText(content).width * 3, / / 캔버스 그리기 내용 너비 color: color || this.getColor() // 사용자 정의 색상})},
초기화 데이터에서 처리해야 할 것은 canvas
그릴 때 사용할 수 있도록 현재 포격의 궤적, 위치, 너비를 계산하는 것입니다.
canvas
그리기
/** * 렌더*/render () { this.ctx.clearRect(0, 0, this.barrageWidth, this.barrageHeight) this.ctx.font = '30px Microsoft YaHei' this.draw() window.requestAnimationFrame(this .render) // 16.6밀리초마다 렌더링합니다. setInterval을 사용하면 저사양 모델에서는 약간 지연됩니다.},/** * 텍스트 및 배경 그리기 시작*/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) { // 여기서 탄막이 사라지는 시간을 결정합니다. if (i === this.barrageArray.length - 1) { // 마지막 탄막이 사라질 때의 판단 논리 if (!this.loop) { // 루프가 아닌 경우 그리기를 취소하여 루프인지 확인하고 루프 없이 cancelAnimationFrame을 실행합니다. cancelAnimationFrame(this.render) return } if (this.addArray .length !== 0) { // 여기에 사격을 추가하는 논리를 결정합니다. this.barrageArray = this.barrageArray.concat(this.addArray) this.addArray = [] } for (let j = 0; j < this.barrageArray.length; j++) { // 각 사격에 x의 초기 값을 지정합니다. this.barrageArray[j].x = this.barrageArray[j].originX } } } if (barrage.x <= 2 * document.body.clientWidth + barrage.width) { // 그리기를 시작할 시기를 결정합니다. 그렇지 않으면 탄막 스크롤이 중단됩니다. // 배경 그리기 this.drawRoundRect(this.ctx, barrage.x - 15, barrage.position - 30, barrage.width + 30, 40, 20, `rgba(0,0,0,0.75)`) // text this .ctx.fillStyle = `${barrage.color}` this.ctx.fillText(barrage.content, barrage.x, barrage.position) } } catch (e) { console.log(e) } }},
취소 시점, 탄막 그리기 시작 시점 판단, 탄막이 사라지는 시점 판단 등 그리기 논리가 여기에서 판단됩니다.
기타 기능
/** * 텍스트 위치 가져오기 * pathWayIndex를 사용하여 각 포격이 있는 트랙을 확인합니다. * 상단으로부터의 거리를 반환합니다. * @TODO 또한 각 트랙의 거리를 기반으로 다음 포격의 위치를 결정하도록 최적화할 수 있습니다. */ getPosition () { let range = this.channels let top = (this.pathWayIndex % range) * 50 + 40 this.pathWayIndex++ return top},/** * 임의의 색상 가져오기*/getColor () { return '#' + ('00000' + (Math.random() * 0x1000000 << 0).toString(16)).slice(-6);},/** * 둥근 사각형 그리기* @ param 컨텍스트 * @param x * @param y * @param 너비 * @param 높이 * @param 반경 * @param 색상 */drawRoundRect (컨텍스트, x, y, 너비, 높이, 반경, 색상) { context.beginPath() context.fillStyle = 색상 context.arc(x + 반경, y + 반경, 반경, Math.PI, Math.PI * 3 / 2) context.lineTo (폭 - 반경 + x, y) context.arc(폭 - 반경 + x, 반경 + y, 반경, Math.PI * 3 / 2, Math.PI * 2) context.lineTo(폭 + x, 높이 + y - 반경) context.arc(너비 - 반경 + x, 높이 - 반경 + y, 반경, 0, Math.PI / 2) context.lineTo(반경 + x, 높이 + y) context.arc (반경 + x, 높이 - 반경 + y, 반경, Math.PI / 2, Math.PI) context.fill() context.closePath()}
사격 서비스 기능은 다음과 같습니다.
사용
<barrage ref=barrage class=barrage :barrage-list=barrageList :speed=speed :loop=loop :channels=channels/> import Barrage from 'vue-barrage'// Barrage 데이터 초기화 this.barrageList = [{ content: ' 테스트 데이터 테스트 번호 테스트 데이터 번호 테스트 데이터', color: 'white'}]// 새로운 사격 추가 this.$refs.barrage.add({ content: '새 사격 추가새 사격 추가', 색상: '흰색'})결론
전반적으로 이 구성 요소는 아직 최적화할 여지가 있으며 앞으로도 지속적으로 개선해 나가겠습니다.
위의 내용은 이 기사의 전체 내용입니다. 모든 분들의 학습에 도움이 되기를 바랍니다. 또한 모든 분들이 VeVb Wulin Network를 지지해 주시길 바랍니다.