@@ -632,6 +632,63 @@ lib.isD3Selection = function(obj) {
632
632
return obj && ( typeof obj . classed === 'function' ) ;
633
633
} ;
634
634
635
+ /**
636
+ * Append element to DOM only if not present.
637
+ *
638
+ * @param {d3 selection } parent : parent selection of the element in question
639
+ * @param {string } nodeType : node type of element to append
640
+ * @param {string } className : class name of element in question
641
+ * @param {fn } enterFn (optional) : optional fn applied to entering elements only
642
+ * @return {d3 selection } selection of new layer
643
+ *
644
+ * Previously, we were using the following pattern:
645
+ *
646
+ * ```
647
+ * var sel = parent.selectAll('.' + className)
648
+ * .data([0]);
649
+ *
650
+ * sel.enter().append(nodeType)
651
+ * .classed(className, true);
652
+ *
653
+ * return sel;
654
+ * ```
655
+ *
656
+ * in numerous places in our codebase to achieve the same behavior.
657
+ *
658
+ * The logic below performs much better, mostly as we are using
659
+ * `.select` instead `.selectAll` that is `querySelector` instead of
660
+ * `querySelectorAll`.
661
+ *
662
+ */
663
+ lib . ensureSingle = function ( parent , nodeType , className , enterFn ) {
664
+ var sel = parent . select ( nodeType + ( className ? '.' + className : '' ) ) ;
665
+ if ( sel . size ( ) ) return sel ;
666
+
667
+ var layer = parent . append ( nodeType ) . classed ( className , true ) ;
668
+ if ( enterFn ) layer . call ( enterFn ) ;
669
+
670
+ return layer ;
671
+ } ;
672
+
673
+ /**
674
+ * Same as Lib.ensureSingle, but using id as selector.
675
+ * This version is mostly used for clipPath nodes.
676
+ *
677
+ * @param {d3 selection } parent : parent selection of the element in question
678
+ * @param {string } nodeType : node type of element to append
679
+ * @param {string } id : id of element in question
680
+ * @param {fn } enterFn (optional) : optional fn applied to entering elements only
681
+ * @return {d3 selection } selection of new layer
682
+ */
683
+ lib . ensureSingleById = function ( parent , nodeType , id , enterFn ) {
684
+ var sel = parent . select ( nodeType + '#' + id ) ;
685
+ if ( sel . size ( ) ) return sel ;
686
+
687
+ var layer = parent . append ( nodeType ) . attr ( 'id' , id ) ;
688
+ if ( enterFn ) layer . call ( enterFn ) ;
689
+
690
+ return layer ;
691
+ } ;
635
692
636
693
/**
637
694
* Converts a string path to an object.
0 commit comments