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