import Base from '@src/common/base' ; import { IElement , Options } from '@src/types/line' ; import { degreesToRadians , offset , randomInRange , randomSpeed , toFixed , } from '@src/utils' ; export default class Line extends Base < Options > { static defaultConfig : Options = { num : 6 , maxWidth : 2 , minWidth : 1 , maxSpeed : 3 , minSpeed : 1 , maxDegree : 90 , minDegree : 80 , createOnClick : true , numberOfCreations : 3 , removeOnOverflow : true , overflowCompensation : 20 , reservedLines : 6 , } ; protected elements ! : IElement [ ] ; private specificAngles = [ - 180 , - 90 , 0 , 90 , 180 ] ; constructor ( selector , options ? ) { super ( Line . defaultConfig , selector , options ) ; this . bootstrap ( ) ; } /**
     * 初始化数据和运行程序
     */ protected init ( ) { this . createLines ( this . options . num ) ; this . createLinesOnClick ( ) ; } param number param positionX private createLines ( number , positionX ? ) { const { maxWidth , minWidth , maxSpeed , minSpeed , maxDegree , minDegree } = this . options ; while ( number -- ) { this . elements . push ( { x : positionX ?? Math . random ( ) * this . canvasWidth , width : randomInRange ( maxWidth , minWidth ) , color : this . getColor ( ) , speed : randomSpeed ( maxSpeed , minSpeed ) , degree : toFixed ( randomInRange ( maxDegree , minDegree ) % 180 ) , } ) ; } } /**
     * 点击的时候创建线条
     */ private createLinesOnClick ( ) { if ( ! this . options . createOnClick ) return ; const handleClick = ( event ) => { if ( this . isPaused ) return ; const x = event . pageX - offset ( this . canvas ) . left ; this . createLines ( this . options . numberOfCreations , x ) ; } ; this . canvas . addEventListener ( 'click' , handleClick ) ; this . onDestroy ( ( ) => { this . canvas . removeEventListener ( 'click' , handleClick ) ; } ) ; } protected draw ( ) { const { ctx , canvasWidth , canvasHeight } = this ; const { removeOnOverflow , overflowCompensation , reservedLines } = this . options ; this . clearCanvasAndSetGlobalAttrs ( ) ; const hypotenuse = Math . hypot ( canvasWidth , canvasHeight ) ; const lineLength = hypotenuse * 10 ; const OC = Math . max ( 0 , overflowCompensation ) ; this . elements . forEach ( ( line , i ) => { const radian = degreesToRadians ( - line . degree ) ; let adjacentSide = 0 ; if ( ! this . specificAngles . includes ( line . degree ) ) { adjacentSide = Math . abs ( this . canvasHeight / 2 / Math . tan ( radian ) ) ; } ctx . save ( ) ; ctx . beginPath ( ) ; ctx . translate ( line . x , this . canvasHeight / 2 ) ; ctx . rotate ( radian ) ; ctx . moveTo ( - lineLength , 0 ) ; ctx . lineTo ( lineLength , 0 ) ; ctx . lineWidth = line . width ; ctx . strokeStyle = line . color ; ctx . stroke ( ) ; ctx . closePath ( ) ; ctx . restore ( ) ; if ( ! this . isPaused ) { line . x += line . speed ; } let isOverflow = false ; let isOverflowOnLeft = false ; if ( line . x + adjacentSide + line . width + OC < 0 ) { isOverflow = true ; isOverflowOnLeft = true ; } else if ( line . x > this . canvasWidth + adjacentSide + line . width + OC ) { isOverflow = true ; } if ( isOverflow ) { if ( removeOnOverflow && this . elements . length > reservedLines ) { this . elements . splice ( i , 1 ) ; } else { line . speed = Math . abs ( line . speed ) * ( isOverflowOnLeft ? 1 : - 1 ) ; } } } ) ; this . requestAnimationFrame ( ) ; } }