@@ -371,6 +371,60 @@ export class GradientParser {
371371 }
372372 return c ;
373373 }
374+ static processColorStops (
375+ colorStops : Array < { value : string ; length ?: { value : string } } >
376+ ) : { color : string ; offset : number } [ ] {
377+ if ( ! colorStops || colorStops . length === 0 ) {
378+ return [ ] ;
379+ }
380+
381+ const anyStopHasLength = colorStops . some ( ( item : any ) => item . length ) ;
382+
383+ if ( anyStopHasLength ) {
384+ const stops = colorStops . map ( ( item : any ) => ( {
385+ color : item . value ,
386+ offset : item . length ? parseFloat ( item . length . value ) / 100 : - 1
387+ } ) ) ;
388+
389+ // If first color stop has no position, it defaults to 0%
390+ if ( stops [ 0 ] . offset < 0 ) {
391+ stops [ 0 ] . offset = 0 ;
392+ }
393+
394+ // If last color stop has no position, it defaults to 100%
395+ if ( stops [ stops . length - 1 ] . offset < 0 ) {
396+ stops [ stops . length - 1 ] . offset = 1 ;
397+ }
398+
399+ // If a color stop in between has no position, its position is the average of the preceding and succeeding color stops with positions.
400+ for ( let i = 1 ; i < stops . length - 1 ; i ++ ) {
401+ if ( stops [ i ] . offset < 0 ) {
402+ const prevWithOffsetIdx = i - 1 ;
403+ let nextWithOffsetIdx = i + 1 ;
404+ while ( nextWithOffsetIdx < stops . length && stops [ nextWithOffsetIdx ] . offset < 0 ) {
405+ nextWithOffsetIdx ++ ;
406+ }
407+
408+ const startOffset = stops [ prevWithOffsetIdx ] . offset ;
409+ const endOffset = stops [ nextWithOffsetIdx ] . offset ;
410+ const unspecCount = nextWithOffsetIdx - prevWithOffsetIdx ;
411+
412+ for ( let j = 1 ; j < unspecCount ; j ++ ) {
413+ stops [ prevWithOffsetIdx + j ] . offset = startOffset + ( ( endOffset - startOffset ) * j ) / unspecCount ;
414+ }
415+ i = nextWithOffsetIdx - 1 ;
416+ }
417+ }
418+ return stops ;
419+ }
420+ return colorStops . map ( ( item : any , index : number ) => {
421+ const offset = colorStops . length > 1 ? index / ( colorStops . length - 1 ) : 0 ;
422+ return {
423+ color : item . value ,
424+ offset
425+ } ;
426+ } ) ;
427+ }
374428 private static ParseConic ( datum : any ) : IConicalGradient {
375429 const { orientation, colorStops = [ ] } = datum ;
376430 const halfPi = pi / 2 ;
@@ -381,12 +435,7 @@ export class GradientParser {
381435 y : 0.5 ,
382436 startAngle : sa ,
383437 endAngle : sa + pi2 ,
384- stops : colorStops . map ( ( item : any ) => {
385- return {
386- color : item . value ,
387- offset : parseFloat ( item . length . value ) / 100
388- } ;
389- } )
438+ stops : GradientParser . processColorStops ( colorStops )
390439 } ;
391440 }
392441 private static ParseRadial ( datum : any ) : IRadialGradient {
@@ -399,12 +448,7 @@ export class GradientParser {
399448 y1 : 0.5 ,
400449 r0 : 0 ,
401450 r1 : 1 ,
402- stops : colorStops . map ( ( item : any ) => {
403- return {
404- color : item . value ,
405- offset : parseFloat ( item . length . value ) / 100
406- } ;
407- } )
451+ stops : GradientParser . processColorStops ( colorStops )
408452 } ;
409453 }
410454 private static ParseLinear ( datum : any ) : ILinearGradient {
@@ -448,12 +492,7 @@ export class GradientParser {
448492 y0,
449493 x1,
450494 y1,
451- stops : colorStops . map ( ( item : any ) => {
452- return {
453- color : item . value ,
454- offset : parseFloat ( item . length . value ) / 100
455- } ;
456- } )
495+ stops : GradientParser . processColorStops ( colorStops )
457496 } ;
458497 }
459498}
0 commit comments