@@ -56,7 +56,8 @@ var mappers = {
56
56
// @todo if (fill[0] === '#')
57
57
function decodeFill ( el , index , count ) {
58
58
var model = el . _model || { } ;
59
- var fill = model . fill ;
59
+ var fillOption = model . fill ;
60
+ var fill = fillOption && typeof fillOption . target !== 'undefined' ? fillOption . target : fillOption ;
60
61
var target ;
61
62
62
63
if ( fill === undefined ) {
@@ -235,50 +236,121 @@ function isDrawable(point) {
235
236
return point && ! point . skip ;
236
237
}
237
238
238
- function drawArea ( ctx , curve0 , curve1 , len0 , len1 , stepped , tension ) {
239
- const lineTo = stepped ? helpers . canvas . _steppedLineTo : helpers . canvas . _bezierCurveTo ;
240
- let i , cx , cy , r , target ;
239
+ function fillPointsSets ( ctx , curve0 , curve1 , len0 , len1 , area , pointSets ) {
240
+ const fillAreaPointsSet = [ ] ;
241
+ const clipAboveAreaPointsSet = [ ] ;
242
+ const clipBelowAreaPointsSet = [ ] ;
243
+ const radialSet = [ ] ;
244
+ const jointPoint = { } ;
245
+ let i , cx , cy , r ;
241
246
242
247
if ( ! len0 || ! len1 ) {
243
248
return ;
244
249
}
250
+ clipAboveAreaPointsSet . push ( { x : curve1 [ len1 - 1 ] . x , y : area . top } ) ;
251
+ clipBelowAreaPointsSet . push ( { x : curve0 [ 0 ] . x , y : area . top } ) ;
252
+ clipBelowAreaPointsSet . push ( curve0 [ 0 ] ) ;
245
253
246
254
// building first area curve (normal)
247
- ctx . moveTo ( curve0 [ 0 ] . x , curve0 [ 0 ] . y ) ;
255
+ fillAreaPointsSet . push ( curve0 [ 0 ] ) ;
248
256
for ( i = 1 ; i < len0 ; ++ i ) {
249
- target = curve0 [ i ] ;
250
- if ( ! target . boundary && ( tension || stepped ) ) {
251
- lineTo ( ctx , curve0 [ i - 1 ] , target , false , stepped ) ;
252
- } else {
253
- ctx . lineTo ( target . x , target . y ) ;
254
- }
257
+ curve0 [ i ] . flip = false ;
258
+ fillAreaPointsSet . push ( curve0 [ i ] ) ;
259
+ clipBelowAreaPointsSet . push ( curve0 [ i ] ) ;
255
260
}
256
261
257
262
if ( curve1 [ 0 ] . angle !== undefined ) {
263
+ pointSets . fill . push ( fillAreaPointsSet ) ;
258
264
cx = curve1 [ 0 ] . cx ;
259
265
cy = curve1 [ 0 ] . cy ;
260
266
r = Math . sqrt ( Math . pow ( curve1 [ 0 ] . x - cx , 2 ) + Math . pow ( curve1 [ 0 ] . y - cy , 2 ) ) ;
261
267
for ( i = len1 - 1 ; i > 0 ; -- i ) {
262
- ctx . arc ( cx , cy , r , curve1 [ i ] . angle , curve1 [ i - 1 ] . angle , true ) ;
268
+ radialSet . push ( { cx : cx , cy : cy , radius : r , startAngle : curve1 [ i ] . angle , endAngle : curve1 [ i - 1 ] . angle } ) ;
269
+ }
270
+ if ( radialSet . length ) {
271
+ pointSets . fill . push ( radialSet ) ;
263
272
}
264
273
return ;
265
274
}
266
-
267
275
// joining the two area curves
268
- ctx . lineTo ( curve1 [ len1 - 1 ] . x , curve1 [ len1 - 1 ] . y ) ;
276
+ for ( var key in curve1 [ len1 - 1 ] ) {
277
+ if ( Object . prototype . hasOwnProperty . call ( curve1 [ len1 - 1 ] , key ) ) {
278
+ jointPoint [ key ] = curve1 [ len1 - 1 ] [ key ] ;
279
+ }
280
+ }
281
+ jointPoint . joint = true ;
282
+ fillAreaPointsSet . push ( jointPoint ) ;
269
283
270
284
// building opposite area curve (reverse)
271
285
for ( i = len1 - 1 ; i > 0 ; -- i ) {
272
- target = curve1 [ i - 1 ] ;
273
- if ( ! target . boundary && ( tension || stepped ) ) {
274
- lineTo ( ctx , curve1 [ i ] , target , true , stepped ) ;
286
+ curve1 [ i ] . flip = true ;
287
+ clipAboveAreaPointsSet . push ( curve1 [ i ] ) ;
288
+ curve1 [ i - 1 ] . flip = true ;
289
+ fillAreaPointsSet . push ( curve1 [ i - 1 ] ) ;
290
+ }
291
+ clipAboveAreaPointsSet . push ( curve1 [ 0 ] ) ;
292
+ clipAboveAreaPointsSet . push ( { x : curve1 [ 0 ] . x , y : area . top } ) ;
293
+ clipBelowAreaPointsSet . push ( { x : curve0 [ len0 - 1 ] . x , y : area . top } ) ;
294
+
295
+ pointSets . clipAbove . push ( clipAboveAreaPointsSet ) ;
296
+ pointSets . clipBelow . push ( clipBelowAreaPointsSet ) ;
297
+ pointSets . fill . push ( fillAreaPointsSet ) ;
298
+ }
299
+
300
+ function clipAndFill ( ctx , clippingPointsSets , fillingPointsSets , color , stepped , tension ) {
301
+ const lineTo = stepped ? helpers . canvas . _steppedLineTo : helpers . canvas . _bezierCurveTo ;
302
+ let i , ilen , j , jlen , set , target ;
303
+ if ( clippingPointsSets ) {
304
+ ctx . save ( ) ;
305
+ ctx . beginPath ( ) ;
306
+ for ( i = 0 , ilen = clippingPointsSets . length ; i < ilen ; i ++ ) {
307
+ set = clippingPointsSets [ i ] ;
308
+ // Have edge lines straight
309
+ ctx . moveTo ( set [ 0 ] . x , set [ 0 ] . y ) ;
310
+ ctx . lineTo ( set [ 1 ] . x , set [ 1 ] . y ) ;
311
+ for ( j = 2 , jlen = set . length ; j < jlen - 1 ; j ++ ) {
312
+ target = set [ j ] ;
313
+ if ( ! target . boundary && ( tension || stepped ) ) {
314
+ lineTo ( ctx , set [ j - 1 ] , target , target . flip , stepped ) ;
315
+ } else {
316
+ ctx . lineTo ( target . x , target . y ) ;
317
+ }
318
+ }
319
+ ctx . lineTo ( set [ j ] . x , set [ j ] . y ) ;
320
+ }
321
+ ctx . closePath ( ) ;
322
+ ctx . clip ( ) ;
323
+ ctx . beginPath ( ) ;
324
+ }
325
+ for ( i = 0 , ilen = fillingPointsSets . length ; i < ilen ; i ++ ) {
326
+ set = fillingPointsSets [ i ] ;
327
+ if ( set [ 0 ] . startAngle !== undefined ) {
328
+ for ( j = 0 , jlen = set . length ; j < jlen ; j ++ ) {
329
+ ctx . arc ( set [ j ] . cx , set [ j ] . cy , set [ j ] . radius , set [ j ] . startAngle , set [ j ] . endAngle , true ) ;
330
+ }
275
331
} else {
276
- ctx . lineTo ( target . x , target . y ) ;
332
+ ctx . moveTo ( set [ 0 ] . x , set [ 0 ] . y ) ;
333
+ for ( j = 1 , jlen = set . length ; j < jlen ; j ++ ) {
334
+ if ( set [ j ] . joint ) {
335
+ ctx . lineTo ( set [ j ] . x , set [ j ] . y ) ;
336
+ } else {
337
+ target = set [ j ] ;
338
+ if ( ! target . boundary && ( tension || stepped ) ) {
339
+ lineTo ( ctx , set [ j - 1 ] , target , target . flip , stepped ) ;
340
+ } else {
341
+ ctx . lineTo ( target . x , target . y ) ;
342
+ }
343
+ }
344
+ }
277
345
}
278
346
}
347
+ ctx . closePath ( ) ;
348
+ ctx . fillStyle = color ;
349
+ ctx . fill ( ) ;
350
+ ctx . restore ( ) ;
279
351
}
280
352
281
- function doFill ( ctx , points , mapper , el ) {
353
+ function doFill ( ctx , points , mapper , colors , el , area ) {
282
354
const count = points . length ;
283
355
const view = el . _view ;
284
356
const loop = el . _loop ;
@@ -289,8 +361,10 @@ function doFill(ctx, points, mapper, el) {
289
361
let curve1 = [ ] ;
290
362
let len0 = 0 ;
291
363
let len1 = 0 ;
364
+ let pointSets = { clipBelow : [ ] , clipAbove : [ ] , fill : [ ] } ;
292
365
let i , ilen , index , p0 , p1 , d0 , d1 , loopOffset ;
293
366
367
+ ctx . save ( ) ;
294
368
ctx . beginPath ( ) ;
295
369
296
370
for ( i = 0 , ilen = count ; i < ilen ; ++ i ) {
@@ -310,7 +384,7 @@ function doFill(ctx, points, mapper, el) {
310
384
len1 = curve1 . push ( p1 ) ;
311
385
} else if ( len0 && len1 ) {
312
386
if ( ! span ) {
313
- drawArea ( ctx , curve0 , curve1 , len0 , len1 , stepped , tension ) ;
387
+ fillPointsSets ( ctx , curve0 , curve1 , len0 , len1 , area , pointSets ) ;
314
388
len0 = len1 = 0 ;
315
389
curve0 = [ ] ;
316
390
curve1 = [ ] ;
@@ -325,11 +399,14 @@ function doFill(ctx, points, mapper, el) {
325
399
}
326
400
}
327
401
328
- drawArea ( ctx , curve0 , curve1 , len0 , len1 , stepped , tension ) ;
402
+ fillPointsSets ( ctx , curve0 , curve1 , len0 , len1 , area , pointSets ) ;
329
403
330
- ctx . closePath ( ) ;
331
- ctx . fillStyle = view . backgroundColor ;
332
- ctx . fill ( ) ;
404
+ if ( colors . below !== colors . above ) {
405
+ clipAndFill ( ctx , pointSets . clipAbove , pointSets . fill , colors . above , stepped , tension ) ;
406
+ clipAndFill ( ctx , pointSets . clipBelow , pointSets . fill , colors . below , stepped , tension ) ;
407
+ } else {
408
+ clipAndFill ( ctx , false , pointSets . fill , colors . above , stepped , tension ) ;
409
+ }
333
410
}
334
411
335
412
module . exports = {
@@ -375,7 +452,7 @@ module.exports = {
375
452
beforeDatasetsDraw : function ( chart ) {
376
453
var metasets = chart . _getSortedVisibleDatasetMetas ( ) ;
377
454
var ctx = chart . ctx ;
378
- var meta , i , el , points , mapper ;
455
+ var meta , i , el , view , points , mapper , color , colors , fillOption ;
379
456
380
457
for ( i = metasets . length - 1 ; i >= 0 ; -- i ) {
381
458
meta = metasets [ i ] . $filler ;
@@ -385,12 +462,20 @@ module.exports = {
385
462
}
386
463
387
464
el = meta . el ;
465
+ view = el . _view ;
388
466
points = el . _children || [ ] ;
389
467
mapper = meta . mapper ;
468
+ fillOption = meta . el . _model . fill ;
469
+ color = view . backgroundColor || defaults . global . defaultColor ;
390
470
471
+ colors = { above : color , below : color } ;
472
+ if ( fillOption && typeof fillOption === 'object' ) {
473
+ colors . above = fillOption . above || color ;
474
+ colors . below = fillOption . below || color ;
475
+ }
391
476
if ( mapper && points . length ) {
392
477
helpers . canvas . clipArea ( ctx , chart . chartArea ) ;
393
- doFill ( ctx , points , mapper , el ) ;
478
+ doFill ( ctx , points , mapper , colors , el , chart . chartArea ) ;
394
479
helpers . canvas . unclipArea ( ctx ) ;
395
480
}
396
481
}
0 commit comments