I've not done JavaScript in quite a while, but I wanted to make it so that I can circle (in many different ways) around the bounding box of a tagged item.

Is this a good way of doing what I'm wanting?  Is there a better way?  I.e. can this be done with only CSS?

http://jsfiddle.net/adrianh/4SVHH/27/

    // Creating a tag with the class 'circled' will have that element circled
    // using a number of different ways by setting data-style attribute to:
    //   'default'  - an open ellipse (default)
    //   'ellipse'  - a closed ellipse
    //   'circle'   - a closed circle circumscribed around the bounding box.
    //   'rect'     - a closed rectangle
    //   'vbracket' - a square bracket like [ ]
    //   'hbracket' - a square bracket that is rotated 90 degrees
    //
    // Other attributes are:
    //   data-width - width of lines used to circle element. (default='2')
    //   data-style - can be: 'solid', 'dotted' or 'dashed'. (default='solid')
    //   data-color - any html color. (default='red')
    //
    // Note: The circle is around the bounding box of the tagged object,
    //       so if the object wraps, it will span the paragraph width.
    //
    // Note: Circle will be redrawn if window is resized.
    
    (function()
    {
        // draws an ellipse
        function drawEllipse(context, centerX, centerY, width, height)
        {
            var ratio = height/width;
            context.save();
            context.scale(1,  ratio);
            context.beginPath();
            context.arc(centerX, centerY/ratio, width/2, 0, 2 * Math.PI);
            context.restore();
        };
    
        // returns the appropriate array for the style requested
        function getLineDash(style)
        {
            if (style == "solid")
                return [];
            if (style == 'dotted')
                return [3];
            if (style == 'dashed')
                return [6, 3];
            return [];
        };
        
        // points at object that contains all the circle canvases
        var circles;
        
        // Return a canvas given an indexed number.  If the same
        // number is used multiple times, then that canvas is reused.
        // Canvas is positioned in the (left, top) coordinate in the
        // document with the specified width and height.
        function getCanvas(i, left, top, width, height)
        {
            var canvas;
            if (typeof circles.childNodes[i] != 'undefined')
            {
                canvas = circles.childNodes[i];
                canvas.width=width;
                canvas.height=height;
                canvas.style.left=left+"px";
                canvas.style.top=top+"px";
            }
            else
            {
                canvas = "<canvas "+
                "width='"+width+"' "+
                "height='"+height+"' "+
                "style='"+
                    "position:absolute;"+
                    "z-index:0;"+
                    "left:"+left+"px;"+
                    "top:"+top+"px;"+
                    "pointer-events:none;"+
                    //"border:1px solid;"+
                "' />";
                circles.insertAdjacentHTML('beforeend', canvas);
            }
            return circles.childNodes[i];
        };
        
        // draw a circle circumscribed around the rect
        function circleRect(i, rect, lineWidth, lineColor, lineStyle)
        {
            var diameter = Math.sqrt(rect.width*rect.width+rect.height*rect.height);
            var cx = (rect.right + rect.left)/2;
            var cy = (rect.top + rect.bottom)/2;
            var left = Math.floor(cx - diameter/2);
            var top  = Math.floor(cy - diameter/2);
            diameter = Math.floor(diameter);
            var canvas = getCanvas(i, left-1, top-1, diameter+2, diameter+2);
            var ctx=canvas.getContext("2d");
            ctx.beginPath();
            ctx.arc(diameter/2+1,diameter/2+1,diameter/2,0,2*Math.PI);
            ctx.lineWidth   = lineWidth;
            ctx.strokeStyle = lineColor;
            ctx.setLineDash = getLineDash(lineStyle);
            ctx.stroke();
        };
        
        // draw an open ellipse around the rect.
        function defaultRect(i, rect, lineWidth, lineColor, lineStyle)
        {
            var quarterWidth = rect.width/4;
            var quarterHeight = rect.height/4;
            var eighthWidth = quarterWidth/2;
            var eighthHeight = quarterHeight/2;
            var padx = quarterWidth;
            var pady = quarterHeight*1.5;
            var width = rect.width;
            var height = rect.height;
            var canvas = getCanvas(i, rect.left-padx, rect.top-pady, width+padx*2, height+pady*2);
            //canvas.style.border="1px solid yellow";
            var ctx=canvas.getContext("2d");
            ctx.beginPath();
            ctx.moveTo(       padx+width/2,             pady+eighthHeight);
            ctx.bezierCurveTo(padx-quarterWidth,        pady+quarterHeight/3,
                              padx,                     pady+height+eighthHeight,
                              padx+width/2-eighthWidth, pady+height+eighthHeight);
            ctx.bezierCurveTo(padx+width+quarterWidth,  pady+height+quarterHeight,
                              padx+width+eighthWidth,   pady-eighthHeight*3,
                              padx+width/2-eighthWidth, pady-quarterHeight);
            ctx.lineWidth   = lineWidth;
            ctx.strokeStyle = lineColor;
            ctx.setLineDash(getLineDash(lineStyle));
            ctx.stroke();
        //    ctx.strokeStyle = "blue";
        //    ctx.lineWidth = 1;
        //    ctx.strokeRect(padx, pady, width, height);
        };
        
        // draw an ellipse around the rect
        function ellipseRect(i, rect, lineWidth, lineColor, lineStyle)
        {
            var padx = 200;
            var pady = 200;
            var canvas = getCanvas(i, rect.left-padx, rect.top-pady, rect.width+padx*2, rect.height+pady*2);
            var ctx=canvas.getContext("2d");
            //canvas.style.border = "1px blue solid"
            drawEllipse(ctx, rect.width/2+padx, rect.height/2+pady, rect.width, rect.height);
            ctx.lineWidth   = lineWidth;
            ctx.strokeStyle = lineColor;
            ctx.setLineDash(getLineDash(lineStyle));
            ctx.stroke();
        };
        
        // Draw a rectangle around the rect.
        function rectRect(i, rect, lineWidth, lineColor, lineStyle)
        {
            var half = Math.ceil(lineWidth/2);
            var padx = lineWidth;
            var pady = lineWidth;
            var canvas = getCanvas(i, rect.left-padx, rect.top-pady, rect.width+padx*2, rect.height+pady*2);
            //canvas.style.border = "1px blue solid";
            var ctx=canvas.getContext("2d");
            ctx.lineWidth   = lineWidth;
            ctx.strokeStyle = lineColor;
            ctx.setLineDash(getLineDash(lineStyle));
            ctx.strokeRect(padx-half, pady-half, rect.width+lineWidth/2, rect.height+lineWidth/2);
        };
        
        // Draw a rectangle around the rect.
        function vbracketRect(i, rect, lineWidth, lineColor, lineStyle)
        {
            var half = Math.ceil(lineWidth/2);
            var padx = lineWidth*2;
            var pady = lineWidth*2;
            var canvas = getCanvas(i, rect.left-padx, rect.top-pady, rect.width+padx*2, rect.height+pady*2);
            //canvas.style.border = "1px blue solid";
            var ctx=canvas.getContext("2d");
            ctx.lineWidth   = lineWidth;
            ctx.strokeStyle = lineColor;
            ctx.setLineDash(getLineDash(lineStyle));
            ctx.beginPath();
            ctx.moveTo(padx-half+half*3            , pady-half);
            ctx.lineTo(padx-half                   , pady-half);
            ctx.lineTo(padx-half                   , pady+half+rect.height);
            ctx.lineTo(padx-half+half*3            , pady+half+rect.height);
            ctx.moveTo(padx+half+rect.width-half*3 , pady-half);
            ctx.lineTo(padx+half+rect.width        , pady-half);
            ctx.lineTo(padx+half+rect.width        , pady+half+rect.height);
            ctx.lineTo(padx+half+rect.width-half*3 , pady+half+rect.height);
            ctx.stroke();
        };
        
        function hbracketRect(i, rect, lineWidth, lineColor, lineStyle)
        {
            var half = Math.ceil(lineWidth/2);
            var padx = lineWidth*2;
            var pady = lineWidth*2;
            var canvas = getCanvas(i, rect.left-padx, rect.top-pady, rect.width+padx*2, rect.height+pady*2);
            //canvas.style.border = "1px blue solid";
            var ctx=canvas.getContext("2d");
            ctx.lineWidth   = lineWidth;
            ctx.strokeStyle = lineColor;
            ctx.setLineDash(getLineDash(lineStyle));
            ctx.beginPath();
            ctx.moveTo(padx-half                   , pady-half+half*3);
            ctx.lineTo(padx-half                   , pady-half);
            ctx.lineTo(padx+half+rect.width        , pady-half);
            ctx.lineTo(padx+half+rect.width        , pady-half+half*3);
            ctx.moveTo(padx-half                   , pady+half+rect.height-half*3);
            ctx.lineTo(padx-half                   , pady+half+rect.height);
            ctx.lineTo(padx+half+rect.width        , pady+half+rect.height);
            ctx.lineTo(padx+half+rect.width        , pady+half+rect.height-half*3);
            ctx.stroke();
        };
        
        // if x is null return _default, otherwise return x.
        function val(x, _default)
        {
            return (x == null) ? _default : x;
        };
    
        // This draws the circles around all 'circled' class objects.
        function drawCircles()
        {
            $(".circled").each(function(i, obj) {
                var rect  = obj.getBoundingClientRect();
                var type  = val(obj.getAttribute("data-type"), "default");
                var width = val(obj.getAttribute("data-width"), 2);
                var color = val(obj.getAttribute("data-color"), "red");
                var style = val(obj.getAttribute("data-style"), "solid");
                if (type == 'default')
                {
                    defaultRect(i, rect, width, color, style);
                }
                else if (type == 'rect')
                {
                    rectRect(i, rect, width, color, style);
                }
                else if (type == 'ellipse')
                {
                    ellipseRect(i, rect, width, color, style);
                }
                else if (type == 'vbracket')
                {
                    vbracketRect(i, rect, width, color, style);
                }
                else if (type == 'hbracket')
                {
                    hbracketRect(i, rect, width, color, style);
                }
                else if (type == 'circle')
                {
                    circleRect(i, rect, width, color, style);
                }
            });
        };
    
        // Place a div container to place all of the canvases in.
        document.body.insertAdjacentHTML('afterbegin', '<div id="circles"></div>');
        circles = document.getElementById("circles");
        
        // Draw the circles upon loading the document and 
        // if the window extents have changed.
        window.onload=drawCircles;
        window.onresize=drawCircles;
    })();