@@ -609,26 +609,76 @@ drawing.makeTester = function() {
609609 drawing . testref = testref ;
610610} ;
611611
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+ */
616618drawing . savedBBoxes = { } ;
617619var savedBBoxesCount = 0 ;
618620var maxSavedBBoxes = 10000 ;
619621
620622drawing . 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+ */
627631 var hash = nodeHash ( node ) ;
632+ var out ;
628633 if ( hash ) {
629- var out = drawing . savedBBoxes [ hash ] ;
634+ out = drawing . savedBBoxes [ hash ] ;
630635 if ( out ) return Lib . extendFlat ( { } , out ) ;
631636 }
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+ }
632682
633683 var tester = drawing . tester . node ( ) ;
634684
@@ -662,7 +712,7 @@ drawing.bBox = function(node) {
662712 // by saving boxes for long-gone elements
663713 if ( savedBBoxesCount >= maxSavedBBoxes ) {
664714 drawing . savedBBoxes = { } ;
665- maxSavedBBoxes = 0 ;
715+ savedBBoxesCount = 0 ;
666716 }
667717
668718 // cache this bbox
@@ -674,21 +724,6 @@ drawing.bBox = function(node) {
674724
675725// capture everything about a node (at least in our usage) that
676726// 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- // }
692727function nodeHash ( node ) {
693728 var inputText = node . getAttribute ( 'data-unformatted' ) ;
694729 if ( inputText === null ) return ;
0 commit comments