Skip to content

Commit 8305c02

Browse files
committed
let drawing.bBox cache simple nested elements
1 parent 46d6e44 commit 8305c02

File tree

1 file changed

+62
-27
lines changed

1 file changed

+62
-27
lines changed

src/components/drawing/index.js

+62-27
Original file line numberDiff line numberDiff line change
@@ -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+
*/
616618
drawing.savedBBoxes = {};
617619
var savedBBoxesCount = 0;
618620
var maxSavedBBoxes = 10000;
619621

620622
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+
*/
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-
// }
692727
function nodeHash(node) {
693728
var inputText = node.getAttribute('data-unformatted');
694729
if(inputText === null) return;

0 commit comments

Comments
 (0)