import { getParent, types } from "mobx-state-tree";
|
import { isDefined } from "../../utils/utilities";
|
|
export const Anchor = types
|
.model({
|
regionId: types.maybe(types.string),
|
controlName: types.maybe(types.string),
|
})
|
.views((self) => ({
|
get comment() {
|
return getParent(self);
|
},
|
get annotation() {
|
return self.comment.annotation;
|
},
|
get region() {
|
return self.annotation.regions.find((r) => r.cleanId === self.regionId);
|
},
|
get result() {
|
// @todo we might link global classifications via region id only in a future
|
// @todo so then we have to check for `region.classification === true`
|
if (!self.controlName) return null;
|
// if we just removed the region
|
if (!self.region) return null;
|
return self.region.results.find((r) => r.from_name.name === self.controlName);
|
},
|
/**
|
* This will be provided to CommentsOverlay to observe changes in bbox coordinates and sizes
|
*
|
* @return {Object} The overlays-applicable node of the anchor.
|
*/
|
get overlayNode() {
|
const { result, region } = self;
|
if (self.comment.isResolved || self.comment.isDeleted) return null;
|
if (!region || region.hidden) return null;
|
const isOnCurrentItem = (region.item_index ?? 0) === (region.object.currentItemIndex ?? 0);
|
if (!isOnCurrentItem) return null;
|
|
if (result) {
|
const controlTag = result.from_name;
|
// Most probably, it's always true as we should work only with classification results for now.
|
// If this is not the case, then at the time of writing this comment,
|
// we assume that we have no way of displaying anything related to the overlay for this result.
|
const isClassification = controlTag.isClassificationTag;
|
// Taking into account `visiblewhen`
|
const isVisible = controlTag.isVisible !== false;
|
// The result that is displayed at the control tag right now
|
const currentResult = controlTag.result;
|
// It'll always be true for perObject mode,
|
// and for perRegion/perItem it'll be true only if the result is already displayed at the control tag
|
// (related region/item are selected)
|
const isCurrentResult = currentResult === result;
|
const isDisplayedAtControlTag = isClassification && isVisible && isCurrentResult;
|
if (isDisplayedAtControlTag) {
|
return result;
|
}
|
}
|
|
// if a result does not exist,
|
// or it's hidden, we still need to indicate comment existence on its region if it's possible
|
return self.region;
|
},
|
/**
|
* A key that should be unique in the context of the current annotation and current moment
|
* based on the target of Anchor.
|
* It allows distinguishing Anchors by their target (basically by area on the screen to which it was attached)
|
* and groups Anchors with the same target.
|
* Right now it is used to display only one comment per area on the screen.
|
*
|
* @return {string} A key which points to a unique Anchor's target.
|
*/
|
get targetKey() {
|
const parts = [self.regionId];
|
if (isDefined(self.controlName)) {
|
parts.push(self.controlName);
|
}
|
return parts.join("-");
|
},
|
}))
|
.actions((self) => ({
|
serialize() {
|
const { id, ...result } = self.toJSON();
|
return result;
|
},
|
setRegion(region) {
|
self.regionId = region.cleanId;
|
},
|
}));
|