changeset 1386:d8beafc1df41

sort image areas by size so that smaller areas are not eclipsed by bigger ones. shape initialisation not complete. measure tool currently broken.
author robcast
date Mon, 23 Mar 2015 18:13:03 +0100
parents 9376a5fe1166
children 2540222b6dfe
files webapp/src/main/webapp/jquery/jquery.digilib.measure.js webapp/src/main/webapp/jquery/jquery.digilib.vector.js
diffstat 2 files changed, 282 insertions(+), 193 deletions(-) [+]
line wrap: on
line diff
--- a/webapp/src/main/webapp/jquery/jquery.digilib.measure.js	Sun Mar 15 19:17:29 2015 +0100
+++ b/webapp/src/main/webapp/jquery/jquery.digilib.measure.js	Mon Mar 23 18:13:03 2015 +0100
@@ -1274,134 +1274,150 @@
 
     // set up additional SVG shapes
     var setupSvgFactory = function(data) {
-        var factory = data.svgFactory;
+        var factory = data.shapeFactory;
         if (factory == null) {
             console.error("No SVG factory found: jquery.digilib.vector not loaded?");
             return;
             }
-        factory['Proportion'] = function (shape) {
-            var $s = factory['LineString'](shape);
-            shape.properties.maxvtx = 3;
-            return $s;
+        factory['Proportion'] = {
+                'setup' : function (data, shape) {
+                    shape.properties.maxvtx = 3;
+                },
+                'svg' : function (shape) {
+                    var $s = factory['LineString'].svg(shape);
+                    return $s;
+                }
             };
-        factory['Rect'] = function (shape) {
-            var trafo = data.imgTrafo;
-            var $s = factory['Polygon'](shape);
-            var props = shape.properties;
-            props.maxvtx = 3;
-            $s.place = function () {
-                var p = props.screenpos;
-                var vtx = props.vtx;
-                if (p.length > 2) { // p[2] is the mouse pointer
-                    var line1 = geom.line(p[0], p[1]); // base line
-                    var line2 = line1.parallel(p[2]);
-                    var p3 = line1.perpendicular().intersection(line2);
-                    var p2 = p3.copy().add(line1.vector());
-                    p[2] = p2.mid(p3); // handle position
-                    shape.geometry.coordinates[2] = trafo.invtransform(p[2]).toArray();
-                    props.pos = [p2, p3]; // save other points
-                    }
-                this.attr({points: [p[0], p[1], p2, p3].join(" ")});
-                };
-            return $s;
+        factory['Rect'] = {
+                'setup' : function (data, shape) {
+                    shape.properties.maxvtx = 3;
+                },
+                'svg' : function (shape) {
+                    var trafo = data.imgTrafo;
+                    var $s = factory['Polygon'].svg(shape);
+                    var props = shape.properties;
+                    $s.place = function () {
+                        var p = props.screenpos;
+                        var vtx = props.vtx;
+                        if (p.length > 2) { // p[2] is the mouse pointer
+                            var line1 = geom.line(p[0], p[1]); // base line
+                            var line2 = line1.parallel(p[2]);
+                            var p3 = line1.perpendicular().intersection(line2);
+                            var p2 = p3.copy().add(line1.vector());
+                            p[2] = p2.mid(p3); // handle position
+                            shape.geometry.coordinates[2] = trafo.invtransform(p[2]).toArray();
+                            props.pos = [p2, p3]; // save other points
+                            }
+                        this.attr({points: [p[0], p[1], p2, p3].join(" ")});
+                        };
+                    return $s;
+                }
             };
-        factory['Oval'] = function (shape) {
-            var trafo = data.imgTrafo;
-            var $s = factory['Rect'](shape);
-            var props = shape.properties;
-            var place = $s.place;
-            var guide = CSS+'guide';
-            var constr = CSS+'constr';
-            $s.attr({'class' : guide});
-            props.maxvtx = 4;
-            var $g = $(fn.svgElement('g', {'id': shape.id + '-oval'}));
-            var $c1 = $(fn.svgElement('circle', {'id': shape.id + '-circ1', 'class': guide }));
-            var $c2 = $(fn.svgElement('circle', {'id': shape.id + '-circ2', 'class': guide }));
-            var $p1 = $(fn.svgElement('path',   {'id': shape.id + '-lines', 'class': guide }));
-            var $p2 = $(fn.svgElement('path',   {'id': shape.id + '-arc', stroke: props.stroke, fill: 'none' }));
-            var $p3 = $(fn.svgElement('path',   {'id': shape.id + '-constr', 'class': constr })); // debug construction
-            $g.append($s).append($c1).append($c2).append($p1).append($p2).append($p3);
-            $g.place = function () {
-                var p = props.screenpos;
-                place.call($s); // place the framing rectangle (polygon)
-                if (p.length > 3) { // p[3] is the mouse pointer
-                    var side0 = geom.line(p[0], p[1])
-                    var side1 = geom.line(p[1], props.pos[0]);
-                    var side2 = geom.line(props.pos[0], props.pos[1]);
-                    var side3 = geom.line(props.pos[1], p[0]);
-                    var mid0 = side0.mid(); // midpoints of sides
-                    var mid1 = side1.mid();
-                    var mid2 = side2.mid();
-                    var mid3 = side3.mid();
-                    var axis0 = side0.parallel(mid3); // short axis
-                    var axis1 = side1.parallel(mid0); // long axis
-                    var maxDiam = axis0.length()-1; // maximal diameter for small circles
-                    var handle = axis1.perpendicularPoint(p[3]); // drag point projected on long axis
-                    if (handle.distance(mid0) > axis1.length()) { // constrain handle
-                        handle.moveTo(mid2);
-                    } else if (handle.distance(mid2) > maxDiam) {
-                        handle.moveTo(geom.line(mid2, handle).length(maxDiam).point());
-                        }
-                    var m1 = handle.mid(mid2); // midpoints of the small circles
-                    var m2 = axis0.mirror(m1);
-                    var rad1 = m1.distance(mid2); // radius of the small circles
-                    var rd = axis0.copy().length(rad1).point(); // radius distance from short axis
-                    var ld = geom.line(rd, m1);
-                    var md = rd.mid(m1);
-                    var bi = ld.perpendicular(md); // perpendicular bisector
-                    var m3 = axis0.intersection(bi); // midpoints of the big circles
-                    var m4 = axis1.mirror(m3);
-                    var fp1 = geom.line(m3, m1).addEnd(rad1); // the four fitting points
-                    var fp2 = geom.line(m3, m2).addEnd(rad1);
-                    var fp3 = geom.line(m4, m1).addEnd(rad1);
-                    var fp4 = geom.line(m4, m2).addEnd(rad1);
-                    var rad2 = m3.distance(fp1); // radius of the big circles
-                    // place the SVG shapes
-                    $c1.attr({cx: m1.x, cy: m1.y, r: rad1});
-                    $c2.attr({cx: m2.x, cy: m2.y, r: rad1});
-                    $p1.attr({d: // the guides
-                        'M'+fp1+' L'+m3+' '+fp2+
-                        'M'+fp3+' L'+m4+' '+fp4+
-                        'M'+mid0+' L'+mid2+
-                        'M'+mid1+' L'+mid3});
-                    $p2.attr({d: 'M'+fp2+ // the arcs
-                        ' A'+rad2+','+rad2+' 0 0,1 '+fp1+
-                        ' A'+rad1+','+rad1+' 0 0,1 '+fp3+
-                        ' A'+rad2+','+rad2+' 0 0,1 '+fp4+
-                        ' A'+rad1+','+rad1+' 0 0,1 '+fp2});
-                    $p3.attr({d: 'M'+rd+' L'+m1+' M'+md+' '+m3}); // debug construction
-                    p[3] = handle;
-                    shape.geometry.coordinates[3] = trafo.invtransform(handle).toArray();
-                    }
-                };
-            return $g;
+        factory['Oval'] = {
+                'setup' : function (data, shape) {
+                    shape.properties.maxvtx = 4;
+                },
+                'svg' : function (shape) {
+                    var trafo = data.imgTrafo;
+                    var $s = factory['Rect'].svg(shape);
+                    var props = shape.properties;
+                    var place = $s.place;
+                    var guide = CSS+'guide';
+                    var constr = CSS+'constr';
+                    $s.attr({'class' : guide});
+                    var $g = $(fn.svgElement('g', {'id': shape.id + '-oval'}));
+                    var $c1 = $(fn.svgElement('circle', {'id': shape.id + '-circ1', 'class': guide }));
+                    var $c2 = $(fn.svgElement('circle', {'id': shape.id + '-circ2', 'class': guide }));
+                    var $p1 = $(fn.svgElement('path',   {'id': shape.id + '-lines', 'class': guide }));
+                    var $p2 = $(fn.svgElement('path',   {'id': shape.id + '-arc', stroke: props.stroke, fill: 'none' }));
+                    var $p3 = $(fn.svgElement('path',   {'id': shape.id + '-constr', 'class': constr })); // debug construction
+                    $g.append($s).append($c1).append($c2).append($p1).append($p2).append($p3);
+                    $g.place = function () {
+                        var p = props.screenpos;
+                        place.call($s); // place the framing rectangle (polygon)
+                        if (p.length > 3) { // p[3] is the mouse pointer
+                            var side0 = geom.line(p[0], p[1])
+                            var side1 = geom.line(p[1], props.pos[0]);
+                            var side2 = geom.line(props.pos[0], props.pos[1]);
+                            var side3 = geom.line(props.pos[1], p[0]);
+                            var mid0 = side0.mid(); // midpoints of sides
+                            var mid1 = side1.mid();
+                            var mid2 = side2.mid();
+                            var mid3 = side3.mid();
+                            var axis0 = side0.parallel(mid3); // short axis
+                            var axis1 = side1.parallel(mid0); // long axis
+                            var maxDiam = axis0.length()-1; // maximal diameter for small circles
+                            var handle = axis1.perpendicularPoint(p[3]); // drag point projected on long axis
+                            if (handle.distance(mid0) > axis1.length()) { // constrain handle
+                                handle.moveTo(mid2);
+                            } else if (handle.distance(mid2) > maxDiam) {
+                                handle.moveTo(geom.line(mid2, handle).length(maxDiam).point());
+                                }
+                            var m1 = handle.mid(mid2); // midpoints of the small circles
+                            var m2 = axis0.mirror(m1);
+                            var rad1 = m1.distance(mid2); // radius of the small circles
+                            var rd = axis0.copy().length(rad1).point(); // radius distance from short axis
+                            var ld = geom.line(rd, m1);
+                            var md = rd.mid(m1);
+                            var bi = ld.perpendicular(md); // perpendicular bisector
+                            var m3 = axis0.intersection(bi); // midpoints of the big circles
+                            var m4 = axis1.mirror(m3);
+                            var fp1 = geom.line(m3, m1).addEnd(rad1); // the four fitting points
+                            var fp2 = geom.line(m3, m2).addEnd(rad1);
+                            var fp3 = geom.line(m4, m1).addEnd(rad1);
+                            var fp4 = geom.line(m4, m2).addEnd(rad1);
+                            var rad2 = m3.distance(fp1); // radius of the big circles
+                            // place the SVG shapes
+                            $c1.attr({cx: m1.x, cy: m1.y, r: rad1});
+                            $c2.attr({cx: m2.x, cy: m2.y, r: rad1});
+                            $p1.attr({d: // the guides
+                                'M'+fp1+' L'+m3+' '+fp2+
+                                'M'+fp3+' L'+m4+' '+fp4+
+                                'M'+mid0+' L'+mid2+
+                                'M'+mid1+' L'+mid3});
+                            $p2.attr({d: 'M'+fp2+ // the arcs
+                                ' A'+rad2+','+rad2+' 0 0,1 '+fp1+
+                                ' A'+rad1+','+rad1+' 0 0,1 '+fp3+
+                                ' A'+rad2+','+rad2+' 0 0,1 '+fp4+
+                                ' A'+rad1+','+rad1+' 0 0,1 '+fp2});
+                            $p3.attr({d: 'M'+rd+' L'+m1+' M'+md+' '+m3}); // debug construction
+                            p[3] = handle;
+                            shape.geometry.coordinates[3] = trafo.invtransform(handle).toArray();
+                            }
+                        };
+                    return $g;
+                }
             };
-        factory['Grid'] = function (shape) {
-            var $s = factory['Line'](shape);
-            var place = $s.place;
-            var gridID = shape.id + '-grid';
-            var props = shape.properties;
-            props.maxvtx = 2;
-            var $g = $(fn.svgElement('g', {id: shape.id + '-g'}));
-            var $defs = $(fn.svgElement('defs'));
-            var $pat = $(fn.svgElement('pattern', {id: gridID, height: '10%', width: '10%', patternUnits: 'objectBoundingBox'}));
-            var $path = $(fn.svgElement('path', {d: "M1000,0 L0,0 0,1000", fill: 'none', stroke: props.stroke, 'stroke-width': '1'}));
-            var $r = $(fn.svgElement('rect', {id: shape.id + '-rect', stroke: props.stroke, fill: 'url(#'+gridID+')'}));
-            $g.append($defs.append($pat.append($path))).append($r).append($s);
-            $g.place = function () {
-                place.call($s);
-                var p = props.screenpos;
-                var d = p[0].distance(p[1]);
-                var angle = mRound(p[0].deg(p[1]));
-                var scale = 10;
-                var fac = Math.ceil((1-scale)/2);
-                var x = p[0].x + fac * d;
-                var y = p[0].y + (fac-1) * d;
-                var transform = 'rotate('+angle+' '+p[0].x+' '+p[0].y+')';
-                $r.attr({x:x, y:y, height:d*scale, width:d*scale, transform:transform});
-                $pat.attr({patternTransform:transform});
-                };
-            return $g;
+        factory['Grid'] = {
+                'setup' : function (data, shape) {
+                    shape.properties.maxvtx = 2;
+                },
+                'svg' : function (shape) {
+                    var $s = factory['Line'](shape);
+                    var place = $s.place;
+                    var gridID = shape.id + '-grid';
+                    var props = shape.properties;
+                    var $g = $(fn.svgElement('g', {id: shape.id + '-g'}));
+                    var $defs = $(fn.svgElement('defs'));
+                    var $pat = $(fn.svgElement('pattern', {id: gridID, height: '10%', width: '10%', patternUnits: 'objectBoundingBox'}));
+                    var $path = $(fn.svgElement('path', {d: "M1000,0 L0,0 0,1000", fill: 'none', stroke: props.stroke, 'stroke-width': '1'}));
+                    var $r = $(fn.svgElement('rect', {id: shape.id + '-rect', stroke: props.stroke, fill: 'url(#'+gridID+')'}));
+                    $g.append($defs.append($pat.append($path))).append($r).append($s);
+                    $g.place = function () {
+                        place.call($s);
+                        var p = props.screenpos;
+                        var d = p[0].distance(p[1]);
+                        var angle = mRound(p[0].deg(p[1]));
+                        var scale = 10;
+                        var fac = Math.ceil((1-scale)/2);
+                        var x = p[0].x + fac * d;
+                        var y = p[0].y + (fac-1) * d;
+                        var transform = 'rotate('+angle+' '+p[0].x+' '+p[0].y+')';
+                        $r.attr({x:x, y:y, height:d*scale, width:d*scale, transform:transform});
+                        $pat.attr({patternTransform:transform});
+                        };
+                    return $g;
+                }
             };
         };
 
--- a/webapp/src/main/webapp/jquery/jquery.digilib.vector.js	Sun Mar 15 19:17:29 2015 +0100
+++ b/webapp/src/main/webapp/jquery/jquery.digilib.vector.js	Mon Mar 23 18:13:03 2015 +0100
@@ -225,7 +225,7 @@
         // shapes layer is first
         data.vectorLayers = [shapeLayer];
         // pluggable SVG create functions 
-        setupSVGFactory(data);
+        data.shapeFactory = getShapeFactory(data);
         setupHandleFactory(data);
         // install event handlers
         $data.bind('update', handleUpdate);
@@ -284,14 +284,26 @@
      * @param layer
      */
     var renderShapes = function (data, layer) {
+        if (layer == null) {
+            // assume shape layer is 0
+            layer = data.vectorLayers[0];
+        }
     	var shapes = layer.shapes || data.shapes;
     	console.debug("renderShapes shapes:", shapes);
     	if (shapes == null || data.imgTrafo == null || !data.settings.isVectorActive) 
     	    return;
-    	if (layer == null) {
-    	    // assume shape layer is 0
-    	    layer = data.vectorLayers[0];
-    	}
+    	// set up shapes
+        for (var i = 0; i < shapes.length; ++i) {
+            var shape = shapes[i];
+            data.shapeFactory[shape.geometry.type].setup(data, shape);
+        }
+        // sort shapes by size descending
+        shapes.sort(function (a, b) {
+           console.debug("sort.compare:",a.properties.sorta,b.properties.sorta);
+           return (b.properties.sorta - a.properties.sorta); 
+        });
+        console.debug("renderShapes: sorted shapes:", shapes);
+        // set up SVG
     	var $svg = layer.$elem;
         if ($svg != null) {
         	$svg.remove();
@@ -314,12 +326,12 @@
     };
 
     /**
-     * setup SVG creation functions
-     * (more functions can be plugged into data.settings.SVGFactory)
+     * setup Shape SVG creation functions
+     * (more functions can be plugged into data.settings.ShapeFactory)
      * 
      * @param data
      */
-    var setupSVGFactory = function (data) {
+    var getShapeFactory = function (data) {
         var settings = data.settings;
         var css = settings.cssPrefix;
         var hs = settings.editHandleSize;
@@ -336,74 +348,118 @@
                 };
             };
         var factory = {
-            'Point' : function (shape) {
-                var $s = $(svgElement('path', svgAttr(shape)));
-                shape.properties.maxvtx = 1;
-                $s.place = function () {
-                    // point uses pin-like path of size 3*pu
-                    var p = shape.properties.screenpos[0];
-                    var pu = hs / 3;
-                    this.attr({'d': 'M '+p.x+','+p.y+' l '+2*pu+','+pu+' c '+2*pu+','+pu+' '+0+','+3*pu+' '+(-pu)+','+pu+' Z'});
-                    };
-                return $s;
+            'Point' : {
+                'setup' : function (data, shape) {
+                    shape.properties.maxvtx = 1;
+                    shape.properties.sorta = 0;
+                },
+                'svg' : function (shape) {
+                    var $s = $(svgElement('path', svgAttr(shape)));
+                    $s.place = function () {
+                        // point uses pin-like path of size 3*pu
+                        var p = shape.properties.screenpos[0];
+                        var pu = hs / 3;
+                        this.attr({'d': 'M '+p.x+','+p.y+' l '+2*pu+','+pu+' c '+2*pu+','+pu+' '+0+','+3*pu+' '+(-pu)+','+pu+' Z'});
+                        };
+                    return $s;
+                }
+            },
+            'Line' : {
+                'setup' : function (data, shape) {
+                    shape.properties.maxvtx = 2;
+                    shape.properties.bbox = getBboxRect(data, shape);
+                    shape.properties.sorta = 0;
                 },
-            'Line' : function (shape) {
-                shape.properties.maxvtx = 2;
-                var $s = $(svgElement('line', svgAttr(shape)));
-                $s.place = function () {
-                    var p = shape.properties.screenpos;
-                    this.attr({'x1': p[0].x, 'y1': p[0].y, 'x2': p[1].x, 'y2': p[1].y});
-                    };
-                return $s;
+                'svg' : function (shape) {
+                    var $s = $(svgElement('line', svgAttr(shape)));
+                    $s.place = function () {
+                        var p = shape.properties.screenpos;
+                        this.attr({'x1': p[0].x, 'y1': p[0].y, 'x2': p[1].x, 'y2': p[1].y});
+                        };
+                    return $s;
+                }
+            },
+            'Rectangle' : {
+                'setup' : function (data, shape) {
+                    shape.properties.maxvtx = 2;
+                    shape.properties.bbox = getBboxRect(data, shape);
+                    shape.properties.sorta = shape.properties.bbox.getArea();
                 },
-            'Rectangle' : function (shape) {
-                shape.properties.maxvtx = 2;
-                var $s = $(svgElement('rect', svgAttr(shape)));
-                $s.place = function () {
-                    var p = shape.properties.screenpos;
-                    var r = geom.rectangle(p[0], p[1]);
-                    this.attr({'x': r.x, 'y': r.y, 'width': r.width, 'height': r.height});
-                    };
-                return $s;
+                'svg' : function (shape) {
+                    var $s = $(svgElement('rect', svgAttr(shape)));
+                    $s.place = function () {
+                        var p = shape.properties.screenpos;
+                        var r = geom.rectangle(p[0], p[1]);
+                        this.attr({'x': r.x, 'y': r.y, 'width': r.width, 'height': r.height});
+                        };
+                    return $s;
+                }
+            },
+            'Polygon' : {
+                'setup' : function (data, shape) {
+                    shape.properties.bbox = getBboxRect(data, shape);
+                    shape.properties.sorta = shape.properties.bbox.getArea();
                 },
-            'Polygon' : function (shape) {
-                var $s = $(svgElement('polygon', svgAttr(shape)));
-                $s.place = function () {
-                    var p = shape.properties.screenpos;
-                    this.attr({'points': p.join(" ")});
-                    };
-                return $s;
-                },
-            'LineString' : function (shape) {
-                var $s = $(svgElement('polyline', svgAttr(shape)));
-                $s.place = function () {
-                    var p = shape.properties.screenpos;
-                    this.attr({'points': p.join(" ")});
-                    };
-                return $s;
+                'svg' : function (shape) {
+                    var $s = $(svgElement('polygon', svgAttr(shape)));
+                    $s.place = function () {
+                        var p = shape.properties.screenpos;
+                        this.attr({'points': p.join(" ")});
+                        };
+                    return $s;
+                }
+            },
+            'LineString' : {
+                'setup' : function (data, shape) {
+                    shape.properties.bbox = getBboxRect(data, shape);
+                    shape.properties.sorta = shape.properties.bbox.getArea();
                 },
-            'Circle' : function (shape) {
-                shape.properties.maxvtx = 2;
-                var $s = $(svgElement('circle', svgAttr(shape)));
-                $s.place = function () {
-                    var p = shape.properties.screenpos;
-                    this.attr({'cx': p[0].x, 'cy': p[0].y, 'r': p[0].distance(p[1])});
-                    };
-                return $s;
+                'svg' : function (shape) {
+                    var $s = $(svgElement('polyline', svgAttr(shape)));
+                    $s.place = function () {
+                        var p = shape.properties.screenpos;
+                        this.attr({'points': p.join(" ")});
+                        };
+                    return $s;
+                }
+            },
+            'Circle' : {
+                'setup' : function (data, shape) {
+                    shape.properties.maxvtx = 2;
+                    // TODO: bbox not really accurate
+                    shape.properties.bbox = getBboxRect(data, shape);
+                    shape.properties.sorta = shape.properties.bbox.getArea();
                 },
-            'Ellipse' : function (shape) {
-                shape.properties.maxvtx = 2;
-                var $s = $(svgElement('ellipse', svgAttr(shape)));
-                $s.place = function () {
-                    var p = shape.properties.screenpos;
-                    this.attr({'cx': p[0].x, 'cy': p[0].y,
-                        'rx' : Math.abs(p[0].x - p[1].x),
-                        'ry' : Math.abs(p[0].y - p[1].y)});
-                    };
-                return $s;
+                'svg' : function (shape) {
+                    var $s = $(svgElement('circle', svgAttr(shape)));
+                    $s.place = function () {
+                        var p = shape.properties.screenpos;
+                        this.attr({'cx': p[0].x, 'cy': p[0].y, 'r': p[0].distance(p[1])});
+                        };
+                    return $s;
+                }
+            },
+            'Ellipse' : {
+                'setup' : function (data, shape) {
+                    shape.properties.maxvtx = 2;
+                    // TODO: bbox not really accurate
+                    shape.properties.bbox = getBboxRect(data, shape);
+                    shape.properties.sorta = shape.properties.bbox.getArea();
+                },
+                'svg' : function (shape) {
+                    var $s = $(svgElement('ellipse', svgAttr(shape)));
+                    $s.place = function () {
+                        var p = shape.properties.screenpos;
+                        this.attr({'cx': p[0].x, 'cy': p[0].y,
+                            'rx' : Math.abs(p[0].x - p[1].x),
+                            'ry' : Math.abs(p[0].y - p[1].y)});
+                        };
+                    return $s;
+                    }
                 }
             };
-        data.svgFactory = factory;
+
+        return factory;
     };
 
     /**
@@ -508,6 +564,24 @@
         return screenpos;
     };
 
+    var getBboxRect = function (data, shape) {
+        var coords = shape.geometry.coordinates;
+        var xmin = 1;
+        var xmax = 0;
+        var ymin = 1;
+        var ymax = 0;
+        var x, y;
+        for (var i = 0; i < coords.length; ++i) {
+            x = coords[i][0];
+            y = coords[i][1];
+            xmin = (x < xmin) ? x : xmin;
+            xmax = (x > xmax) ? x : xmax;
+            ymin = (y < ymin) ? y : ymin;
+            ymax = (y > ymax) ? y : ymax;            
+        }
+        return geom.rectangle(xmin, ymin, xmax-xmin, ymax-ymin);
+    };
+    
     /**
      * render a shape on screen.
      * 
@@ -530,8 +604,7 @@
             return;
         }
         // create the SVG
-        var newSVG = data.svgFactory[shapeType];
-        var $elem = newSVG(shape);
+        var $elem = data.shapeFactory[shapeType].svg(shape);
         shape.$elem = $elem;
         // place the SVG on screen
         createScreenCoords(data, shape);
@@ -656,7 +729,7 @@
      * @param shapeType shapeType to test
      */
     var isSupported = function (data, shapeType) {
-        return data.svgFactory[shapeType] != null;
+        return data.shapeFactory[shapeType] != null;
     };
 
     /**