@@ -609,26 +609,76 @@ drawing.makeTester = function() {
609
609
drawing . testref = testref ;
610
610
} ;
611
611
612
- // use our offscreen tester to get a clientRect for an element,
613
- // in a reference frame where it isn't translated and its anchor
614
- // point is at (0,0)
615
- // always returns a copy of the bbox, so the caller can modify it safely
612
+ /*
613
+ * use our offscreen tester to get a clientRect for an element,
614
+ * in a reference frame where it isn't translated and its anchor
615
+ * point is at (0,0)
616
+ * always returns a copy of the bbox, so the caller can modify it safely
617
+ */
616
618
drawing . savedBBoxes = { } ;
617
619
var savedBBoxesCount = 0 ;
618
620
var maxSavedBBoxes = 10000 ;
619
621
620
622
drawing . bBox = function ( node ) {
621
- // Cache elements we've already measured so we don't have to
622
- // remeasure the same thing many times
623
- // We have a few bBox callers though who pass a node larger than
624
- // a <text> or a MathJax <g>, such as an axis group containing many labels.
625
- // These will not generate a hash (unless we figure out an appropriate
626
- // hash key for them) and thus we will not hash them.
623
+ /*
624
+ * Cache elements we've already measured so we don't have to
625
+ * remeasure the same thing many times
626
+ * We have a few bBox callers though who pass a node larger than
627
+ * a <text> or a MathJax <g>, such as an axis group containing many labels.
628
+ * These will not generate a hash (unless we figure out an appropriate
629
+ * hash key for them) and thus we will not hash them.
630
+ */
627
631
var hash = nodeHash ( node ) ;
632
+ var out ;
628
633
if ( hash ) {
629
- var out = drawing . savedBBoxes [ hash ] ;
634
+ out = drawing . savedBBoxes [ hash ] ;
630
635
if ( out ) return Lib . extendFlat ( { } , out ) ;
631
636
}
637
+ else if ( node . children . length === 1 ) {
638
+ /*
639
+ * If we have only one child element, make a new hash from this element
640
+ * plus its x,y,transform
641
+ * These bounding boxes *include* x,y,transform - mostly for use by
642
+ * callers trying to avoid overlaps (ie titles)
643
+ */
644
+ var innerNode = node . children [ 0 ] ;
645
+
646
+ hash = nodeHash ( innerNode ) ;
647
+ if ( hash ) {
648
+ var x = + innerNode . getAttribute ( 'x' ) || 0 ;
649
+ var y = + innerNode . getAttribute ( 'y' ) || 0 ;
650
+ var transform = innerNode . getAttribute ( 'transform' ) || '' ;
651
+
652
+ if ( ! transform ) {
653
+ // in this case, just varying x and y, don't bother caching
654
+ // because the alteration is simple.
655
+ var innerBB = drawing . bBox ( innerNode ) ;
656
+ if ( x ) {
657
+ innerBB . left += x ;
658
+ innerBB . right += x ;
659
+ }
660
+ if ( y ) {
661
+ innerBB . top += y ;
662
+ innerBB . bottom += y ;
663
+ }
664
+ return innerBB ;
665
+ }
666
+ /*
667
+ * else we have a transform - rather than make a complicated
668
+ * (and error-prone and probably slow) transform parser/calculator,
669
+ * just continue on calculating the boundingClientRect of the group
670
+ * and use the new composite hash to cache it.
671
+ * That said, `innerNode.transform.baseVal` is an array of
672
+ * `SVGTransform` objects, that *do* seem to have a nice matrix
673
+ * multiplication interface that we could use to avoid making
674
+ * another getBoundingClientRect call...
675
+ */
676
+ hash += '~' + x + '~' + y + '~' + transform ;
677
+
678
+ out = drawing . savedBBoxes [ hash ] ;
679
+ if ( out ) return Lib . extendFlat ( { } , out ) ;
680
+ }
681
+ }
632
682
633
683
var tester = drawing . tester . node ( ) ;
634
684
@@ -662,7 +712,7 @@ drawing.bBox = function(node) {
662
712
// by saving boxes for long-gone elements
663
713
if ( savedBBoxesCount >= maxSavedBBoxes ) {
664
714
drawing . savedBBoxes = { } ;
665
- maxSavedBBoxes = 0 ;
715
+ savedBBoxesCount = 0 ;
666
716
}
667
717
668
718
// cache this bbox
@@ -674,21 +724,6 @@ drawing.bBox = function(node) {
674
724
675
725
// capture everything about a node (at least in our usage) that
676
726
// impacts its bounding box, given that bBox clears x, y, and transform
677
- // TODO: is this really everything? Is it worth taking only parts of style,
678
- // so we can share across more changes (like colors)? I guess we can't strip
679
- // colors and stuff from inside innerHTML so maybe not worth bothering outside.
680
- // TODO # 2: this can be long, so could take a lot of memory, do we want to
681
- // hash it? But that can be slow...
682
- // extracting this string from a typical element takes ~3 microsec, where
683
- // doing a simple hash ala https://stackoverflow.com/questions/7616461
684
- // adds ~15 microsec (nearly all of this is spent in charCodeAt)
685
- // function hash(s) {
686
- // var h = 0;
687
- // for (var i = 0; i < s.length; i++) {
688
- // h = (((h << 5) - h) + s.charCodeAt(i)) | 0; // codePointAt?
689
- // }
690
- // return h;
691
- // }
692
727
function nodeHash ( node ) {
693
728
var inputText = node . getAttribute ( 'data-unformatted' ) ;
694
729
if ( inputText === null ) return ;
0 commit comments