raphael icon indicating copy to clipboard operation
raphael copied to clipboard

Solution to: getBBox NaN or Infinity

Open LiamKarlMitchell opened this issue 10 years ago • 1 comments

getBBox on a set will return Infinity and -Infinity for all of the bbox values. If done on one with a child set that is empty it would return NaN.

And this can also happen for a set with hidden elements. (We should probably also take their bboxs into consideration. Being able to pass an argument to also include hidden bounding boxes would be a good idea)

Returning a NaN or Infinity or -Infinity can be troublesome. The width and height calculation needs an isFinite check.

Basic code example of issue

Math.min.apply(0, [])

Would show Infinity.

Infinity - Infinity is a problem just like -Infinity - -Infinity would be a problem both result in NaN.

But then when calculating the width/height we need to do this

Raphael.st.getBBox = function () {
    var x = [],
        y = [],
        x2 = [],
        y2 = [];
    for (var i = this.items.length; i--;) if (!this.items[i].removed) {
        var box = this.items[i].getBBox();
        x.push(box.x);
        y.push(box.y);
        x2.push(box.x + box.width);
        y2.push(box.y + box.height);
    }
        x = mmin[apply](0, x);
        y = mmin[apply](0, y);
        x2 = mmax[apply](0, x2);
        y2 = mmax[apply](0, y2);
    return {
        x: x,
        y: y,
        x2: x2,
        y2: y2,
        width: isFinite(x2) && isFinite(x) ? x2 - x : 0,
        height: isFinite(y2) && isFinite(y) ? y2 - y : 0
    };
};

See the isFinite checks if both dimension parts are finite then its fine to use them to calculate a dimension size. Otherwise we should just return a dimension size of 0 because its sane, we cant draw to infinity on a finite system and infinite width or height has no use?.

LiamKarlMitchell avatar Aug 27 '14 03:08 LiamKarlMitchell

An update for IE 9, 10, 11 as they do not let you over write the returned object from this.node.getBBox(); Also works as an extension too Raphael :)

Raphael.el.origional_getBBox = Raphael.el._getBBox;
Raphael.el._getBBox = function () {
    if (this.node.style.display == "none") {
        this.show();
        var hide = true;
    }
    var bbox = {};
    try {
        // Copy the objects values because IE does not like you writing too them.
        var tmp = this.node.getBBox();
        bbox.x = tmp.x;
        bbox.y = tmp.y;
        bbox.width = tmp.width;
        bbox.height = tmp.height;
    } catch(e) {
        // Firefox 3.0.x plays badly here
    } finally {
        bbox = bbox || {};
        // does not take rotation into consideration
        if (bbox.x === 0 && this.attrs.x !== 0) {
          bbox.x = this.attrs.x;
        }

        if (bbox.y === 0 && this.attrs.y !== 0) {
          bbox.y = this.attrs.y;
        }
    }
    hide && this.hide();
    return bbox;
};

LiamKarlMitchell avatar Oct 08 '14 03:10 LiamKarlMitchell