label-studio
Version:
Data Labeling Tool that is backend agnostic and can be embedded into your applications
243 lines (197 loc) • 5.7 kB
JavaScript
import React from "react";
import { Rect, Circle } from "react-konva";
import { observer } from "mobx-react";
import { types, getParent, getRoot } from "mobx-state-tree";
import { guidGenerator } from "../core/Helpers";
const PolygonPoint = types
.model("PolygonPoint", {
id: types.identifier,
relativeX: types.optional(types.number, 0),
relativeY: types.optional(types.number, 0),
init_x: types.optional(types.number, 0),
init_y: types.optional(types.number, 0),
x: types.number,
y: types.number,
index: types.number,
selected: types.optional(types.boolean, false),
style: types.string,
size: types.string,
})
.views(self => ({
get parent() {
return getParent(self, 2);
},
get completion() {
return getRoot(self).completionStore.selected;
},
}))
.actions(self => ({
/**
* Triggered after create model
*/
afterCreate() {
self.init_x = self.x;
self.init_y = self.y;
if (self.parent.coordstype === "perc") {
self.relativeX = self.x;
self.relativeY = self.y;
} else {
self.relativeX = (self.x / self.parent.parent.stageWidth) * 100;
self.relativeY = (self.y / self.parent.parent.stageHeight) * 100;
}
},
/**
* External function for Polygon Parent
* @param {number} x
* @param {number} y
*/
movePoint(offsetX, offsetY) {
self.init_x = self.init_x + offsetX;
self.init_y = self.init_y + offsetY;
self.x = self.x + offsetX;
self.y = self.y + offsetY;
self.relativeX = (self.x / self.parent.parent.stageWidth) * 100;
self.relativeY = (self.y / self.parent.parent.stageHeight) * 100;
},
_movePoint(x, y) {
self.init_x = x;
self.init_y = y;
self.relativeX = (x / self.parent.parent.stageWidth) * 100;
self.relativeY = (y / self.parent.parent.stageHeight) * 100;
self.x = x;
self.y = y;
},
/**
* Close polygon
* @param {*} ev
*/
closeStartPoint(ev) {
if (!self.completion.edittable) return;
if (self.parent.mouseOverStartPoint) {
self.parent.closePoly();
}
},
handleMouseOverStartPoint(ev) {
const stage = self.parent.parent.stageRef;
stage.container().style.cursor = "crosshair";
/**
* Check if polygon > 2 points and closed point
*/
if (self.parent.closed || self.parent.points.length < 3) return;
const startPoint = ev.target;
if (self.style === "rectangle") {
startPoint.setX(startPoint.x() - startPoint.width() / 2);
startPoint.setY(startPoint.y() - startPoint.height() / 2);
}
const scaleMap = {
small: 2,
medium: 3,
large: 4,
};
const scale = scaleMap[self.size];
startPoint.scale({ x: scale, y: scale });
self.parent.setMouseOverStartPoint(true);
},
handleMouseOutStartPoint(ev) {
const t = ev.target;
const stage = self.parent.parent.stageRef;
stage.container().style.cursor = "default";
if (self.style === "rectangle") {
t.setX(t.x() + t.width() / 2);
t.setY(t.y() + t.height() / 2);
}
t.scale({ x: 1, y: 1 });
self.parent.setMouseOverStartPoint(false);
},
}));
const PolygonPointView = observer(({ item, name }) => {
const sizes = {
small: 4,
medium: 8,
large: 12,
};
const stroke = {
small: 1,
medium: 2,
large: 3,
};
const w = sizes[item.size];
const startPointAttr =
item.index === 0
? {
hitStrokeWidth: 12,
fill: item.parent.strokecolor ? item.parent.strokecolor : item.primary,
onMouseOver: item.handleMouseOverStartPoint,
onMouseOut: item.handleMouseOutStartPoint,
onClick: item.closeStartPoint,
}
: null;
const dragOpts = {
onDragMove: e => {
let { x, y } = e.target.attrs;
if (x < 0) x = 0;
if (y < 0) y = 0;
if (x > item.parent.parent.stageWidth) x = item.parent.parent.stageWidth;
if (y > item.parent.parent.stageHeight) y = item.parent.parent.stageHeight;
item._movePoint(x, y);
},
onDragEnd: e => {
e.cancelBubble = true;
},
onMouseOver: e => {
const stage = item.parent.parent.stageRef;
stage.container().style.cursor = "crosshair";
},
onMouseOut: e => {
const stage = item.parent.parent.stageRef;
stage.container().style.cursor = "default";
},
};
const fill = item.selected ? "green" : "white";
if (item.style === "circle") {
return (
<Circle
key={name}
name={name}
x={item.x}
y={item.y}
radius={w}
fill={fill}
stroke="black"
strokeWidth={stroke[item.size]}
dragOnTop={false}
onClick={ev => {
if (item.parent.mouseOverStartPoint) {
item.parent.closePoly();
} else {
// ev.evt.preventDefault();
// ev.cancelBubble = true;
item.parent.setSelectedPoint(item);
}
}}
{...dragOpts}
{...startPointAttr}
draggable={item.completion.edittable}
/>
);
} else {
return (
<Rect
name={name}
key={name}
x={item.x - w / 2}
y={item.y - w / 2}
width={w}
height={w}
fill={fill}
stroke="black"
strokeWidth={stroke[item.size]}
dragOnTop={false}
{...dragOpts}
{...startPointAttr}
draggable={item.completion.edittable}
/>
);
}
});
export { PolygonPoint, PolygonPointView };