Mercurial > hg > digilib
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; }; /**