Bounding Containers in RaphaelJS

Read more about it here: http://terryyoung.blogspot.com/2011/08/bounding-containers-in-raphaeljs.html

by Terry Young

HTML

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<p>This demonstrates my getCBox() function, which calculates the bounding container coordinates of any given number of objects.</p>
<p>The green container is the result.</p>
<p>Drag any of the small elements (i.e. Image, Rect, Text) and the container resizes.</p>
<p>Or click one of the two buttons to randomize positions automatically.</p>
<p>Hover the green container to view the refreshed connector dot positions.</p>
<p>
<button id="SVG_GETCBOX_MANUAL">Randomize Manually</button>
<button id="SVG_GETCBOX_AUTO">Randomize Continuously</button>
</p>
<br>

<div id="SVG_GETCBOX_1" class="SVG_CONNECTORS_HOLDER"></div>

CSS

/***********************************************************************
Common styles
***********************************************************************/

html, body, button
{
font-family:            Tahoma;
font-size:              9pt;
line-height:            14pt;
}

br.clear
{
clear:                  both;
}

/***********************************************************************
Common styles
***********************************************************************/

.SVG_CONNECTORS_HOLDER {

-moz-border-radius:       10px;
-webkit-border-radius:    10px;
border-radius:            10px;
border:                   solid 3px #818ca0;
background-color:         #dbdee3;
width:                    640px;
height:                   260px;

}

JavaScript

/**
 * @blog       http://terryyoung.blogspot.com/2011/08/bounding-containers-in-raphaeljs.html
 */


///////////////////////////////////////////////////////////////////////////////
// Please scroll to the bottom to look at the usage code of this demo.
// These below are some core extensions to RaphaelJS that makes it all happen.


/**
 * Simplifies something like this:
 *
 * this.ox = this.type == 'rect' ? this.attr('x') : this.attr('cx');
 * this.oy = this.type == 'rect' ? this.attr('y') : this.attr('cy');
 *
 * to this:
 *
 * el.o();    // and better, it supports chaining
 *
 * @copyright   Terry Young <terryyounghk [at] gmail.com>
 * @license     WTFPL Version 2 ( http://en.wikipedia.org/wiki/WTFPL )
 */
Raphael.el.is = function (type) { return this.type == (''+type).toLowerCase(); };
Raphael.el.isNot = function (type) { return this.type != (''+type).toLowerCase(); };
Raphael.el.x = function () { return this.is('circle') ? this.attr('cx') : this.attr('x'); };
Raphael.el.y = function () { return this.is('circle') ? this.attr('cy') : this.attr('y'); };
Raphael.el.o = function () { this.ox = this.x(); this.oy = this.y(); return this; };


/**
 * getABox() for RaphaelJS - getBBox() On Steroids
 * More routine, pre-calculated values that getBBox() doesn't provide
 *
 * @author      Terry Young <terryyounghk [at] gmail.com>
 * @license     WTFPL Version 2 ( http://en.wikipedia.org/wiki/WTFPL )
 */
Raphael.el.getABox = function ()
{
    var b = this.getBBox(); // thanks, I'll take it from here...

    var o =
    {
        // we'd still return what the original getBBox() provides us with
        x:              b.x,
        y:              b.y,
        width:          b.width,
        height:         b.height,

        // three different x coordinates: left edge, centered, and right edge
        xLeft:          b.x,
        xCenter:        b.x + b.width / 2,
        xRight:         b.x + b.width,


        // three different y coordinates: top edge, middle, and...