@@ -55,7 +55,8 @@ var mappers = {
5555// @todo if (fill[0] === '#')
5656function decodeFill ( el , index , count ) {
5757 var model = el . _model || { } ;
58- var fill = model . fill ;
58+ var fillOption = model . fill ;
59+ var fill = fillOption && typeof fillOption === 'object' ? fillOption . target : fillOption ;
5960 var target ;
6061
6162 if ( fill === undefined ) {
@@ -232,47 +233,120 @@ function isDrawable(point) {
232233 return point && ! point . skip ;
233234}
234235
235- function drawArea ( ctx , curve0 , curve1 , len0 , len1 ) {
236+ function fillPointsSets ( ctx , curve0 , curve1 , len0 , len1 , area , pointSets ) {
236237 var i , cx , cy , r ;
238+ var fillAreaPointsSet = [ ] ;
239+ var clipAboveAreaPointsSet = [ ] ;
240+ var clipBelowAreaPointsSet = [ ] ;
237241
238242 if ( ! len0 || ! len1 ) {
239243 return ;
240244 }
245+ clipAboveAreaPointsSet . push ( { x : curve1 [ len1 - 1 ] . x , y : area . top } ) ;
246+ clipBelowAreaPointsSet . push ( { x : curve0 [ 0 ] . x , y : area . top } ) ;
247+ clipBelowAreaPointsSet . push ( curve0 [ 0 ] ) ;
241248
242249 // building first area curve (normal)
243- ctx . moveTo ( curve0 [ 0 ] . x , curve0 [ 0 ] . y ) ;
250+ fillAreaPointsSet . push ( curve0 [ 0 ] ) ;
244251 for ( i = 1 ; i < len0 ; ++ i ) {
245- helpers . canvas . lineTo ( ctx , curve0 [ i - 1 ] , curve0 [ i ] ) ;
252+ curve0 [ i ] . flip = false ;
253+ fillAreaPointsSet . push ( curve0 [ i ] ) ;
254+ clipBelowAreaPointsSet . push ( curve0 [ i ] ) ;
246255 }
247256
248257 if ( curve1 [ 0 ] . angle !== undefined ) {
258+ pointSets . fill . push ( fillAreaPointsSet ) ;
259+ var radialSet = [ ] ;
249260 cx = curve1 [ 0 ] . cx ;
250261 cy = curve1 [ 0 ] . cy ;
251262 r = Math . sqrt ( Math . pow ( curve1 [ 0 ] . x - cx , 2 ) + Math . pow ( curve1 [ 0 ] . y - cy , 2 ) ) ;
252263 for ( i = len1 - 1 ; i > 0 ; -- i ) {
253- ctx . arc ( cx , cy , r , curve1 [ i ] . angle , curve1 [ i - 1 ] . angle , true ) ;
264+ radialSet . push ( { cx : cx , cy : cy , radius : r , startAngle : curve1 [ i ] . angle , endAngle : curve1 [ i - 1 ] . angle } ) ;
265+ }
266+ if ( radialSet . length ) {
267+ pointSets . fill . push ( radialSet ) ;
254268 }
255269 return ;
256270 }
257-
258271 // joining the two area curves
259- ctx . lineTo ( curve1 [ len1 - 1 ] . x , curve1 [ len1 - 1 ] . y ) ;
272+ var jointPoint = { } ;
273+ for ( var key in curve1 [ len1 - 1 ] ) {
274+ if ( curve1 [ len1 - 1 ] . hasOwnProperty ( key ) ) {
275+ jointPoint [ key ] = curve1 [ len1 - 1 ] [ key ] ;
276+ }
277+ }
278+ jointPoint . joint = true ;
279+ fillAreaPointsSet . push ( jointPoint ) ;
260280
261281 // building opposite area curve (reverse)
262282 for ( i = len1 - 1 ; i > 0 ; -- i ) {
263- helpers . canvas . lineTo ( ctx , curve1 [ i ] , curve1 [ i - 1 ] , true ) ;
283+ curve1 [ i ] . flip = true ;
284+ clipAboveAreaPointsSet . push ( curve1 [ i ] ) ;
285+ curve1 [ i - 1 ] . flip = true ;
286+ fillAreaPointsSet . push ( curve1 [ i - 1 ] ) ;
264287 }
288+ clipAboveAreaPointsSet . push ( curve1 [ 0 ] ) ;
289+ clipAboveAreaPointsSet . push ( { x : curve1 [ 0 ] . x , y : area . top } ) ;
290+ clipBelowAreaPointsSet . push ( { x : curve0 [ len0 - 1 ] . x , y : area . top } ) ;
291+
292+ pointSets . clipAbove . push ( clipAboveAreaPointsSet ) ;
293+ pointSets . clipBelow . push ( clipBelowAreaPointsSet ) ;
294+ pointSets . fill . push ( fillAreaPointsSet ) ;
265295}
266296
267- function doFill ( ctx , points , mapper , view , color , loop ) {
297+ function clipAndFill ( ctx , clippingPointsSets , fillingPointsSets , color ) {
298+ var i , ilen , j , jlen , set ;
299+ if ( clippingPointsSets ) {
300+ ctx . save ( ) ;
301+ ctx . beginPath ( ) ;
302+ for ( i = 0 , ilen = clippingPointsSets . length ; i < ilen ; i ++ ) {
303+ set = clippingPointsSets [ i ] ;
304+ // Have edge lines straight
305+ ctx . moveTo ( set [ 0 ] . x , set [ 0 ] . y ) ;
306+ ctx . lineTo ( set [ 1 ] . x , set [ 1 ] . y ) ;
307+ for ( j = 2 , jlen = set . length ; j < jlen - 1 ; j ++ ) {
308+ helpers . canvas . lineTo ( ctx , set [ j - 1 ] , set [ j ] , set [ j ] . flip ) ;
309+ }
310+ ctx . lineTo ( set [ j ] . x , set [ j ] . y ) ;
311+ }
312+ ctx . closePath ( ) ;
313+ ctx . clip ( ) ;
314+ ctx . beginPath ( ) ;
315+ }
316+ for ( i = 0 , ilen = fillingPointsSets . length ; i < ilen ; i ++ ) {
317+ set = fillingPointsSets [ i ] ;
318+ if ( set [ 0 ] . startAngle !== undefined ) {
319+ for ( j = 0 , jlen = set . length ; j < jlen ; j ++ ) {
320+ ctx . arc ( set [ j ] . cx , set [ j ] . cy , set [ j ] . radius , set [ j ] . startAngle , set [ j ] . endAngle , true ) ;
321+ }
322+ } else {
323+ ctx . moveTo ( set [ 0 ] . x , set [ 0 ] . y ) ;
324+ for ( j = 1 , jlen = set . length ; j < jlen ; j ++ ) {
325+ if ( set [ j ] . joint ) {
326+ ctx . lineTo ( set [ j ] . x , set [ j ] . y ) ;
327+ } else {
328+ helpers . canvas . lineTo ( ctx , set [ j - 1 ] , set [ j ] , set [ j ] . flip ) ;
329+ }
330+ }
331+ }
332+ }
333+ ctx . closePath ( ) ;
334+ ctx . fillStyle = color ;
335+ ctx . fill ( ) ;
336+ ctx . restore ( ) ;
337+ }
338+
339+ function doFill ( ctx , points , mapper , view , colors , loop , area ) {
268340 var count = points . length ;
269341 var span = view . spanGaps ;
270342 var curve0 = [ ] ;
271343 var curve1 = [ ] ;
272344 var len0 = 0 ;
273345 var len1 = 0 ;
346+ var pointSets = { clipBelow : [ ] , clipAbove : [ ] , fill : [ ] } ;
274347 var i , ilen , index , p0 , p1 , d0 , d1 ;
275348
349+ ctx . save ( ) ;
276350 ctx . beginPath ( ) ;
277351
278352 for ( i = 0 , ilen = ( count + ! ! loop ) ; i < ilen ; ++ i ) {
@@ -287,7 +361,7 @@ function doFill(ctx, points, mapper, view, color, loop) {
287361 len1 = curve1 . push ( p1 ) ;
288362 } else if ( len0 && len1 ) {
289363 if ( ! span ) {
290- drawArea ( ctx , curve0 , curve1 , len0 , len1 ) ;
364+ fillPointsSets ( ctx , curve0 , curve1 , len0 , len1 , area , pointSets ) ;
291365 len0 = len1 = 0 ;
292366 curve0 = [ ] ;
293367 curve1 = [ ] ;
@@ -302,11 +376,14 @@ function doFill(ctx, points, mapper, view, color, loop) {
302376 }
303377 }
304378
305- drawArea ( ctx , curve0 , curve1 , len0 , len1 ) ;
379+ fillPointsSets ( ctx , curve0 , curve1 , len0 , len1 , area , pointSets ) ;
306380
307- ctx . closePath ( ) ;
308- ctx . fillStyle = color ;
309- ctx . fill ( ) ;
381+ if ( colors . below !== colors . above ) {
382+ clipAndFill ( ctx , pointSets . clipAbove , pointSets . fill , colors . above ) ;
383+ clipAndFill ( ctx , pointSets . clipBelow , pointSets . fill , colors . below ) ;
384+ } else {
385+ clipAndFill ( ctx , false , pointSets . fill , colors . above ) ;
386+ }
310387}
311388
312389module . exports = {
@@ -351,7 +428,7 @@ module.exports = {
351428 beforeDatasetsDraw : function ( chart ) {
352429 var count = ( chart . data . datasets || [ ] ) . length - 1 ;
353430 var ctx = chart . ctx ;
354- var meta , i , el , view , points , mapper , color ;
431+ var meta , i , el , view , points , mapper , color , colors , fillOption ;
355432
356433 for ( i = count ; i >= 0 ; -- i ) {
357434 meta = chart . getDatasetMeta ( i ) . $filler ;
@@ -364,11 +441,17 @@ module.exports = {
364441 view = el . _view ;
365442 points = el . _children || [ ] ;
366443 mapper = meta . mapper ;
444+ fillOption = meta . el . _model . fill ;
367445 color = view . backgroundColor || defaults . global . defaultColor ;
368446
447+ colors = { above : color , below : color } ;
448+ if ( fillOption && typeof fillOption === 'object' ) {
449+ colors . above = fillOption . above || color ;
450+ colors . below = fillOption . below || color ;
451+ }
369452 if ( mapper && color && points . length ) {
370453 helpers . canvas . clipArea ( ctx , chart . chartArea ) ;
371- doFill ( ctx , points , mapper , view , color , el . _loop ) ;
454+ doFill ( ctx , points , mapper , view , colors , el . _loop , chart . chartArea ) ;
372455 helpers . canvas . unclipArea ( ctx ) ;
373456 }
374457 }
0 commit comments