preserve import { Point } from './point' ; import { PointContainer } from './pointContainer' ; import { AbstractDistanceCalculator } from '../distance/distanceCalculator' ; import { rgb2hsl } from '../conversion/rgb2hsl' ; const hueGroups = 10 ; export function hueGroup ( hue , segmentsNumber ) { const maxHue = 360 ; const seg = maxHue / segmentsNumber ; const half = seg / 2 ; for ( let i = 1 , mid = seg - half ; i < segmentsNumber ; i ++ , mid += seg ) { if ( hue >= mid && hue < mid + seg ) return i ; } return 0 ; } export class Palette { private readonly _pointContainer : PointContainer ; private readonly _pointArray : Point [ ] = [ ] ; private _i32idx : { [ key ] : number ; } = { } ; constructor ( ) { this . _pointContainer = new PointContainer ( ) ; this . _pointContainer . setHeight ( 1 ) ; this . _pointArray = this . _pointContainer . getPointArray ( ) ; } add ( color ) { this . _pointArray . push ( color ) ; this . _pointContainer . setWidth ( this . _pointArray . length ) ; } has ( color ) { for ( let i = this . _pointArray . length - 1 ; i >= 0 ; i -- ) { if ( color . uint32 === this . _pointArray [ i ] . uint32 ) return true ; } return false ; } getNearestColor ( colorDistanceCalculator , color ) { return this . _pointArray [ this . _getNearestIndex ( colorDistanceCalculator , color ) | 0 ] ; } getPointContainer ( ) { return this . _pointContainer ; } private _nearestPointFromCache ( key ) { return typeof this . _i32idx [ key ] === 'number' ? this . _i32idx [ key ] : - 1 ; } private _getNearestIndex ( colorDistanceCalculator , point ) { let idx = this . _nearestPointFromCache ( '' + point . uint32 ) ; if ( idx >= 0 ) return idx ; let minimalDistance = Number . MAX_VALUE ; idx = 0 ; for ( let i = 0 , l = this . _pointArray . length ; i < l ; i ++ ) { const p = this . _pointArray [ i ] ; const distance = colorDistanceCalculator . calculateRaw ( point . r , point . g , point . b , point . a , p . r , p . g , p . b , p . a ) ; if ( distance < minimalDistance ) { minimalDistance = distance ; idx = i ; } } this . _i32idx [ point . uint32 ] = idx ; return idx ; } sort ( ) { this . _i32idx = { } ; this . _pointArray . sort ( ( a , b ) => { const hslA = rgb2hsl ( a . r , a . g , a . b ) ; const hslB = rgb2hsl ( b . r , b . g , b . b ) ; const hueA = a . r === a . g && a . g === a . b ? 0 : 1 + hueGroup ( hslA . h , hueGroups ) ; const hueB = b . r === b . g && b . g === b . b ? 0 : 1 + hueGroup ( hslB . h , hueGroups ) ; const hueDiff = hueB - hueA ; if ( hueDiff ) return - hueDiff ; const lA = a . getLuminosity ( true ) ; const lB = b . getLuminosity ( true ) ; if ( lB - lA !== 0 ) return lB - lA ; const satDiff = ( ( hslB . s * 100 ) | 0 ) - ( ( hslA . s * 100 ) | 0 ) ; if ( satDiff ) return - satDiff ; return 0 ; } ) ; } }