Mercurial > hg > digilib
changeset 1538:747ed0af8663
annotations: some refactoring in shape creation; enable shape editing
author | hertzhaft |
---|---|
date | Sun, 16 Oct 2016 20:41:53 +0200 |
parents | dc63c24c59be |
children | 157198c7e805 |
files | webapp/src/main/webapp/jquery/jquery.digilib.annotator.js webapp/src/main/webapp/jquery/jquery.digilib.measure.js webapp/src/main/webapp/jquery/jquery.digilib.vector.js |
diffstat | 3 files changed, 167 insertions(+), 180 deletions(-) [+] |
line wrap: on
line diff
--- a/webapp/src/main/webapp/jquery/jquery.digilib.annotator.js Thu Oct 13 18:08:14 2016 +0200 +++ b/webapp/src/main/webapp/jquery/jquery.digilib.annotator.js Sun Oct 16 20:41:53 2016 +0200 @@ -42,6 +42,14 @@ // annotation shape layer var annotationLayer = null; + // translate shapes to Digilib + var shapeTypeMap = { + point: 'Point', + rectangle: 'Rectangle', + linestring: 'LineString', + polygon: 'Polygon' + }; + var buttons = { annotations : { onclick : "toggleAnnotations", @@ -126,7 +134,7 @@ setAnnotationMark : function (data, mpos, text) { if (mpos == null) { // interactive - setAnnotationShape(data, 'Point'); + addAnnotationShape(data, 'point'); } else { // use position and text (and user-id) console.error("Sorry, currently only interactive annotations!"); @@ -143,7 +151,7 @@ setAnnotationRect : function (data, rect, text) { if (rect == null) { // interactive - setAnnotationShape(data, 'Rectangle'); + addAnnotationShape(data, 'rectangle'); } else { // use position and text (and user-id) console.error("Sorry, currently only interactive annotations!"); @@ -154,13 +162,13 @@ * set a polygon-annotation by clicking (or giving a position and a text) * * @param data - * @param poly + * @param polygon * @param text */ - setAnnotationPolygon : function (data, poly, text) { - if (poly == null) { + setAnnotationPolygon : function (data, polygon, text) { + if (polygon == null) { // interactive - setAnnotationShape(data, 'Polygon'); + addAnnotationShape(data, 'polygon'); } else { // use position and text (and user-id) console.error("Sorry, currently only interactive annotations!"); @@ -174,10 +182,10 @@ * @param poly * @param text */ - setAnnotationPolyline : function (data, poly, text) { - if (poly == null) { + setAnnotationPolyline : function (data, polyline, text) { + if (polyline == null) { // interactive - setAnnotationShape(data, 'LineString'); + addAnnotationShape(data, 'linestring'); } else { // use position and text (and user-id) console.error("Sorry, currently only interactive annotations!"); @@ -267,73 +275,67 @@ /** * Add a shape-annotation where clicked. */ - var setAnnotationShape = function (data, type) { - var annotator = data.annotator; - var shape = {'geometry': {'type': type}}; - digilib.actions.addShape(data, shape, function (data, newshape) { - console.debug("new annotation shape:", newshape); - var annoShape = null; - var pos = null; - if (type === 'Point') { - pos = geom.position(newshape.geometry.coordinates[0]); - // create annotation shape - annoShape = {'type': 'point', 'geometry': pos}; - annoShape.geometry['units'] = 'fraction'; - } else if (type === 'Rectangle') { - pos = geom.position(newshape.geometry.coordinates[0]); - var pt2 = geom.position(newshape.geometry.coordinates[1]); - var rect = geom.rectangle(pos, pt2); - // create annotation shape - annoShape = {'type': 'rectangle', 'geometry': rect}; - annoShape.geometry['units'] = 'fraction'; - } else if (type === 'Polygon') { - pos = geom.position(newshape.geometry.coordinates[0]); - // create annotation shape - annoShape = {'type': 'polygon', 'geometry': {'coordinates': newshape.geometry.coordinates}}; - annoShape.geometry['units'] = 'fraction'; - } else if (type === 'LineString') { - pos = geom.position(newshape.geometry.coordinates[0]); - // create annotation shape - annoShape = {'type': 'linestring', 'geometry': {'coordinates': newshape.geometry.coordinates}}; - annoShape.geometry['units'] = 'fraction'; - } else { - console.error("Unsupported annotation shape="+type); - return; - } - var mpos = data.imgTrafo.transform(pos); - createAnnotation(data, annoShape, mpos); - }, annotationLayer); + var addAnnotationShape = function (data, type) { + var onComplete = function (data, shape) { + if (! shape.type in data.shapeFactory) { + console.error("Unsupported annotation shape="+type); + return; + } + var newshape = { + type: shape.type, + geometry: shape.geometry + }; + if (shape.type === 'Rectangle') { + var c = shape.geometry.coordinates; + newshape.geometry = geom.rectangle(c[0], c[1]); + } + newshape.geometry.units = 'fraction'; + // screen position for annotation editor + var pos = geom.position(newshape.geometry.coordinates[0]); + var mpos = data.imgTrafo.transform(pos); + console.debug("creating annotation for shape:", newshape); + addAnnotationContent(data, newshape, mpos); + }; + var shape = { + type: type, + geometry: { + type: shapeTypeMap[type] + } + }; + digilib.actions.addShape(data, shape, annotationLayer, onComplete); }; /** * Show editor and save annotation. */ - var createAnnotation = function (data, shape, screenPos) { - var annotator = data.annotator; - annotator.selectedShapes = [shape]; - // create and edit new annotation - var annotation = annotator.createAnnotation(); - var cleanup = function () { - annotator.unsubscribe('annotationEditorSubmit', save); - annotator.unsubscribe('annotationEditorHidden', cancel); - }; - var save = function () { - console.log("annotation save."); - cleanup(); - annotator.setupAnnotation(annotation); - // Fire annotationCreated events so that plugins can react to them - annotator.publish('annotationCreated', [annotation]); - renderAnnotations(data); - }; - var cancel = function () { - console.log("annotation cancel."); - cleanup(); - renderAnnotations(data); - }; - annotator.subscribe('annotationEditorSubmit', save); - annotator.subscribe('annotationEditorHidden', cancel); - annotator.showEditor(annotation, screenPos.getAsCss()); + var addAnnotationContent = function (data, shape, screenPos) { + var annotator = data.annotator; + annotator.selectedShapes = [shape]; + // create and edit new annotation + var annotation = annotator.createAnnotation(); + annotation.editing = true; + var cleanup = function () { + annotator.unsubscribe('annotationEditorSubmit', save); + annotator.unsubscribe('annotationEditorHidden', cancel); + delete annotation.editing; + }; + var save = function () { + console.log("annotation save."); + cleanup(); + annotator.setupAnnotation(annotation); + // Fire annotationCreated events so that plugins can react to them + annotator.publish('annotationCreated', [annotation]); + renderAnnotations(data); + }; + var cancel = function () { + console.log("annotation cancel."); + cleanup(); + renderAnnotations(data); + }; + annotator.subscribe('annotationEditorSubmit', save); + annotator.subscribe('annotationEditorHidden', cancel); + annotator.showEditor(annotation, screenPos.getAsCss()); }; /** @@ -351,7 +353,10 @@ var shapes = []; if (data.dlOpts.isAnnotationsVisible) { for (var i = 0; i < annotations.length; ++i) { - shapes = shapes.concat(createShape(data, annotations[i])); + var annot = annotations[i]; + var annoshapes = createShape(data, annot); + annotationLayer.shapeindex[annot.annotation.id] = annoshapes; + shapes = shapes.concat(annoshapes); } } annotationLayer.shapes = shapes; @@ -390,19 +395,12 @@ var shapes = []; if (annotation.areas != null && annotation.shapes == null) { console.warn("Annotation uses legacy 'areas' format! Converting..."); - /* - * convert legacy annotation areas into shapes - */ + // convert legacy annotation areas into shapes area = geom.rectangle(annotation.areas[0]); annoShape = { 'geometry' : area, - 'units' : 'fraction' - }; - if (area.isRectangle()) { - annoShape['type'] = 'rectangle'; - } else { - annoShape['type'] = 'point'; - } + 'type': area.isRectangle() ? 'rectangle' : 'point' + }; delete annotation.areas; annotation.shapes = [annoShape]; } @@ -415,73 +413,36 @@ // annotation shape annoShape = annotation.shapes[i]; type = annoShape.type; + var coordinates; if (type === "point") { area = geom.position(annoShape.geometry); - shape = { - 'id': id, - 'geometry': { - 'type' : 'Point', - 'coordinates' : [[area.x, area.y]] - }, - 'properties' : { - 'stroke' : 'yellow', - 'cssclass' : cssPrefix+'svg-annotation annotator-hl', - 'style' : 'pointer-events:all' - }, - 'annotation': annotation - }; + coordinates = [[area.x, area.y]]; } else if (type === "rectangle") { area = geom.rectangle(annoShape.geometry); - // render rectangle - var pt1 = area.getPt1(); - var pt2 = area.getPt2(); - shape = { - 'id': id, - 'geometry': { - 'type' : 'Rectangle', - 'coordinates' : [[pt1.x, pt1.y], [pt2.x, pt2.y]] - }, - 'properties' : { - 'stroke' : 'yellow', - 'cssclass' : cssPrefix+'svg-annotationregion annotator-hl', - 'style' : 'pointer-events:all' - }, - 'annotation': annotation - }; - } else if (type === "polygon") { - // render polygon - shape = { - 'id': id, - 'geometry': { - 'type' : 'Polygon', - 'coordinates' : annoShape.geometry.coordinates - }, - 'properties' : { - 'stroke' : 'yellow', - 'cssclass' : cssPrefix+'svg-annotationregion annotator-hl', - 'style' : 'pointer-events:all' - }, - 'annotation': annotation - }; - } else if (type === "linestring") { - // render polyline - shape = { - 'id': id, - 'geometry': { - 'type' : 'LineString', - 'coordinates' : annoShape.geometry.coordinates - }, - 'properties' : { - 'stroke' : 'yellow', - 'cssclass' : cssPrefix+'svg-annotation annotator-hl', - 'style' : 'pointer-events:visiblePainted' - }, - 'annotation': annotation - }; + var pt1 = area.getPt1(); + var pt2 = area.getPt2(); + coordinates = [[pt1.x, pt1.y], [pt2.x, pt2.y]]; + } else if (type in shapeTypeMap) { + coordinates = annoShape.geometry.coordinates; } else { - console.error("Unsupported annotation shape type: "+type); + console.error("Unsupported annotation shape="+type); return; } + var shape = { + 'id': id, + 'annotation': annotation, + 'geometry': { + 'type': shapeTypeMap[type], + 'units' : 'fraction', + 'coordinates': coordinates + }, + 'properties': { + 'stroke': 'yellow', + 'cssclass': cssPrefix+'svg-annotationregion annotator-hl', + 'style': 'pointer-events:all' + } + }; + console.debug('createshape: '+type, annoShape, shape); shapes.push(shape); } return shapes; @@ -515,9 +476,13 @@ if (annoShape.cssclass != null) { $annotation[0].classList.add(shape.cssclass); } - // hook up Annotator events - $annotation.on("mouseover", annotator.onHighlightMouseover); - $annotation.on("mouseout", annotator.startViewerHideTimer); + // no mouseover when editing + if (shape.properties.editable || annotation.editing) { + $annotation[0].classList.remove('annotator-hl'); + } else { + $annotation.on("mouseover", annotator.onHighlightMouseover); + $annotation.on("mouseout", annotator.startViewerHideTimer); + } /* $annotation.on('click.dlAnnotation', function(event) { $(data).trigger('annotationClick', [$annotation]); }); */ @@ -783,9 +748,12 @@ annotationLayer = { 'projection': 'screen', 'renderFn': fn.vectorDefaultRenderFn, - 'shapes': [] + 'shapes': [], + 'shapeindex': {} }; digilib.actions.addVectorLayer(data, annotationLayer); + // make annotationLayer accessible for plugins + data.annotationLayer = annotationLayer; $(data).on("renderShape", handleRenderShape); // set up annotator (after html has been set up) var uri = getAnnotationPageUri(data);
--- a/webapp/src/main/webapp/jquery/jquery.digilib.measure.js Thu Oct 13 18:08:14 2016 +0200 +++ b/webapp/src/main/webapp/jquery/jquery.digilib.measure.js Sun Oct 16 20:41:53 2016 +0200 @@ -754,13 +754,13 @@ Line : { name : 'line', display : 'length', }, LineString : { name : 'linestring', display : 'length' }, Proportion : { name : 'proportion', display : 'length' }, - Rectangle : { name : 'box', display : 'diagonal' }, + Rectangle : { name : 'box', display : 'diagonal' }, Rect : { name : 'rectangle', display : 'area' }, Square : { name : 'square', display : 'length' }, Polygon : { name : 'polygon', display : 'area' }, Circle : { name : 'circle', display : 'radius' }, Ellipse : { name : 'ellipse', display : 'area' }, - Oval : { name : 'oval', display : 'distance' }, + Oval : { name : 'oval', display : 'distance' }, Grid : { name : 'linegrid', display : 'spacing' } }, // currently selected shape type @@ -832,7 +832,7 @@ var shape = newShape(data); var layer = data.measureLayer; $(data).trigger('createShape', shape); - digilib.actions.addShape(data, shape, shapeCompleted, layer); + digilib.actions.addShape(data, shape, layer, shapeCompleted); console.debug('drawshape', shape); _debug_shape('action drawshape', shape); } @@ -1401,7 +1401,8 @@ 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 + '-constr', 'class': constr })); // debug construction + var $p2 = $(fn.svgElement('path', {'id': shape.id + '-constr', 'class': constr })); // debug construction + var $arc = $(fn.svgElement('path', {'id': shape.id + '-arc', 'class': shapeClass, stroke: props.stroke, 'stroke-width': styles.shape['stroke-width'], fill: 'none' })); $g.append($s).append($c1).append($c2).append($p1).append($p2).append($arc); $g.place = function () {
--- a/webapp/src/main/webapp/jquery/jquery.digilib.vector.js Thu Oct 13 18:08:14 2016 +0200 +++ b/webapp/src/main/webapp/jquery/jquery.digilib.vector.js Sun Oct 16 20:41:53 2016 +0200 @@ -28,7 +28,7 @@ * * Shapes are objects with "geometry" and "properties" members. * geometry is an object with "type" and "coordinates" members. - * Currently supported types: "Point", "Line", "LineString", "Rectangle", "Polygon", "Circle". + * Currently supported types: "Point", "Line", "LineString", "Rectangle", "Polygon", "Circle". * coordinates is a list of pairs of relative coordinates. * properties are the SVG properties "stroke", "stroke-width", "fill" and other properties. * A property 'editable':true will display drag-handles to change the shape. @@ -100,21 +100,25 @@ * @param onComplete * @param layer */ - addShape : function (data, shape, onComplete, layer) { + addShape : function (data, shape, layer, onComplete) { if (layer == null) { - // assume shape layer is 0 - layer = data.vectorLayers[0]; + // assume shape layer is 0 + layer = data.vectorLayers[0]; } if (layer.shapes == null) { layer.shapes = []; } - if (shape.geometry.coordinates == null) { + if (shape.geometry == null) { + shape.geometry = {}; + } + if (shape.geometry.coordinates == null) { // define shape interactively - defineShape(data, shape, layer, onComplete); - } else { - layer.shapes.push(shape); + defineShape(data, shape, layer, onComplete); + console.debug('addShape', shape); + } else { + layer.shapes.push(shape); renderShapes(data, layer); - } + } }, /** @@ -206,8 +210,13 @@ $.extend(digilib.defaults, defaults); $.extend(digilib.actions, actions); // export functions - digilib.fn.vectorDefaultRenderFn = renderShapes; - digilib.fn.svgElement = svgElement; + $.extend(digilib.fn, { + vectorDefaultRenderFn: renderShapes, + svgElement: svgElement, + createScreenCoords: createScreenCoords, + editShapeBegin: addEditHandles, + editShapeEnd: removeEditHandles + }); }; /** @@ -295,6 +304,7 @@ for (var i = 0; i < shapes.length; ++i) { var shape = shapes[i]; data.shapeFactory[shape.geometry.type].setup(data, shape); + console.debug('render', shape); } // sort shapes by size descending shapes.sort(function (a, b) { @@ -529,18 +539,15 @@ }; /** - * create handles for a shape. + * add adjustment handles to a shape. * - * Creates SVG elements for each screen point and append it to the SVG element. + * Creates a SVG element for each screen point and append them to the SVG element. * * @param data * @param shape - * @param svg The SVG element where to append handle elements - * @param func If present, use a special create function + * @param layer */ - //create handles for a shape. - var createHandles = function (data, shape, layer) { - if (!shape.properties.editable) { return }; + var addEditHandles = function (data, shape, layer) { var $svg = $(layer.svgElem); var trafo = data.imgTrafo; // type of handle can be stated in layer @@ -570,6 +577,22 @@ }; /** + * remove SVG adjustment handles from a shape. + * + * @param data + * @param shape + */ + var removeEditHandles = function (data, shape) { + // remove vertex handles + if (shape.$vertexElems != null) { + for (var i = 0; i < shape.$vertexElems.length; ++i) { + shape.$vertexElems[i].remove(); + } + delete shape.$vertexElems; + } + }; + + /** * calculate screen positions from coordinates for a shape. * * @param data @@ -581,6 +604,9 @@ var screenpos = $.map(coords, function (coord) { return trafo.transform(geom.position(coord)); }); + if (shape.properties == null) { + shape.properties = {}; + } shape.properties.screenpos = screenpos; return screenpos; }; @@ -599,7 +625,7 @@ xmin = (x < xmin) ? x : xmin; xmax = (x > xmax) ? x : xmax; ymin = (y < ymin) ? y : ymin; - ymax = (y > ymax) ? y : ymax; + ymax = (y > ymax) ? y : ymax; } return geom.rectangle(xmin, ymin, xmax-xmin, ymax-ymin); }; @@ -633,7 +659,9 @@ $elem.place(); // render the SVG $(layer.svgElem).append($elem); - createHandles(data, shape, layer); + if (shape.properties.editable) { + addEditHandles(data, shape, layer); + } $(data).trigger("renderShape", shape); }; @@ -646,13 +674,7 @@ * @param shape */ var unrenderShape = function (data, shape) { - // remove vertex handles - if (shape.$vertexElems != null) { - for (var i = 0; i < shape.$vertexElems.length; ++i) { - shape.$vertexElems[i].remove(); - } - delete shape.$vertexElems; - } + removeEditHandles(data, shape); // remove SVG element if (shape.$elem != null) { shape.$elem.remove(); @@ -767,10 +789,6 @@ * @onComplete function (data, shape) */ var defineShape = function (data, shape, layer, onComplete) { - if (layer == null) { - // assume shape layer is 0 - layer = data.vectorLayers[0]; - } var shapeType = shape.geometry.type; // call setup to make sure maxvtx is set data.shapeFactory[shapeType].setup(data, shape);