| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- import { useState } from "react";
- import { Circle, Rect } from "react-konva";
- import { observer } from "mobx-react";
- import { getParent, hasParent, types } from "mobx-state-tree";
- import { guidGenerator } from "../core/Helpers";
- import { useRegionStyles } from "../hooks/useRegionColor";
- import { AnnotationMixin } from "../mixins/AnnotationMixin";
- const PolygonPointModel = types
- .model("PolygonPoint", {
- id: types.optional(types.identifier, guidGenerator),
- x: types.number,
- y: types.number,
- index: types.number,
- style: "circle",
- size: "small",
- })
- .volatile(() => ({
- selected: false,
- }))
- .views((self) => ({
- get parent() {
- if (!hasParent(self, 2)) return null;
- return getParent(self, 2);
- },
- get stage() {
- return self.parent?.parent;
- },
- get canvasX() {
- return self.stage?.internalToCanvasX(self.x);
- },
- get canvasY() {
- return self.stage?.internalToCanvasY(self.y);
- },
- }))
- .actions((self) => ({
- /**
- * External function for Polygon Parent
- * @param {number} x
- * @param {number} y
- */
- movePoint(offsetX, offsetY) {
- const dx = self.stage.canvasToInternalX(offsetX);
- const dy = self.stage.canvasToInternalY(offsetY);
- self.x = self.x + dx;
- self.y = self.y + dy;
- },
- _setPos(x, y) {
- self.x = x;
- self.y = y;
- },
- _movePoint(canvasX, canvasY) {
- const point = self.parent.control?.getSnappedPoint({
- x: self.stage.canvasToInternalX(canvasX),
- y: self.stage.canvasToInternalY(canvasY),
- });
- self._setPos(point.x, point.y);
- },
- /**
- * Close polygon
- * @param {*} ev
- */
- closeStartPoint() {
- if (self.annotation.isReadOnly()) return;
- if (self.parent.closed) return;
- if (self.parent.mouseOverStartPoint) {
- self.parent.closePoly();
- }
- },
- handleMouseOverStartPoint(ev) {
- ev.cancelBubble = true;
- const stage = self.stage?.stageRef;
- if (!stage) return;
- 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 / self.stage.zoomScale,
- y: scale / self.stage.zoomScale,
- });
- self.parent.setMouseOverStartPoint(true);
- },
- handleMouseOutStartPoint(ev) {
- const t = ev.target;
- const stage = self.stage?.stageRef;
- if (!stage) return;
- 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 / self.stage.zoomScale,
- y: 1 / self.stage.zoomScale,
- });
- self.parent.setMouseOverStartPoint(false);
- },
- getSkipInteractions() {
- return self.parent.control.obj.getSkipInteractions();
- },
- }));
- const PolygonPoint = types.compose("PolygonPoint", AnnotationMixin, PolygonPointModel);
- const PolygonPointView = observer(({ item, name }) => {
- if (!item.parent) return;
- const [draggable, setDraggable] = useState(true);
- const regionStyles = useRegionStyles(item.parent);
- 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: regionStyles.strokeColor || item.primary,
- onMouseOver: item.handleMouseOverStartPoint,
- onMouseOut: item.handleMouseOutStartPoint,
- }
- : null;
- const dragOpts = {
- onDragMove: (e) => {
- if (item.getSkipInteractions()) return false;
- if (e.target !== e.currentTarget) return;
- const shape = e.target;
- let { x, y } = shape.attrs;
- if (x < 0) x = 0;
- if (y < 0) y = 0;
- if (x > item.stage.stageWidth) x = item.stage.stageWidth;
- if (y > item.stage.stageHeight) y = item.stage.stageHeight;
- item._movePoint(x, y);
- shape.setAttr("x", item.canvasX);
- shape.setAttr("y", item.canvasY);
- },
- onDragStart: () => {
- if (item.getSkipInteractions()) {
- setDraggable(false);
- return false;
- }
- item.annotation.history.freeze();
- },
- onDragEnd: (e) => {
- setDraggable(true);
- item.annotation.history.unfreeze();
- e.cancelBubble = true;
- },
- onMouseOver: (e) => {
- e.cancelBubble = true;
- const stage = item.stage?.stageRef;
- if (!stage) return;
- stage.container().style.cursor = "crosshair";
- },
- onMouseOut: () => {
- const stage = item.stage?.stageRef;
- if (!stage) return;
- stage.container().style.cursor = "default";
- },
- onTransformEnd(e) {
- if (e.target !== e.currentTarget) return;
- const t = e.target;
- t.setAttr("x", 0);
- t.setAttr("y", 0);
- t.setAttr("scaleX", 1);
- t.setAttr("scaleY", 1);
- },
- };
- const fill = item.selected ? "green" : "white";
- if (item.style === "circle") {
- return (
- <Circle
- key={name}
- name={name}
- x={item.canvasX}
- y={item.canvasY}
- radius={w}
- fill={fill}
- stroke="black"
- strokeWidth={stroke[item.size]}
- dragOnTop={false}
- strokeScaleEnabled={false}
- perfectDrawEnabled={false}
- shadowForStrokeEnabled={false}
- scaleX={1 / (item.stage.zoomScale || 1)}
- scaleY={1 / (item.stage.zoomScale || 1)}
- onDblClick={() => {
- item.parent.deletePoint(item);
- }}
- onClick={(ev) => {
- if (ev.evt.altKey) return item.parent.deletePoint(item);
- if (item.parent.isDrawing && item.parent.points.length === 1) return;
- // don't unselect polygon on point click
- ev.evt.preventDefault();
- ev.cancelBubble = true;
- if (item.parent.mouseOverStartPoint) {
- item.closeStartPoint();
- item.parent.notifyDrawingFinished();
- } else {
- item.parent.setSelectedPoint(item);
- }
- }}
- {...dragOpts}
- {...startPointAttr}
- draggable={!item.parent.isReadOnly() && draggable}
- />
- );
- }
- 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]}
- strokeScaleEnabled={false}
- perfectDrawEnabled={false}
- shadowForStrokeEnabled={false}
- dragOnTop={false}
- {...dragOpts}
- {...startPointAttr}
- draggable={!item.parent.isReadOnly()}
- />
- );
- });
- export { PolygonPoint, PolygonPointView };
|