From 3f4ece70c16438085a3addd4b4ff793fa6dfd8af Mon Sep 17 00:00:00 2001 From: nanli-emory Date: Fri, 5 Apr 2024 17:00:27 -0400 Subject: [PATCH] add drawing circle and ellipse annotations --- apps/mini/uicallbacks.js | 3 +- apps/viewer/uicallbacks.js | 3 +- common/DrawHelper.js | 67 ++++++++++++------- common/util.js | 11 ++- .../openseadragon-overlays-manage.js | 12 ++++ 5 files changed, 70 insertions(+), 26 deletions(-) diff --git a/apps/mini/uicallbacks.js b/apps/mini/uicallbacks.js index e24265d19..c1ba9bb08 100644 --- a/apps/mini/uicallbacks.js +++ b/apps/mini/uicallbacks.js @@ -1359,7 +1359,8 @@ function locationCallback(layerData) { return; } // locate annotation 3.0 - if (item.data.geometries.features[0].geometry.type == 'Point') { + const geoType = item.data.geometries.features[0].geometry.type + if (geoType == 'Point'||geoType == 'Circle'||geoType == 'Ellipse') { const bound = item.data.geometries.features[0].bound.coordinates; const center = $CAMIC.viewer.viewport.imageToViewportCoordinates( bound[0], diff --git a/apps/viewer/uicallbacks.js b/apps/viewer/uicallbacks.js index 8f2015fd0..c06970d6d 100644 --- a/apps/viewer/uicallbacks.js +++ b/apps/viewer/uicallbacks.js @@ -1547,7 +1547,8 @@ function locationCallback(layerData) { return; } // locate annotation 3.0 - if (item.data.geometries.features[0].geometry.type == 'Point') { + const geoType = item.data.geometries.features[0].geometry.type + if (geoType == 'Point'||geoType == 'Circle'||geoType == 'Ellipse') { const bound = item.data.geometries.features[0].bound.coordinates; const center = $CAMIC.viewer.viewport.imageToViewportCoordinates( bound[0], diff --git a/common/DrawHelper.js b/common/DrawHelper.js index 027d3969b..977a93a59 100644 --- a/common/DrawHelper.js +++ b/common/DrawHelper.js @@ -82,7 +82,9 @@ caDrawHelper.prototype.drawMultiline = function(ctx,array){ this.drawLine(ctx,array[i-1],array[i]); } } -caDrawHelper.prototype.circle = function(ctx, point, radius){ +caDrawHelper.prototype.circle = function(ctx, point, radius, isPoint=true){ + + const path = new Path(); path.arc( point[0], @@ -90,11 +92,32 @@ caDrawHelper.prototype.circle = function(ctx, point, radius){ radius, 0, 2 * Math.PI ); path.closePath(); - path.strokeAndFill(ctx); - //path.stroke(ctx); + if(isPoint) { + path.strokeAndFill(ctx); + } else { + path.stroke(ctx); + } // return points and path return path; } +caDrawHelper.prototype.ellipse = function(ctx, point, radius, rotation){ + const path = new Path(); + path.ellipse( + point[0], + point[1], + radius[0], + radius[1], + rotation * Math.PI, + 0, + 2 * Math.PI + ); + path.closePath(); + // path.strokeAndFill(ctx); + path.stroke(ctx); + // return points and path + return path; +} + caDrawHelper.prototype.drawMultiGrid = function(ctx, points, size){ const path = new Path(); points.forEach(p=>{ @@ -125,25 +148,6 @@ caDrawHelper.prototype.drawLine = function(ctx, start, end){ ctx.stroke(); } -/** - * draw a circle - * @param {CanvasRenderingContext2D} ctx - * is used for drawing rectangles, text, images and other objects onto the canvas element - * @param {Number} cx - * The x-coordinate of the center of the circle - * @param {Number} xy - * The x-coordinate of the center of the circle - * @param {Number} r - * The radius of the circle - */ -caDrawHelper.prototype.drawCircle = function(ctx, cx, cy, r){ - // draw line - ctx.beginPath(); - ctx.arc(cx, cy, r, 0, 2 * Math.PI); - ctx.stroke(); - ctx.closePath() - -} /** * draw a polygon on a canvas * @param {CanvasRenderingContext2D} ctx @@ -221,8 +225,25 @@ caDrawHelper.prototype.draw = function(ctx, image_data){ && !this.isPointInBBox(ctx.viewBoundBoxInData, {x:point[0],y:point[1]})) continue; ctx.fillStyle = (ctx.isFill ==undefined || ctx.isFill)?hexToRgbA(style.color,1):style.color; + console.log(this) polygon.geometry.path = this.circle(ctx, polygon.geometry.coordinates, ctx.radius); - }else if(false){ + } + else if(polygon.geometry.type=='Circle') { + const point = polygon.geometry.coordinates + if(ctx.viewBoundBoxInData + && !this.isPointInBBox(ctx.viewBoundBoxInData, {x:point[0],y:point[1]})) continue; + + ctx.fillStyle = (ctx.isFill ==undefined || ctx.isFill)?hexToRgbA(style.color,1):style.color; + polygon.geometry.path = this.circle(ctx, polygon.geometry.coordinates, polygon.geometry.radius, false); + }else if(polygon.geometry.type=='Ellipse'){ + const point = polygon.geometry.coordinates + if(ctx.viewBoundBoxInData + && !this.isPointInBBox(ctx.viewBoundBoxInData, {x:point[0],y:point[1]})) continue; + + ctx.fillStyle = (ctx.isFill ==undefined || ctx.isFill)?hexToRgbA(style.color,1):style.color; + polygon.geometry.path = this.ellipse(ctx, polygon.geometry.coordinates, polygon.geometry.radius, polygon.geometry.rotation); + } + else if(false){ }else{ // determine drawing or not diff --git a/common/util.js b/common/util.js index c695c5af0..aae1477e4 100644 --- a/common/util.js +++ b/common/util.js @@ -405,13 +405,22 @@ function VieweportFeaturesToImageFeatures(viewer, geometries) { this.imgHeight = image.source.dimensions.y; geometries.features = geometries.features.map((feature) => { - if (feature.geometry.type=='Point') { + if (feature.geometry.type=='Point'||feature.geometry.type=='Circle'||feature.geometry.type=='Ellipse') { feature.geometry.coordinates = [ Math.round(feature.geometry.coordinates[0] * imgWidth), Math.round(feature.geometry.coordinates[1] * imgHeight)]; feature.bound.coordinates =[ Math.round(feature.bound.coordinates[0] * imgWidth), Math.round(feature.bound.coordinates[1] * imgHeight)]; + + + + if (feature.geometry.type=='Circle') { + feature.geometry.radius = Math.round(feature.geometry.radius * imgWidth) + } + if (feature.geometry.type=='Ellipse') { + feature.geometry.radius = [Math.round(feature.geometry.radius[0] * imgWidth), Math.round(feature.geometry.radius[1] * imgHeight)]; + } return feature; } feature.geometry.coordinates[0] = feature.geometry.coordinates[0].map( diff --git a/core/extension/openseadragon-overlays-manage.js b/core/extension/openseadragon-overlays-manage.js index 6116e7d9b..889cb4400 100644 --- a/core/extension/openseadragon-overlays-manage.js +++ b/core/extension/openseadragon-overlays-manage.js @@ -383,6 +383,12 @@ pointPath.closePath(); pointPath.strokeAndFill(ctx); this.editPointPathList.push(pointPath); + } else if (this.editPathData.geometry.type === 'Circle') { + // TODO editor + console.log('drawEditPoints Circle'); + } else if (this.editPathData.geometry.type === 'Ellipse') { + // TODO editor + console.log('drawEditPoints Ellipse'); } else { pathData[0].map((point) => { const pointPath = new Path(); @@ -497,6 +503,12 @@ pointPath.closePath(); pointPath.strokeAndFill(this._edit_tool_ctx_); this.editPointPathList.push(pointPath); + } else if (this.editPathData.geometry.type === 'Circle') { + // TODO editor + console.log('onEditPointMouseMove Circle'); + } else if (this.editPathData.geometry.type === 'Ellipse') { + // TODO editor + console.log('onEditPointMouseMove Ellipse'); } else { // brush this.editPathData.geometry.coordinates[0][this.onEditIndex] = [img_point.x, img_point.y];