import twoPointsAngle from './twoPointsAngle' ; import twoPointsDistance from './twoPointsDistance' ; import { SKGradient , SKLayer , LinearGradient , GListItem } from '../../../../types' ; import { precisionControl , transSketchColor } from '../../../../common/utils' ; export default ( gradient , layer , contextSettings = 1 ) : LinearGradient => { let frame = layer . frame ; let changePointList = [ ] ; let startPointStr = gradient . from ; let startX = + startPointStr . split ( '{' ) [ 1 ] . split ( ',' ) [ 0 ] * frame . width ; let startY = - startPointStr . split ( ',' ) [ 1 ] . split ( '}' ) [ 0 ] * frame . height ; let endPointStr = gradient . to ; let endX = + endPointStr . split ( '{' ) [ 1 ] . split ( ',' ) [ 0 ] * frame . width ; let endY = - endPointStr . split ( ',' ) [ 1 ] . split ( '}' ) [ 0 ] * frame . height ; let gAngle = twoPointsAngle ( startX , startY , endX , endY ) ; let gDistance = twoPointsDistance ( startX , startY , endX , endY ) ; let startPoint = { x : startX , y : startY } ; let endPoint = { x : endX , y : endY } ; let stops = gradient . stops ; if ( endX < startX ) { startPoint = { x : endX , y : endY } ; endPoint = { x : startX , y : startY } ; gAngle = twoPointsAngle ( endX , endY , startX , startY ) ; gDistance = twoPointsDistance ( endX , endY , startX , startY ) ; stops = stops . reverse ( ) ; stops = stops . map ( item => { item . position = 1 - item . position ; return item ; } ) ; } type Point = { x : number ; y : number ; } ; let point1 = { x : 0 , y : 0 } ; let point2 = { x : frame . width , y : 0 } ; let point3 = { x : frame . width , y : - frame . height } ; let point4 = { x : 0 , y : - frame . height } ; let mainStart = point1 ; let mainEnd = point3 ; if ( gAngle >= 0 && gAngle < Math . PI / 2 ) { mainStart = point4 ; mainEnd = point2 ; } else if ( gAngle >= Math . PI / 2 && gAngle < Math . PI ) { mainStart = point1 ; mainEnd = point3 ; } let lengthStart = 0 ; let lengthEnd = 0 ; let startColor = { } ; let endColor = { } ; const verticalDistance = ( point1 , point2 , lineAngle ) : number => { return Math . abs ( twoPointsDistance ( point1 . x , point1 . y , point2 . x , point2 . y ) ) * Math . cos ( twoPointsAngle ( point1 . x , point1 . y , point2 . x , point2 . y ) - lineAngle ) ; } ; if ( ! ( startPoint . x == mainStart . x && startPoint . y == mainStart . y ) ) { lengthStart = verticalDistance ( mainStart , startPoint , gAngle ) ; } if ( ! ( endPoint . x == mainEnd . x && endPoint . y == mainEnd . y ) ) { lengthEnd = verticalDistance ( endPoint , mainEnd , gAngle ) ; } if ( lengthStart < 0 ) { for ( let i = 1 ; i < stops . length ; i ++ ) { if ( stops [ i ] . position > - lengthStart / gDistance ) { let currColor = stops [ i ] . color ; let preColor = stops [ i - 1 ] . color ; const getVal = ( prop ) => { return preColor [ prop ] + ( currColor [ prop ] - preColor [ prop ] ) / ( stops [ i ] . position - stops [ i - 1 ] . position ) * ( - lengthStart / gDistance - stops [ i - 1 ] . position ) ; } ; startColor = { index : i , color : { 'alpha' : getVal ( 'alpha' ) , 'blue' : getVal ( 'blue' ) , 'green' : getVal ( 'green' ) , 'red' : getVal ( 'red' ) } , position : - lengthStart / gDistance } ; break ; } } } else { startColor = { index : 0 , color : stops [ 0 ] . color , position : - lengthStart / gDistance } ; } if ( lengthEnd < 0 ) { for ( let i = 0 ; i < stops . length - 1 ; i ++ ) { if ( stops [ i + 1 ] . position > 1 + lengthEnd / gDistance ) { let currColor = stops [ i ] . color ; let nextColor = stops [ i + 1 ] . color ; const getVal = ( prop ) => { return currColor [ prop ] + ( nextColor [ prop ] - currColor [ prop ] ) / ( stops [ i + 1 ] . position - stops [ i ] . position ) * ( 1 + lengthEnd / gDistance - stops [ i ] . position ) ; } ; endColor = { index : i , color : { 'alpha' : getVal ( 'alpha' ) , 'blue' : getVal ( 'blue' ) , 'green' : getVal ( 'green' ) , 'red' : getVal ( 'red' ) } , position : 1 + lengthEnd / gDistance } ; break ; } } } else { endColor = { index : stops . length - 1 , color : stops [ stops . length - 1 ] . color , position : 1 + lengthEnd / gDistance } ; } if ( startColor . color ) { changePointList . push ( startColor ) ; } for ( let n = 0 ; n < stops . length ; n ++ ) { if ( n >= startColor . index && n <= endColor . index ) { changePointList . push ( stops [ n ] ) ; } } if ( endColor . color ) { changePointList . push ( endColor ) ; } changePointList = changePointList . map ( ( { color , position } ) => { position = ( position - changePointList [ 0 ] . position ) / ( changePointList [ changePointList . length - 1 ] . position - changePointList [ 0 ] . position ) ; return { color , position } ; } ) ; const valList = changePointList . map ( ( { color , position } ) : GListItem => { let { red , green , blue , alpha } = color ; if ( layer . style && layer . style . contextSettings ) { alpha = layer . style . contextSettings . opacity * contextSettings * alpha ; } return { color : transSketchColor ( { red , green , blue , alpha } ) , position : precisionControl ( position , 0.01 ) , } ; } ) ; return { gAngle : Math . round ( gAngle / Math . PI * 180 * 10 ) / 10 , gList : valList , } ; } ;