@@ -354,6 +354,145 @@ drawing.gradient = function(sel, gd, gradientID, type, colorscale, prop) {
354
354
fullLayout . _gradientUrlQueryParts [ k ] = 1 ;
355
355
} ;
356
356
357
+ /**
358
+ * pattern: create and apply a pattern fill
359
+ *
360
+ * @param {object } sel: d3 selection to apply this pattern to
361
+ * You can use `selection.call(Drawing.pattern, ...)`
362
+ * @param {DOM element } gd: the graph div `sel` is part of
363
+ * @param {string } patternID: a unique (within this plot) identifier
364
+ * for this pattern, so that we don't create unnecessary definitions
365
+ * @param {string } bgcolor: background color for this pattern
366
+ * @param {string } fgcolor: foreground color for this pattern
367
+ * @param {number } scale: scale of this pattern
368
+ * @param {number } solidity: how solid lines of this pattern are
369
+ * @param {string } prop: the property to apply to, 'fill' or 'stroke'
370
+ */
371
+ drawing . pattern = function ( sel , gd , patternID , shape , bgcolor , fgcolor , scale , solidity , prop ) {
372
+ var fullLayout = gd . _fullLayout ;
373
+ var fullID = 'p' + fullLayout . _uid + '-' + patternID ;
374
+ var baseSize = 8 * scale ;
375
+ var width , height ;
376
+
377
+ var path = '' ;
378
+ switch ( shape ) {
379
+ case '/' :
380
+ width = baseSize * Math . sqrt ( 2 ) ;
381
+ height = baseSize * Math . sqrt ( 2 ) ;
382
+ path = 'M-1,1l2,-2' +
383
+ 'M0,' + height + 'L' + width + ',0' +
384
+ 'M' + ( width - 1 ) + ',' + ( height + 1 ) + 'l2,-2' ;
385
+ break ;
386
+ case '\\' :
387
+ width = baseSize * Math . sqrt ( 2 ) ;
388
+ height = baseSize * Math . sqrt ( 2 ) ;
389
+ path = 'M' + ( width - 1 ) + ',-1l2,2' +
390
+ 'M0,0L' + width + ',' + height +
391
+ 'M-1,' + ( height - 1 ) + 'l2,2' ;
392
+ break ;
393
+ case 'x' :
394
+ width = baseSize * Math . sqrt ( 2 ) ;
395
+ height = baseSize * Math . sqrt ( 2 ) ;
396
+ path = 'M-1,1l2,-2' +
397
+ 'M0,' + height + 'L' + width + ',0' +
398
+ 'M' + ( width - 1 ) + ',' + ( height + 1 ) + 'l2,-2' +
399
+ 'M' + ( width - 1 ) + ',-1l2,2' +
400
+ 'M0,0L' + width + ',' + height +
401
+ 'M-1,' + ( height - 1 ) + 'l2,2' ;
402
+ break ;
403
+ case '|' :
404
+ width = baseSize ;
405
+ height = baseSize ;
406
+ path = 'M' + ( width / 2 ) + ',0L' + ( width / 2 ) + ',' + height ;
407
+ break ;
408
+ case '-' :
409
+ width = baseSize ;
410
+ height = baseSize ;
411
+ path = 'M0,' + ( height / 2 ) + 'L' + width + ',' + ( height / 2 ) ;
412
+ break ;
413
+ case '+' :
414
+ width = baseSize ;
415
+ height = baseSize ;
416
+ path = 'M' + ( width / 2 ) + ',0L' + ( width / 2 ) + ',' + height +
417
+ 'M0,' + ( height / 2 ) + 'L' + width + ',' + ( height / 2 ) ;
418
+ break ;
419
+ case '+' :
420
+ width = baseSize ;
421
+ height = baseSize ;
422
+ path = 'M' + ( width / 2 ) + ',0L' + ( width / 2 ) + ',' + height +
423
+ 'M0,' + ( height / 2 ) + 'L' + width + ',' + ( height / 2 ) ;
424
+ break ;
425
+ case '.' :
426
+ width = baseSize ;
427
+ height = baseSize ;
428
+ break ;
429
+ }
430
+
431
+ var pattern = fullLayout . _defs . select ( '.patterns' )
432
+ . selectAll ( '#' + fullID )
433
+ . data ( [ 0 ] ) ;
434
+
435
+ pattern . exit ( ) . remove ( ) ;
436
+
437
+ pattern . enter ( )
438
+ . append ( 'pattern' )
439
+ . each ( function ( ) {
440
+ var el = d3 . select ( this ) ;
441
+
442
+ el . attr ( {
443
+ 'id' : fullID ,
444
+ 'width' : width + 'px' ,
445
+ 'height' : height + 'px' ,
446
+ 'patternUnits' : 'userSpaceOnUse'
447
+ } ) ;
448
+
449
+ var rects = el . selectAll ( 'rect' ) . data ( [ 0 ] ) ;
450
+ rects . exit ( ) . remove ( ) ;
451
+ if ( bgcolor ) {
452
+ rects . enter ( )
453
+ . append ( 'rect' )
454
+ . attr ( {
455
+ 'width' : width + 'px' ,
456
+ 'height' : height + 'px' ,
457
+ 'fill' : bgcolor
458
+ } ) ;
459
+ }
460
+
461
+ if ( shape == '.' ) {
462
+ var circles = el . selectAll ( 'circle' ) . data ( [ 0 ] ) ;
463
+ circles . exit ( ) . remove ( ) ;
464
+ circles . enter ( )
465
+ . append ( 'circle' )
466
+ . attr ( {
467
+ 'cx' : width / 2 ,
468
+ 'cy' : height / 2 ,
469
+ 'r' : solidity ,
470
+ 'fill' : fgcolor
471
+ } ) ;
472
+ } else {
473
+ var paths = el . selectAll ( 'path' ) . data ( [ 0 ] ) ;
474
+ paths . exit ( ) . remove ( ) ;
475
+ paths . enter ( )
476
+ . append ( 'path' )
477
+ . attr ( {
478
+ 'd' : path ,
479
+ 'stroke' : fgcolor ,
480
+ 'stroke-width' : solidity + 'px'
481
+ } ) ;
482
+ }
483
+ } ) ;
484
+
485
+ sel . style ( prop , getFullUrl ( fullID , gd ) )
486
+ . style ( prop + '-opacity' , null ) ;
487
+
488
+ sel . classed ( "pattern_filled" , true ) ;
489
+ var className2query = function ( s ) {
490
+ return '.' + s . attr ( 'class' ) . replace ( / \s / g, '.' ) ;
491
+ } ;
492
+ var k = className2query ( d3 . select ( sel . node ( ) . parentNode ) ) + '>.pattern_filled' ;
493
+ fullLayout . _patternUrlQueryParts [ k ] = 1 ;
494
+ } ;
495
+
357
496
/*
358
497
* Make the gradients container and clear out any previous gradients.
359
498
* We never collect all the gradients we need in one place,
@@ -372,6 +511,16 @@ drawing.initGradients = function(gd) {
372
511
fullLayout . _gradientUrlQueryParts = { } ;
373
512
} ;
374
513
514
+ drawing . initPatterns = function ( gd ) {
515
+ var fullLayout = gd . _fullLayout ;
516
+
517
+ var patternsGroup = Lib . ensureSingle ( fullLayout . _defs , 'g' , 'patterns' ) ;
518
+ patternsGroup . selectAll ( 'pattern' ) . remove ( ) ;
519
+
520
+ // initialize stash of query parts filled in Drawing.pattern,
521
+ // used to fix URL strings during image exports
522
+ fullLayout . _patternUrlQueryParts = { } ;
523
+ } ;
375
524
376
525
drawing . pointStyle = function ( s , trace , gd ) {
377
526
if ( ! s . size ( ) ) return ;
@@ -482,6 +631,16 @@ drawing.singlePointStyle = function(d, sel, trace, fns, gd) {
482
631
if ( ! gradientInfo [ gradientType ] ) gradientType = 0 ;
483
632
}
484
633
634
+ var getPatternAttr = function ( mp , i , dflt ) {
635
+ if ( mp && Array . isArray ( mp ) ) {
636
+ if ( i < mp . length ) return mp [ i ] ;
637
+ else return dflt ;
638
+ }
639
+ return mp ;
640
+ } ;
641
+ var markerPattern = marker . patternfill ;
642
+ var patternShape = markerPattern && getPatternAttr ( markerPattern . shape , d . i , '' ) ;
643
+
485
644
if ( gradientType && gradientType !== 'none' ) {
486
645
var gradientColor = d . mgc ;
487
646
if ( gradientColor ) perPointGradient = true ;
@@ -492,6 +651,20 @@ drawing.singlePointStyle = function(d, sel, trace, fns, gd) {
492
651
493
652
drawing . gradient ( sel , gd , gradientID , gradientType ,
494
653
[ [ 0 , gradientColor ] , [ 1 , fillColor ] ] , 'fill' ) ;
654
+ } else if ( patternShape ) {
655
+ var patternBGColor = getPatternAttr ( markerPattern . bgcolor , d . i , null ) ;
656
+ var patternScale = getPatternAttr ( markerPattern . scale , d . i , 1 ) ;
657
+ var patternSolidity = getPatternAttr ( markerPattern . solidity , d . i , 1 ) ;
658
+ var perPointPattern = Array . isArray ( markerPattern . shape ) ||
659
+ Array . isArray ( markerPattern . bgcolor ) ||
660
+ Array . isArray ( markerPattern . scale ) ||
661
+ Array . isArray ( markerPattern . solidity ) ;
662
+
663
+ var patternID = trace . uid ;
664
+ if ( perPointPattern ) patternID += '-' + d . i ;
665
+
666
+ drawing . pattern ( sel , gd , patternID , patternShape , patternBGColor , fillColor ,
667
+ patternScale , patternSolidity , 'fill' ) ;
495
668
} else {
496
669
Color . fill ( sel , fillColor ) ;
497
670
}
0 commit comments