-
Notifications
You must be signed in to change notification settings - Fork 75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Edit annotations #769
Edit annotations #769
Conversation
Resolves #630. |
@manthey this will take some time to review but overall the feature is great! |
4d1fbac
to
22d9c9e
Compare
Now that all relevant previous PRs are merged to master, I've rebased this to resolve merge conflicts. |
22d9c9e
to
d8882ed
Compare
When enabled, hovering over an annotation will highlight it. Clicking on the annotation will place it in edit mode. Dragging the edit handles will alter the annotation. Escape or clicking outside of edit handles will exit from edit mode. This PR can stand on its own, but there are a number of future improvements that are desired: - escape should revert the edit rather than just exit edit mode (and enter should exit edit mode, keeping the edit) - tab should switch between annotations; when an annotation is selected via the enter key, tab would switch between edit handles. - edit handles should be adjustable with the arrow keys - meta keys (shift, ctrl) should affect how moving edit handles is controlled (for instance, shift might constrain a rectangle's aspect ratio, or ensure 90 degree rotations). I'm not sure of the specifics. - the edit handles should be fancier than just points. I'd rather see squares on the vertices, a curved double-headed arrow on the rotation handle, and a double-headed arrow on the resize handle. This would benefit from a more generic marker option for points. - we should test with a touch device. - for lines, the ability to break or join a line could be disabled. - There could be other constraints, too, like discrete rotations or scales.
d8882ed
to
5de0efd
Compare
@@ -127,7 +131,14 @@ var annotationLayer = function (args) { | |||
if (evt.state && evt.state.actionRecord && | |||
evt.state.actionRecord.owner === geo_annotation.actionOwner && | |||
m_this.currentAnnotation) { | |||
update = m_this.currentAnnotation.processAction(evt); | |||
switch (m_this.mode()) { | |||
case m_this.modes.edit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice and clean.. 👍
/** | ||
* Select or deselect an edit handle. | ||
* | ||
* @param {geo.event} evt The mouse move event. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this only applicable/callable when "The mouse move"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This gets called with the mouseon and mouseoff events. Those only occur on a mouse move or when the mouse move is retriggered. When we want to make sure touch devices are fully supported, we should trigger mouseon and mouseoff events (and mouseover and mouseout) before the touch causes a click (but that is an issue for another PR).
$.each(m_features[geo_annotation._editHandleFeatureLevel], function (type, feature) { | ||
feature.feature.modified(); | ||
}); | ||
m_this.currentAnnotation.selectEditHandle(evt.data, enable); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
curious...here we are passing enable as it is and 2 lines below we are converting into true boolean representation. I think I may know why but just double checking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of javascript handles truthy or falsy values they way you'd expect. However, jQuery's toggleClass does not, and must take either an actual boolean or a function that returns a boolean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, thanks good to know.
}, | ||
scaled: false, | ||
stroke: true, | ||
strokeColor: {r: 0, g: 0, b: 1}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would probably make the default color to orange. What you think @matthewma7 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aashish24 The current color works fine for me, because I used some yellow-orange color in the other project.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay great lets keep the default to blue then thanks @matthewma7
src/annotation.js
Outdated
maxr2 = Math.max(maxr2, Math.pow(pos.x - dispCenter.x, 2) + Math.pow(pos.y - dispCenter.y, 2)); | ||
} | ||
r = Math.sqrt(maxr2) + offset; | ||
pos = map.displayToGcs({x: dispCenter.x + r * Math.cos(rotation), y: dispCenter.y - r * Math.sin(rotation)}, null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
long line?
src/annotation.js
Outdated
y: handle.resizePosition.y + delta.y | ||
}, null), | ||
d01 = Math.pow(Math.pow(p1.y - p0.y, 2) + Math.pow(p1.x - p0.x, 2), 0.5) - handle.handle.style.resizeHandleOffset, | ||
d02 = Math.pow(Math.pow(p2.y - p0.y, 2) + Math.pow(p2.x - p0.x, 2), 0.5) - handle.handle.style.resizeHandleOffset, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrap these long lines?
src/annotation.js
Outdated
* edits from collapsing immediately. */ | ||
} else if (layer.displayDistance(curPts[index], null, curPts[(index + 1) % curPts.length], null) <= aPP) { | ||
near = (index + 1) % curPts.length; | ||
} else if (layer.displayDistance(curPts[index], null, curPts[(index + curPts.length - 1) % curPts.length], null) <= aPP) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here..wrap?
* Process any edit actions for this annotation. | ||
* | ||
* @param {geo.event} evt The action event. | ||
* @returns {boolean|string} `true` to update the annotation, falsy to not |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'true' --> Truthy to update the annotation? To keep it consistent with other docs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On return values, we can be specific -- it does output true
, not just an arbitrary truthy value. On input parameters we try to be flexible and accept any truthy value.
@@ -15,7 +15,8 @@ var geo_action = { | |||
// annotation actions | |||
annotation_line: 'geo_annotation_line', | |||
annotation_polygon: 'geo_annotation_polygon', | |||
annotation_rectangle: 'geo_annotation_rectangle' | |||
annotation_rectangle: 'geo_annotation_rectangle', | |||
annotation_edit_handle: 'geo_annotation_edit_handle' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we just call it annotation_edit? or would that be confusing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may eventually want other edit actions. For instance, suppose we supported an action on selecting the annotation in edit mode, then it might be edit_select
to differentiate it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly looks great to me, just looking at the annotation.js more closely, has some minor comments / questions / suggestions. Overall this is looking great, I am also trying to build it locally to try it out.
@manthey @matthewma7 this is looking very good. Some points for discussions / future work may be (I am interesting in hearing your thoughts on it):
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍 with some comments left for discussions for future PR/work perhaps.
}, | ||
scaled: false, | ||
stroke: true, | ||
strokeColor: {r: 0, g: 0, b: 1}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay great lets keep the default to blue then thanks @matthewma7
src/annotation.js
Outdated
var editPoints, | ||
style = $.extend({}, defaultEditHandleStyle, m_this.editHandleStyle()), | ||
handles = util.ensureFunction(style.handles)() || {}, | ||
selected = m_this._editHandle && m_this._editHandle.handle && m_this._editHandle.handle.selected ? m_this._editHandle.handle : undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrap this line?
y: evt.mouse.mapgcs.y - evt.state.origin.mapgcs.y | ||
}, | ||
curPts = m_this._coordinates(); | ||
var pts = start.map(function (elem) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice +1
* @returns {boolean|string} `true` to update the annotation, falsy to not | ||
* update anything. | ||
*/ | ||
this._processEditActionRotate = function (evt) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice +1
@aashish24, in response to your numbered list:
|
@manthey for
|
When enabled, hovering over an annotation will highlight it. Clicking on the annotation will place it in edit mode. Dragging the edit handles will alter the annotation. Escape or clicking outside of edit handles will exit from edit mode.
This PR can stand on its own, but there are a number of future improvements that are desired: