import Lucky from './lucky' ; import { ConfigType , UniImageType } from '../types/index' ; import LuckyCardConfig , { MaskType , DefaultConfigType , StartCallbackType , EndCallbackType } from '../types/card' ; import { isExpectType , computePadding , hasBackground } from '../utils/index' ; import { drawRoundRect } from '../utils/math' ; export default class LuckyCard extends Lucky { private mask : MaskType = { } ; private defaultConfig : DefaultConfigType = { } ; private _defaultConfig = { percent : 0.5 , cleanZone : { x : 0 , y : 0 , width : 0 , height : 0 } } ; private startCallback ? : StartCallbackType ; private endCallback ? : EndCallbackType ; private canPlay : boolean = false ; private isMouseDown : boolean = false ; param config param data constructor ( config , data = { } ) { super ( config ) ; this . initData ( data ) ; this . init ( ) ; } initData ( data ) { this . $set ( this , 'mask' , data . mask || [ ] ) ; this . $set ( this , 'startCallback' , data . start ) ; this . $set ( this , 'endCallback' , data . end ) ; } init ( ) { super . init ( ) ; const { config , ctx } = this ; this . canPlay = false ; this . draw ( ) ; } draw ( ) { const { config , ctx , mask } = this ; ctx . globalCompositeOperation = 'source-over' ; const background = mask . background ; if ( hasBackground ( background ) ) { ctx . fillStyle = background ! ; ctx . beginPath ( ) ; ctx . rect ( 0 , 0 , this . boxWidth , this . boxHeight ) ; ctx . fill ( ) ; } ctx . globalCompositeOperation = 'destination-out' ; } param e protected handleMouseMove ( e ) { if ( ! this . canPlay || ! this . isMouseDown ) return ; const { config , ctx , _defaultConfig } = this ; ctx . beginPath ( ) ; const radius = 20 ; const [ x , y ] = this . conversionAxis ( e . offsetX , e . offsetY ) ; drawRoundRect ( ctx , x - radius , y - radius , radius * 2 , radius * 2 , 15 , '#ccc' ) ; ctx . fill ( ) ; const ImageData = ctx . getImageData ( 0 , 0 , this . boxWidth * config . dpr , this . boxHeight * config . dpr ) ?. data ; let count = 0 , len = ImageData . length / 4 ; for ( let i = 1 ; i <= len ; i ++ ) { if ( ImageData [ ( i - 1 ) * 4 ] < 128 ) count ++ ; } const percent = + ( count / len ) . toFixed ( 2 ) ; if ( percent > this . getLength ( _defaultConfig . percent ) ) { this . clean ( ) ; this . endCallback ?. ( ) ; } } /**
     * 开始游戏 (调用该方法才可以擦除)
     */ public play ( ) { this . canPlay = true ; this . startCallback ?. ( ) ; } /**
     * 擦除所有区域
     */ public clean ( ) { const { config , ctx } = this ; ctx . clearRect ( 0 , 0 , this . boxWidth , this . boxHeight ) ; } param e protected handleMouseDown ( e ) { this . isMouseDown = true ; } param e protected handleMouseUp ( e ) { this . isMouseDown = false ; } /**
     * 获取相对宽度
     */ private getWidth ( width , maxWidth = this . boxWidth ) { if ( isExpectType ( width , 'number' ) ) return ( width as number ) ; if ( isExpectType ( width , 'string' ) ) return this . changeUnits ( width as string , maxWidth ) ; return 0 ; } /**
     * 获取相对高度
     */ private getHeight ( height , maxHeight = this . boxHeight ) { if ( isExpectType ( height , 'number' ) ) return ( height as number ) ; if ( isExpectType ( height , 'string' ) ) return this . changeUnits ( height as string , maxHeight ) ; return 0 ; } param x param y protected conversionAxis ( x , y ) { const { config } = this ; return [ x / config . dpr , y / config . dpr ] ; } }