<template> <v-group> <v-polygon :polygon="writablePolygon" :closed="true" :color="color" :draggable="true" :highlight-id="highlightId" :max-height="maxHeight" :max-width="maxWidth" :scale="scale" @click="$emit('click-polygon', writablePolygon)" @dragstart="onDragStart" @dragend="onDragEnd" /> <v-circle ref="anchorRef" :config="{ x: -10, y: -10, radius: 5, fill: 'white', stroke: 'black', scaleX: 1 / (scale || 1), scaleY: 1 / (scale || 1) }" /> <template v-if="isSelected && !isMoving"> <v-line v-for="(lineSegment, insertIndex) in writablePolygon.lineSegments" :key="insertIndex" :config="{ draggable: false, hitStrokeWidth: 10, lineJoin: 'round', opacity: 1, points: lineSegment.points, stroke: 'transparent', strokeWidth: 5, strokeScaleEnabled: false }" @mousemove="onMouseMoveLine($event, lineSegment)" @mouseleave="hideAnchorPoint" @click="handleClickLine($event, writablePolygon, insertIndex + 1)" /> <v-point v-for="(point, index) in writablePolygon.toPoints()" :key="`${writablePolygon.id}-${index}`" :color="index === selectedPoint ? color : 'white'" :point="point" :index="index" :max-width="maxWidth" :max-height="maxHeight" :scale="scale" @click="$emit('click-point', index)" @dragstart="hideAnchorPoint" @dragmove="handleDragMovePoint" @dragend="handleDragEndPoint" @dblclick="handleDoubleClickPoint" /> </template> </v-group> </template> <script lang="ts"> import Vue from 'vue' import Konva from 'konva' import Flatten from '@flatten-js/core' import Polygon from '@/domain/models/tasks/segmentation/Polygon' import LineSegment from '@/domain/models/tasks/segmentation/LineSegment' import { transform } from '@/domain/models/tasks/shared/Scaler' import VPolygon from './VPolygon.vue' import VPoint from './VPoint.vue' import Point = Flatten.Point export default Vue.extend({ components: { VPolygon, VPoint }, props: { polygon: { type: Polygon, required: true }, color: { type: String, default: '#00FF00' }, maxWidth: { type: Number, default: 0 }, maxHeight: { type: Number, default: 0 }, scale: { type: Number, default: 1 }, highlightId: { type: String, default: '' }, isSelected: { type: Boolean, default: false }, selectedPoint: { type: Number, default: -1 } }, data() { return { isMoving: false, writablePolygon: this.polygon } }, computed: { anchor() { return (this.$refs.anchorRef as Konva.ShapeConfig).getNode() } }, watch: { polygon: { handler(newPolygon: Polygon) { this.writablePolygon = newPolygon }, immediate: true, deep: true } }, methods: { onDragStart() { this.isMoving = true }, onDragEnd(polygon: Polygon, dx: number, dy: number) { this.isMoving = false this.$emit('drag-end-polygon', polygon, dx, dy) }, handleDragMovePoint(index: number, x: number, y: number) { this.writablePolygon.movePoint(index, x, y) this.writablePolygon = this.writablePolygon.clone() }, handleDragEndPoint(index: number, x: number, y: number) { this.$emit('drag-end-point', this.polygon, index, x, y) }, handleDoubleClickPoint(index: number) { this.$emit('double-click-point', this.polygon, index) }, onMouseMoveLine(e: Konva.KonvaEventObject<MouseEvent>, lineSegment: LineSegment) { const { offsetX, offsetY } = e.evt const { x: stageX = 0, y: stageY = 0 } = e.target.getStage()!.attrs const x = transform(offsetX, stageX, this.scale) const y = transform(offsetY, stageY, this.scale) const point = new Point(x, y) const closestPoint = lineSegment.getClosestPoint(point) this.showAnchorPoint(closestPoint.x, closestPoint.y) }, handleClickLine(e: Konva.KonvaEventObject<MouseEvent>, polygon: Polygon, index: number) { const { offsetX, offsetY } = e.evt const { x: stageX = 0, y: stageY = 0 } = e.target.getStage()!.attrs const x = transform(offsetX, stageX, this.scale) const y = transform(offsetY, stageY, this.scale) this.hideAnchorPoint() this.$emit('click-line', polygon, index, x, y) }, showAnchorPoint(x: number, y: number) { this.anchor.to({ x, y, duration: 0 }) this.anchor.show() }, hideAnchorPoint() { this.anchor.to({ x: -10, y: -10, duration: 0 }) this.anchor.hide() } } }) </script>