@@ -177,8 +177,9 @@ drawing.dashStyle = function(dash, lineWidth) {
177
177
return dash ;
178
178
} ;
179
179
180
- function setFillStyle ( sel , trace , gd ) {
180
+ function setFillStyle ( sel , trace , gd , forLegend ) {
181
181
var markerPattern = trace . fillpattern ;
182
+ var fillgradient = trace . fillgradient ;
182
183
var patternShape = markerPattern && drawing . getPatternAttr ( markerPattern . shape , 0 , '' ) ;
183
184
if ( patternShape ) {
184
185
var patternBGColor = drawing . getPatternAttr ( markerPattern . bgcolor , 0 , null ) ;
@@ -192,6 +193,55 @@ function setFillStyle(sel, trace, gd) {
192
193
undefined , markerPattern . fillmode ,
193
194
patternBGColor , patternFGColor , patternFGOpacity
194
195
) ;
196
+ } else if ( fillgradient && fillgradient . type !== 'none' ) {
197
+ var direction = fillgradient . type ;
198
+ var gradientID = 'scatterfill-' + trace . uid ;
199
+ if ( forLegend ) {
200
+ gradientID = 'legendfill-' + trace . uid ;
201
+ }
202
+
203
+ if ( ! forLegend && ( fillgradient . start !== undefined || fillgradient . stop !== undefined ) ) {
204
+ var start , stop ;
205
+ if ( direction === 'horizontal' ) {
206
+ start = {
207
+ x : fillgradient . start ,
208
+ y : 0 ,
209
+ } ;
210
+ stop = {
211
+ x : fillgradient . stop ,
212
+ y : 0 ,
213
+ } ;
214
+ } else if ( direction === 'vertical' ) {
215
+ start = {
216
+ x : 0 ,
217
+ y : fillgradient . start ,
218
+ } ;
219
+ stop = {
220
+ x : 0 ,
221
+ y : fillgradient . stop ,
222
+ } ;
223
+ }
224
+
225
+ start . x = trace . _xA . c2p (
226
+ ( start . x === undefined ) ? trace . _extremes . x . min [ 0 ] . val : start . x , true
227
+ ) ;
228
+ start . y = trace . _yA . c2p (
229
+ ( start . y === undefined ) ? trace . _extremes . y . min [ 0 ] . val : start . y , true
230
+ ) ;
231
+
232
+ stop . x = trace . _xA . c2p (
233
+ ( stop . x === undefined ) ? trace . _extremes . x . max [ 0 ] . val : stop . x , true
234
+ ) ;
235
+ stop . y = trace . _yA . c2p (
236
+ ( stop . y === undefined ) ? trace . _extremes . y . max [ 0 ] . val : stop . y , true
237
+ ) ;
238
+ sel . call ( gradientWithBounds , gd , gradientID , 'linear' , fillgradient . colorscale , 'fill' , start , stop , true , false ) ;
239
+ } else {
240
+ if ( direction === 'horizontal' ) {
241
+ direction = direction + 'reversed' ;
242
+ }
243
+ sel . call ( drawing . gradient , gd , gradientID , direction , fillgradient . colorscale , 'fill' ) ;
244
+ }
195
245
} else if ( trace . fillcolor ) {
196
246
sel . call ( Color . fill , trace . fillcolor ) ;
197
247
}
@@ -202,17 +252,17 @@ drawing.singleFillStyle = function(sel, gd) {
202
252
var node = d3 . select ( sel . node ( ) ) ;
203
253
var data = node . data ( ) ;
204
254
var trace = ( ( data [ 0 ] || [ ] ) [ 0 ] || { } ) . trace || { } ;
205
- setFillStyle ( sel , trace , gd ) ;
255
+ setFillStyle ( sel , trace , gd , false ) ;
206
256
} ;
207
257
208
- drawing . fillGroupStyle = function ( s , gd ) {
258
+ drawing . fillGroupStyle = function ( s , gd , forLegend ) {
209
259
s . style ( 'stroke-width' , 0 )
210
260
. each ( function ( d ) {
211
261
var shape = d3 . select ( this ) ;
212
262
// N.B. 'd' won't be a calcdata item when
213
263
// fill !== 'none' on a segment-less and marker-less trace
214
264
if ( d [ 0 ] . trace ) {
215
- setFillStyle ( shape , d [ 0 ] . trace , gd ) ;
265
+ setFillStyle ( shape , d [ 0 ] . trace , gd , forLegend ) ;
216
266
}
217
267
} ) ;
218
268
} ;
@@ -294,16 +344,14 @@ function makePointPath(symbolNumber, r, t, s) {
294
344
return drawing . symbolFuncs [ base ] ( r , t , s ) + ( symbolNumber >= 200 ? DOTPATH : '' ) ;
295
345
}
296
346
297
- var HORZGRADIENT = { x1 : 1 , x2 : 0 , y1 : 0 , y2 : 0 } ;
298
- var VERTGRADIENT = { x1 : 0 , x2 : 0 , y1 : 1 , y2 : 0 } ;
299
347
var stopFormatter = numberFormat ( '~f' ) ;
300
348
var gradientInfo = {
301
- radial : { node : 'radialGradient ' } ,
302
- radialreversed : { node : 'radialGradient ' , reversed : true } ,
303
- horizontal : { node : 'linearGradient ' , attrs : HORZGRADIENT } ,
304
- horizontalreversed : { node : 'linearGradient ' , attrs : HORZGRADIENT , reversed : true } ,
305
- vertical : { node : 'linearGradient ' , attrs : VERTGRADIENT } ,
306
- verticalreversed : { node : 'linearGradient ' , attrs : VERTGRADIENT , reversed : true }
349
+ radial : { type : 'radial ' } ,
350
+ radialreversed : { type : 'radial ' , reversed : true } ,
351
+ horizontal : { type : 'linear ' , start : { x : 1 , y : 0 } , stop : { x : 0 , y : 0 } } ,
352
+ horizontalreversed : { type : 'linear ' , start : { x : 1 , y : 0 } , stop : { x : 0 , y : 0 } , reversed : true } ,
353
+ vertical : { type : 'linear ' , start : { x : 0 , y : 1 } , stop : { x : 0 , y : 0 } } ,
354
+ verticalreversed : { type : 'linear ' , start : { x : 0 , y : 1 } , stop : { x : 0 , y : 0 } , reversed : true }
307
355
} ;
308
356
309
357
/**
@@ -321,8 +369,57 @@ var gradientInfo = {
321
369
* @param {string } prop: the property to apply to, 'fill' or 'stroke'
322
370
*/
323
371
drawing . gradient = function ( sel , gd , gradientID , type , colorscale , prop ) {
324
- var len = colorscale . length ;
325
372
var info = gradientInfo [ type ] ;
373
+ return gradientWithBounds (
374
+ sel , gd , gradientID , info . type , colorscale , prop , info . start , info . stop , false , info . reversed
375
+ ) ;
376
+ } ;
377
+
378
+ /**
379
+ * gradient_with_bounds: create and apply a gradient fill for defined start and stop positions
380
+ *
381
+ * @param {object } sel: d3 selection to apply this gradient to
382
+ * You can use `selection.call(Drawing.gradient, ...)`
383
+ * @param {DOM element } gd: the graph div `sel` is part of
384
+ * @param {string } gradientID: a unique (within this plot) identifier
385
+ * for this gradient, so that we don't create unnecessary definitions
386
+ * @param {string } type: 'radial' or 'linear'. Radial goes center to edge,
387
+ * horizontal goes as defined by start and stop
388
+ * @param {array } colorscale: as in attribute values, [[fraction, color], ...]
389
+ * @param {string } prop: the property to apply to, 'fill' or 'stroke'
390
+ * @param {object } start: start point for linear gradients, { x: number, y: number }.
391
+ * Ignored if type is 'radial'.
392
+ * @param {object } stop: stop point for linear gradients, { x: number, y: number }.
393
+ * Ignored if type is 'radial'.
394
+ * @param {boolean } inUserSpace: If true, start and stop give absolute values in the plot.
395
+ * If false, start and stop are fractions of the traces extent along each axis.
396
+ * @param {boolean } reversed: If true, the gradient is reversed between normal start and stop,
397
+ * i.e., the colorscale is applied in order from stop to start for linear, from edge
398
+ * to center for radial gradients.
399
+ */
400
+ function gradientWithBounds ( sel , gd , gradientID , type , colorscale , prop , start , stop , inUserSpace , reversed ) {
401
+ var len = colorscale . length ;
402
+
403
+ var info ;
404
+ if ( type === 'linear' ) {
405
+ info = {
406
+ node : 'linearGradient' ,
407
+ attrs : {
408
+ x1 : start . x ,
409
+ y1 : start . y ,
410
+ x2 : stop . x ,
411
+ y2 : stop . y ,
412
+ gradientUnits : inUserSpace ? 'userSpaceOnUse' : 'objectBoundingBox' ,
413
+ } ,
414
+ reversed : reversed ,
415
+ } ;
416
+ } else if ( type === 'radial' ) {
417
+ info = {
418
+ node : 'radialGradient' ,
419
+ reversed : reversed ,
420
+ } ;
421
+ }
422
+
326
423
var colorStops = new Array ( len ) ;
327
424
for ( var i = 0 ; i < len ; i ++ ) {
328
425
if ( info . reversed ) {
@@ -368,7 +465,7 @@ drawing.gradient = function(sel, gd, gradientID, type, colorscale, prop) {
368
465
. style ( prop + '-opacity' , null ) ;
369
466
370
467
sel . classed ( 'gradient_filled' , true ) ;
371
- } ;
468
+ }
372
469
373
470
/**
374
471
* pattern: create and apply a pattern fill
0 commit comments