97 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			97 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
'use client'
 | 
						|
 | 
						|
import React, { useState } from 'react'
 | 
						|
import Konva from 'konva'
 | 
						|
import { Group, Rect } from 'react-konva'
 | 
						|
import { KonvaEventObject } from 'konva/lib/Node'
 | 
						|
import { entities } from '../../wailsjs/wailsjs/go/models'
 | 
						|
import { useProject } from '../../context/Project/provider'
 | 
						|
import AreaContextMenu from './AreaContextMenu'
 | 
						|
import { useStage } from './context/provider'
 | 
						|
 | 
						|
type Props = {
 | 
						|
  isActive: boolean,
 | 
						|
  area: entities.Area,
 | 
						|
  setHoveredOverAreaIds: Function
 | 
						|
  setHoveredProcessedArea: Function
 | 
						|
}
 | 
						|
 | 
						|
type coordinates = { x: number, y: number }
 | 
						|
 | 
						|
const Area = (props: Props) => {
 | 
						|
  const { getProcessedAreaById, selectedAreaId, setSelectedAreaId } = useProject()
 | 
						|
  const { scale } = useStage()
 | 
						|
  const shapeRef = React.useRef<Konva.Rect>(null)
 | 
						|
  const [isAreaContextMenuOpen, setIsAreaContextMenuOpen] = useState(false)
 | 
						|
  const [areaContextMenuPosition, setAreaContextMenuPosition] = useState<coordinates>()
 | 
						|
 | 
						|
  const { area, isActive, setHoveredOverAreaIds, setHoveredProcessedArea } = props
 | 
						|
  const a = area
 | 
						|
  const width = (a.endX - a.startX)
 | 
						|
  const height = (a.endY - a.startY)
 | 
						|
 | 
						|
  const handleEnterOrLeave = (e: KonvaEventObject<MouseEvent>) => {
 | 
						|
    const stage = e.currentTarget.getStage()!
 | 
						|
    const currentMousePosition = stage.pointerPos
 | 
						|
    const intersectingNodes = stage.getAllIntersections(currentMousePosition)
 | 
						|
    const drawnAreas = intersectingNodes.filter(n => n.attrs?.isArea)
 | 
						|
    const drawnAreasIds = drawnAreas.map(d => d.attrs?.id)
 | 
						|
    setHoveredOverAreaIds(drawnAreasIds)
 | 
						|
 | 
						|
    const processedAreaRequests = drawnAreasIds.map(a => getProcessedAreaById(a || ''))
 | 
						|
    Promise.all(processedAreaRequests).then(responses => {
 | 
						|
      const validResponses = responses.filter(r => r?.id) as entities.ProcessedArea[]
 | 
						|
      setHoveredProcessedArea(validResponses || [])
 | 
						|
    })
 | 
						|
  }
 | 
						|
 | 
						|
  const handleContextMenu = (e: KonvaEventObject<PointerEvent>) => {
 | 
						|
    e.evt.preventDefault()
 | 
						|
    const stage = e.currentTarget.getStage()
 | 
						|
    const pointerPosition = stage?.getRelativePointerPosition()
 | 
						|
    if (!pointerPosition) return
 | 
						|
 | 
						|
    const x = pointerPosition.x + 4
 | 
						|
    const y = pointerPosition.y + 4
 | 
						|
    setAreaContextMenuPosition({ x, y })
 | 
						|
    setIsAreaContextMenuOpen(true)
 | 
						|
  }
 | 
						|
 | 
						|
  const handleAreaClick = (areaId: string) => {
 | 
						|
    if (areaId === selectedAreaId) setSelectedAreaId('')
 | 
						|
    else setSelectedAreaId(areaId)
 | 
						|
  }
 | 
						|
 | 
						|
  return <Group>
 | 
						|
    <Rect
 | 
						|
      ref={shapeRef}
 | 
						|
      id={a.id}
 | 
						|
      width={width}
 | 
						|
      height={height}
 | 
						|
      x={a.startX * scale}
 | 
						|
      y={a.startY * scale}
 | 
						|
      scale={{ x: scale, y: scale }}
 | 
						|
      strokeEnabled
 | 
						|
      stroke={isActive ? '#dc8dec' : '#1e1e1e'}
 | 
						|
      strokeWidth={1}
 | 
						|
      strokeScaleEnabled={false}
 | 
						|
      shadowForStrokeEnabled={false}
 | 
						|
      onMouseEnter={handleEnterOrLeave}
 | 
						|
      onMouseLeave={handleEnterOrLeave}
 | 
						|
      onClick={() => handleAreaClick(a.id)}
 | 
						|
      onContextMenu={handleContextMenu}
 | 
						|
      isArea
 | 
						|
    />
 | 
						|
    {isAreaContextMenuOpen
 | 
						|
      ? <AreaContextMenu
 | 
						|
        area={area}
 | 
						|
        x={areaContextMenuPosition?.x || 0}
 | 
						|
        y={areaContextMenuPosition?.y || 0}
 | 
						|
        scale={scale}
 | 
						|
        setIsAreaContextMenuOpen={setIsAreaContextMenuOpen} />
 | 
						|
      : <></>
 | 
						|
    }
 | 
						|
  </Group>
 | 
						|
}
 | 
						|
 | 
						|
export default Area |