123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- import React, { useEffect, useState } from 'react';
- import theme from '../../helpers/theme';
- import useCursorPosition from '../../hooks/useCursorPosition';
- import { getAbsoluteCoordinate } from '../../helpers/position';
- import { calcDragAndDropScale } from '../../helpers/utility';
- import generateCirclesData from './data';
- import { SVG, Rect, Circle } from './styled';
- type Props = {
- left: number;
- top: number;
- width: number;
- height: number;
- onMove?: (moveCoord: CoordType) => void;
- onScale?: (scaleCoord: CoordType) => void;
- onClick?: (event: React.MouseEvent) => void;
- onDoubleClick?: () => void;
- };
- type ObjPositionType = {
- top: number;
- left: number;
- width: number;
- height: number;
- operator: string;
- clickX: number;
- clickY: number;
- };
- const initState = {
- top: 0,
- left: 0,
- width: 0,
- height: 0,
- operator: '',
- clickX: 0,
- clickY: 0,
- };
- const index: React.FC<Props> = ({
- left,
- top,
- width,
- height,
- onMove,
- onScale,
- onClick,
- onDoubleClick,
- }: Props) => {
- const data = generateCirclesData(width, height);
- const [state, setState] = useState(initState);
- const [cursorPosition, setRef] = useCursorPosition(25);
- const handleMouseDown = (e: React.MouseEvent | React.TouchEvent): void => {
- e.preventDefault();
- const operatorId = (e.target as HTMLElement).getAttribute(
- 'data-id',
- ) as string;
- const coord = getAbsoluteCoordinate(document.body, e);
- setRef(document.body);
- setState({
- top,
- left,
- width,
- height,
- operator: operatorId,
- clickX: coord.x,
- clickY: coord.y,
- });
- };
- const handleMouseUp = (): void => {
- setRef(null);
- setState(initState);
- };
- const calcMoveResult = (
- currentPosition: PointType,
- startPosition: PointType,
- objPosition: ObjPositionType,
- ): CoordType => ({
- left: currentPosition.x - (startPosition.x - objPosition.left),
- top: currentPosition.y - (startPosition.y - objPosition.top),
- });
- const calcScaleResult = (
- currentPosition: PointType,
- objPosition: ObjPositionType,
- ): CoordType => {
- const scaleData = calcDragAndDropScale({
- ...objPosition,
- moveX: currentPosition.x || 0,
- moveY: currentPosition.y || 0,
- });
- const scaleWidth = scaleData.width || 0;
- const scaleHeight = scaleData.height || 0;
- const maxTop = objPosition.top + objPosition.height;
- const maxLeft = objPosition.left + objPosition.width;
- scaleData.left = scaleData.left > maxLeft ? maxLeft : scaleData.left;
- scaleData.top = scaleData.top > maxTop ? maxTop : scaleData.top;
- scaleData.width = scaleWidth > 0 ? scaleWidth : 0;
- scaleData.height = scaleHeight > 0 ? scaleHeight : 0;
- return scaleData;
- };
- useEffect(() => {
- if (cursorPosition.x && cursorPosition.y && state.clickX) {
- if (state.operator === 'move' && onMove) {
- onMove(
- calcMoveResult(
- { x: cursorPosition.x, y: cursorPosition.y },
- { x: state.clickX, y: state.clickY },
- state,
- ),
- );
- } else if (onScale) {
- onScale(
- calcScaleResult(
- {
- x: cursorPosition.x,
- y: cursorPosition.y,
- },
- state,
- ),
- );
- }
- }
- }, [cursorPosition, state]);
- useEffect(() => {
- window.addEventListener('mouseup', handleMouseUp);
- window.addEventListener('touchend', handleMouseUp);
- return (): void => {
- window.removeEventListener('mouseup', handleMouseUp);
- window.removeEventListener('touchend', handleMouseUp);
- };
- }, []);
- return (
- <SVG
- style={{
- left: `${left - 12}px`,
- top: `${top - 12}px`,
- width: `${width + 24}px`,
- height: `${height + 24}px`,
- }}
- onClick={onClick}
- onDoubleClick={onDoubleClick}
- >
- <Rect
- x={6}
- y={6}
- width={width + 12}
- height={height + 12}
- stroke={onScale ? theme.colors.primary : 'transparency'}
- onMouseDown={handleMouseDown}
- onTouchStart={handleMouseDown}
- data-id="move"
- />
- {onScale &&
- data.map((attr: CircleType) => (
- <Circle
- key={attr.direction}
- data-id={attr.direction}
- onMouseDown={handleMouseDown}
- onTouchStart={handleMouseDown}
- fill={theme.colors.primary}
- {...attr}
- />
- ))}
- </SVG>
- );
- };
- export default index;
|