@@ -47,7 +47,8 @@ var Color = this.Color = Base.extend(new function() {
4747 gray : [ 'gray' ] ,
4848 rgb : [ 'red' , 'green' , 'blue' ] ,
4949 hsb : [ 'hue' , 'saturation' , 'brightness' ] ,
50- hsl : [ 'hue' , 'saturation' , 'lightness' ]
50+ hsl : [ 'hue' , 'saturation' , 'lightness' ] ,
51+ gradient : [ 'gradient' , 'origin' , 'destination' , 'hilite' ]
5152 } ;
5253
5354 var colorCache = { } ,
@@ -192,7 +193,18 @@ var Color = this.Color = Base.extend(new function() {
192193 'gray-hsl' : function ( g ) {
193194 // TODO: Is lightness really the same as brightness for gray?
194195 return [ 0 , 0 , g ] ;
196+ } ,
197+
198+ 'gradient-rgb' : function ( gradient ) {
199+ // TODO: Implement
200+ return [ ] ;
201+ } ,
202+
203+ 'rgb-gradient' : function ( r , g , b ) {
204+ // TODO: Implement
205+ return [ ] ;
195206 }
207+
196208 } ;
197209
198210 // Produce getters and setter methods for the various color components known
@@ -201,12 +213,15 @@ var Color = this.Color = Base.extend(new function() {
201213 // its component.
202214 return Base . each ( types , function ( properties , type ) {
203215 Base . each ( properties , function ( name , index ) {
204- var isHue = name === 'hue' ,
216+ var part = Base . capitalize ( name ) ,
217+ isHue = name === 'hue' ,
218+ isGradient = name === 'gradient' ,
219+ isPoint = type === 'gradient' && ! isGradient ,
220+ isHilite = name === 'hilite' ,
205221 // Both hue and saturation have overlapping properties between
206222 // hsb and hsl. Handle this here separately, by testing for
207223 // overlaps and skipping conversion if the type is /hs[bl]/
208- hasOverlap = / ^ ( h u e | s a t u r a t i o n ) $ / . test ( name ) ,
209- part = Base . capitalize ( name ) ;
224+ hasOverlap = / ^ ( h u e | s a t u r a t i o n ) $ / . test ( name ) ;
210225
211226 this [ 'get' + part ] = function ( ) {
212227 return this . _type === type
@@ -222,11 +237,20 @@ var Color = this.Color = Base.extend(new function() {
222237 this . _components = this . _convert ( type ) ;
223238 this . _type = type ;
224239 }
225- this . _components [ index ] = isHue
240+ if ( ! isGradient )
241+ value = isHue
226242 // Keep negative values within modulo 360 too:
227243 ? ( ( value % 360 ) + 360 ) % 360
228- // All other values are 0..1
229- : Math . min ( Math . max ( value , 0 ) , 1 ) ;
244+ : isPoint
245+ ? Point . read ( arguments , 0 , 0 , true , isHilite ) // clone, readNull
246+ // All other values are 0..1
247+ : Math . min ( Math . max ( value , 0 ) , 1 ) ;
248+ if ( value != null ) {
249+ this . _components [ index ] = value ;
250+ if ( isGradient )
251+ value . _addOwner ( this ) ;
252+ this . _changed ( ) ;
253+ }
230254 } ;
231255 } , this ) ;
232256 } , /** @lends Color# */ {
@@ -242,6 +266,10 @@ var Color = this.Color = Base.extend(new function() {
242266 args = arguments ,
243267 read = 0 ,
244268 type ;
269+ if ( Array . isArray ( arg ) ) {
270+ args = arg ;
271+ arg = args [ 0 ] ;
272+ }
245273 // Try type arg first
246274 if ( typeof arg === 'string' && arg in types ) {
247275 type = arg ;
@@ -286,17 +314,19 @@ var Color = this.Color = Base.extend(new function() {
286314 components = arg . _components . slice ( ) ;
287315 alpha = arg . _alpha ;
288316 } else if ( arg . _class === 'Gradient' ) {
289- // TODO: Construct gradient
290317 type = 'gradient' ;
318+ components = slice . call ( args ) ;
291319 } else {
292320 // Determine type by presence of object property names
293321 type = 'hue' in arg
294322 ? 'lightness' in arg
295323 ? 'hsl'
296324 : 'hsb'
297- : 'gray' in arg
298- ? 'gray'
299- : 'rgb' ;
325+ : 'gradient' in arg
326+ ? 'gradient'
327+ : 'gray' in arg
328+ ? 'gray'
329+ : 'rgb' ;
300330 var properties = types [ type ] ;
301331 components = [ ] ;
302332 for ( var i = 0 , l = properties . length ; i < l ; i ++ )
@@ -307,19 +337,31 @@ var Color = this.Color = Base.extend(new function() {
307337 if ( this . _read && type )
308338 read = 1 ;
309339 }
340+ // Define this GradientColor's unique id.
341+ if ( type === 'gradient' )
342+ this . _id = ++ Base . _uid ;
310343 // Default fallbacks: rgb, black
311344 this . _type = type || 'rgb' ;
312345 this . _components = components || ( type === 'gray' ? [ 0 ] : [ 0 , 0 , 0 ] ) ;
313346 this . _alpha = alpha ;
347+ // Trigger setters for each component by looping through properties
348+ // and resseting component value.
349+ // TODO: This is a hack and should implemented better, e.g. with
350+ // value handlers.
351+ var properties = types [ this . _type ] ;
352+ for ( var i = 0 , l = properties . length ; i < l ; i ++ )
353+ this [ properties [ i ] ] = this . _components [ i ] ;
314354 if ( this . _read )
315355 this . _read = read ;
316356 } ,
317357
318- _serialize : function ( options ) {
319- // We can ommit the type for gray and rgb:
320- return / ^ ( g r a y | r g b ) $ / . test ( this . _type )
321- ? this . _components
322- : [ this . _type ] . concat ( this . _components ) ;
358+ _serialize : function ( options , dictionary ) {
359+ return Base . serialize (
360+ // We can ommit the type for gray and rgb:
361+ / ^ ( g r a y | r g b ) $ / . test ( this . _type )
362+ ? this . _components
363+ : [ this . _type ] . concat ( this . _components ) ,
364+ options , true , dictionary ) ;
323365 } ,
324366
325367 /**
@@ -477,8 +519,53 @@ var Color = this.Color = Base.extend(new function() {
477519 return css ;
478520 } ,
479521
480- toCanvasStyle : function ( ) {
481- return this . toCss ( ) ;
522+ toCanvasStyle : function ( ctx ) {
523+ if ( this . _type !== 'gradient' )
524+ return this . toCss ( ) ;
525+ // Gradient code form here onwards, incudling caching
526+ if ( this . _canvasGradient )
527+ return this . _canvasGradient ;
528+ var components = this . _components ,
529+ gradient = components [ 0 ] ,
530+ stops = gradient . _stops ,
531+ origin = components [ 1 ] ,
532+ destination = components [ 2 ] ,
533+ canvasGradient ;
534+ if ( gradient . _radial ) {
535+ var radius = destination . getDistance ( origin ) ,
536+ hilite = components [ 3 ] ;
537+ if ( hilite ) {
538+ var vector = hilite . subtract ( origin ) ;
539+ if ( vector . getLength ( ) > radius )
540+ hilite = origin . add ( vector . normalize ( radius - 0.1 ) ) ;
541+ }
542+ var start = hilite || origin ;
543+ canvasGradient = ctx . createRadialGradient ( start . x , start . y ,
544+ 0 , origin . x , origin . y , radius ) ;
545+ } else {
546+ canvasGradient = ctx . createLinearGradient ( origin . x , origin . y ,
547+ destination . x , destination . y ) ;
548+ }
549+ for ( var i = 0 , l = stops . length ; i < l ; i ++ ) {
550+ var stop = stops [ i ] ;
551+ canvasGradient . addColorStop ( stop . _rampPoint , stop . _color . toCss ( ) ) ;
552+ }
553+ return this . _canvasGradient = canvasGradient ;
554+ } ,
555+
556+ /**
557+ * Transform the gradient color by the specified matrix.
558+ *
559+ * @param {Matrix } matrix the matrix to transform the gradient color by
560+ */
561+ transform : function ( matrix ) {
562+ if ( this . _type === 'gradient' ) {
563+ var components = this . _components ;
564+ for ( var i = 1 , l = components . length ; i < l ; i ++ ) {
565+ var point = components [ i ] ;
566+ matrix . _transformPoint ( point , point , true ) ;
567+ }
568+ }
482569 } ,
483570
484571 /**
@@ -613,6 +700,16 @@ var Color = this.Color = Base.extend(new function() {
613700 color . _type = type ;
614701 color . _components = components ;
615702 color . _alpha = alpha ;
703+ if ( type === 'gradient' ) {
704+ // Make sure gradients always have an id
705+ color . _id = ++ Base . _uid ;
706+ // Clone all points:
707+ for ( var i = 1 , l = components . length ; i < l ; i ++ ) {
708+ var point = components [ i ] ;
709+ if ( point )
710+ components [ i ] = point . clone ( ) ;
711+ }
712+ }
616713 return color ;
617714 } ,
618715
@@ -626,16 +723,18 @@ var Color = this.Color = Base.extend(new function() {
626723
627724// Expose RgbColor, RGBColor, etc. constructors for backward compatibility.
628725Base . each ( Color . _types , function ( properties , type ) {
629- this [ Base . capitalize ( type ) + 'Color' ] = this [ type . toUpperCase ( ) + 'Color' ] =
726+ var ctor = this [ Base . capitalize ( type ) + 'Color' ] =
630727 function ( arg ) {
631728 var argType = arg != null && typeof arg ,
632- components = argType === 'number'
633- ? arguments
634- : argType === 'object' && arg . length != null
635- ? arg
636- : null ;
729+ components = argType === 'object' && arg . length != null
730+ ? arg
731+ : argType === 'string'
732+ ? null
733+ : arguments ;
637734 return components
638735 ? new Color ( type , components )
639736 : new Color ( arg ) ;
640737 } ;
738+ if ( ! / ^ ( g r a y | g r a d i e n t ) $ / . test ( type ) )
739+ this [ type . toUpperCase ( ) + 'Color' ] = ctor ;
641740} , this ) ;
0 commit comments