Skip to content
Snippets Groups Projects
Commit 11c1d7f1 authored by Samuel Jugnet's avatar Samuel Jugnet
Browse files

Merge commit '181ffcca'

Conflicts:
	src/annotationForm/AnnotationDrawing.js
	src/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/ParentComponent.js
	src/annotationForm/KonvaDrawing/shapes/ParentComponent.js
parents 86038559 181ffcca
Branches
No related tags found
No related merge requests found
Showing
with 632 additions and 534 deletions
...@@ -8,7 +8,7 @@ import { v4 as uuid } from 'uuid'; ...@@ -8,7 +8,7 @@ import { v4 as uuid } from 'uuid';
import { exportStageSVG } from 'react-konva-to-svg'; import { exportStageSVG } from 'react-konva-to-svg';
import CompanionWindow from 'mirador/dist/es/src/containers/CompanionWindow'; import CompanionWindow from 'mirador/dist/es/src/containers/CompanionWindow';
import { OSDReferences } from 'mirador/dist/es/src/plugins/OSDReferences'; import { OSDReferences } from 'mirador/dist/es/src/plugins/OSDReferences';
import { VideosReferences } from "mirador/dist/es/src/plugins/VideosReferences"; import { VideosReferences } from 'mirador/dist/es/src/plugins/VideosReferences';
import Tab from '@mui/material/Tab'; import Tab from '@mui/material/Tab';
import HighlightAltIcon from '@mui/icons-material/HighlightAlt'; import HighlightAltIcon from '@mui/icons-material/HighlightAlt';
import LayersIcon from '@mui/icons-material/Layers'; import LayersIcon from '@mui/icons-material/Layers';
...@@ -20,30 +20,24 @@ import WebAnnotation from './WebAnnotation'; ...@@ -20,30 +20,24 @@ import WebAnnotation from './WebAnnotation';
import { secondsToHMS } from './utils'; import { secondsToHMS } from './utils';
import AnnotationFormContent from './annotationForm/AnnotationFormContent'; import AnnotationFormContent from './annotationForm/AnnotationFormContent';
import AnnotationFormTime from './annotationForm/AnnotationFormTime'; import AnnotationFormTime from './annotationForm/AnnotationFormTime';
import AnnotationFormDrawing from './annotationForm/AnnotationFormDrawing';
import { geomFromAnnoTarget, timeFromAnnoTarget } from './AnnotationCreationUtils'; import { geomFromAnnoTarget, timeFromAnnoTarget } from './AnnotationCreationUtils';
import AnnotationFormOverlay from './annotationForm/AnnotationFormOverlay/AnnotationFormOverlay.js';
const TARGET_VIEW = 'target'; const TARGET_VIEW = 'target';
const OVERLAY_VIEW = 'layer'; const OVERLAY_VIEW = 'layer';
const TAG_VIEW = 'tag'; const TAG_VIEW = 'tag';
const MANIFEST_LINK_VIEW = 'link'; const MANIFEST_LINK_VIEW = 'link';
/** Component for creating annotations. /** Component for creating annotations.
* Display in companion window when a manifest is open and an annoation created or edited */ * Display in companion window when a manifest is open and an annoation created or edited */
function AnnotationCreation(props) { function AnnotationCreation(props) {
const [toolState, setToolState] = useState({ const [toolState, setToolState] = useState({
activeTool: 'cursor', activeTool: 'edit',
closedMode: 'closed', closedMode: 'closed',
colorPopoverOpen: false,
currentColorType: false,
fillColor: 'rgba(255, 0, 0, 0.5)', fillColor: 'rgba(255, 0, 0, 0.5)',
image: { id: null }, image: { id: null },
imageEvent: null, imageEvent: null,
lineWeightPopoverOpen: false, strokeColor: 'rgba(255, 0, 0, 0.5)',
popoverAnchorEl: null,
popoverLineWeightAnchorEl: null,
strokeColor: 'green',
strokeWidth: 3, strokeWidth: 3,
}); });
...@@ -147,8 +141,6 @@ function AnnotationCreation(props) { ...@@ -147,8 +141,6 @@ function AnnotationCreation(props) {
}; };
}, []); }, []);
useEffect(() => { useEffect(() => {
}, [toolState.fillColor, toolState.strokeColor, toolState.strokeWidth]); }, [toolState.fillColor, toolState.strokeColor, toolState.strokeWidth]);
...@@ -248,7 +240,6 @@ function AnnotationCreation(props) { ...@@ -248,7 +240,6 @@ function AnnotationCreation(props) {
/** */ /** */
const setShapeProperties = (options) => new Promise(() => { const setShapeProperties = (options) => new Promise(() => {
if (options.fill) { if (options.fill) {
state.fillColor = options.fill; state.fillColor = options.fill;
} }
...@@ -282,30 +273,26 @@ function AnnotationCreation(props) { ...@@ -282,30 +273,26 @@ function AnnotationCreation(props) {
return svg; return svg;
}; };
/** Set color tool from current shape */ /** Set color tool from current shape */
const setColorToolFromCurrentShape = (colorState) => { const setColorToolFromCurrentShape = (colorState) => {
setToolState((prevState) => ({ setToolState((prevState) => ({
...prevState, ...prevState,
...colorState, ...colorState,
})); }));
} };
/** update shapes with shapes from annotationDrawing */ /** update shapes with shapes from annotationDrawing */
const updateShapes = (newShapes) => { const updateShapes = (newShapes) => {
setShapes(newShapes); setShapes(newShapes);
} };
/** delete shape */ /** delete shape */
const deleteShape = (shapeId) => { const deleteShape = (shapeId) => {
const newShapes = shapes.filter((shape) => shape.id !== shapeId); const newShapes = shapes.filter((shape) => shape.id !== shapeId);
setShapes(newShapes); setShapes(newShapes);
} };
/** /**
* Validate form and save annotation * Validate form and save annotation
...@@ -527,7 +514,7 @@ function AnnotationCreation(props) { ...@@ -527,7 +514,7 @@ function AnnotationCreation(props) {
<StyledTabPanel <StyledTabPanel
value={OVERLAY_VIEW} value={OVERLAY_VIEW}
> >
<AnnotationFormDrawing <AnnotationFormOverlay
toolState={toolState} toolState={toolState}
updateToolState={setToolState} updateToolState={setToolState}
handleImgChange={handleImgChange} handleImgChange={handleImgChange}
......
...@@ -18,3 +18,26 @@ export function geomFromAnnoTarget(annotarget) { ...@@ -18,3 +18,26 @@ export function geomFromAnnoTarget(annotarget) {
} }
return r[1]; return r[1];
} }
export const OVERLAY_TOOL = {
CURSOR: 'cursor',
DELETE: 'delete',
EDIT: 'edit',
IMAGE: 'image',
SHAPE: 'shapes',
TEXT: 'text',
};
export const SHAPES_TOOL = {
ARROW: 'arrow',
ELLIPSE: 'ellipse',
FREEHAND: 'freehand',
POLYGON: 'polygon',
RECTANGLE: 'rectangle',
SHAPES: 'shapes',
};
export function isShapesTool(activeTool) {
// Find if active tool in the list of overlay tools. I want a boolean in return
return Object.values(SHAPES_TOOL).find((tool) => tool === activeTool) ;
}
...@@ -11,11 +11,8 @@ import { v4 as uuidv4 } from 'uuid'; ...@@ -11,11 +11,8 @@ import { v4 as uuidv4 } from 'uuid';
import { OSDReferences } from 'mirador/dist/es/src/plugins/OSDReferences'; import { OSDReferences } from 'mirador/dist/es/src/plugins/OSDReferences';
// eslint-disable-next-line import/no-extraneous-dependencies // eslint-disable-next-line import/no-extraneous-dependencies
import { VideosReferences } from 'mirador/dist/es/src/plugins/VideosReferences'; import { VideosReferences } from 'mirador/dist/es/src/plugins/VideosReferences';
import ParentComponent from './KonvaDrawing/shapes/ParentComponent'; import ParentComponent from './AnnotationFormOverlay/KonvaDrawing/shapes/ParentComponent';
import Surface from './KonvaDrawing/Surface'; import { SHAPES_TOOL } from '../AnnotationCreationUtils';
import { act } from '@psychobolt/react-paperjs/dist/index.dev';
import { set } from 'lodash';
/** All the stuff to draw on the canvas */ /** All the stuff to draw on the canvas */
function AnnotationDrawing(props) { function AnnotationDrawing(props) {
const [shapes, setShapes] = useState([]); const [shapes, setShapes] = useState([]);
...@@ -76,18 +73,6 @@ function AnnotationDrawing(props) { ...@@ -76,18 +73,6 @@ function AnnotationDrawing(props) {
const { fillColor, strokeColor, strokeWidth } = props; const { fillColor, strokeColor, strokeWidth } = props;
/** Debug function facility */
const debug = (command) => {
console.debug('***************************');
console.debug(command);
console.debug('shapes', shapes);
console.debug('shapes taille', shapes.length);
console.debug('currentShape', currentShape);
console.debug('isDrawing', isDrawing);
console.debug('props.activeTool', props.activeTool);
console.debug('-----------------------------');
};
/** */ /** */
useEffect(() => { useEffect(() => {
if (!isDrawing) { if (!isDrawing) {
...@@ -123,7 +108,8 @@ function AnnotationDrawing(props) { ...@@ -123,7 +108,8 @@ function AnnotationDrawing(props) {
fillColor: currentShape.fill, fillColor: currentShape.fill,
strokeColor: currentShape.stroke, strokeColor: currentShape.stroke,
strokeWidth: currentShape.strokeWidth, strokeWidth: currentShape.strokeWidth,
}) },
);
return () => { return () => {
window.removeEventListener('keydown', handleKeyPress); window.removeEventListener('keydown', handleKeyPress);
...@@ -131,25 +117,18 @@ function AnnotationDrawing(props) { ...@@ -131,25 +117,18 @@ function AnnotationDrawing(props) {
} }
}, [currentShape]); }, [currentShape]);
useEffect(() => { useEffect(() => {
// compare shapes and props.shapes p, if different, update shapes // compare shapes and props.shapes p, if different, update shapes
if (props.shapes.length !== shapes.length) { /// nul a revoir if (props.shapes.length !== shapes.length) { /// nul a revoir
setShapes(props.shapes); setShapes(props.shapes);
} }
}, [props.shapes]); }, [props.shapes]);
/** */ /** */
const onShapeClick = async (shp) => { const onShapeClick = async (shp) => {
const shape = shapes.find((s) => s.id === shp.id); const shape = shapes.find((s) => s.id === shp.id);
if (props.activeTool === 'delete') { if (props.activeTool === 'delete') {
const newShapes = shapes.filter((s) => s.id !== shape.id); const newShapes = shapes.filter((s) => s.id !== shape.id);
setShapes(newShapes); setShapes(newShapes);
return; return;
...@@ -162,25 +141,22 @@ function AnnotationDrawing(props) { ...@@ -162,25 +141,22 @@ function AnnotationDrawing(props) {
fillColor: shape.fill, fillColor: shape.fill,
strokeColor: shape.stroke, strokeColor: shape.stroke,
strokeWidth: shape.strokeWidth, strokeWidth: shape.strokeWidth,
}) },
);
}; };
const onTransform = (evt) => { const onTransform = (evt) => {
const modifiedshape = evt.target.attrs; const modifiedshape = evt.target.attrs;
const shape = shapes.find((s) => s.id === modifiedshape.id); const shape = shapes.find((s) => s.id === modifiedshape.id);
Object.assign(shape, modifiedshape); Object.assign(shape, modifiedshape);
setCurrentShape({ ...shape }); setCurrentShape({ ...shape });
updateCurrentShapeInShapes(); updateCurrentShapeInShapes();
}; };
const handleDragEnd = (evt) => { const handleDragEnd = (evt) => {
const modifiedshape = evt.currentTarget.attrs; const modifiedshape = evt.currentTarget.attrs;
const shape = shapes.find((s) => s.id === modifiedshape.id); const shape = shapes.find((s) => s.id === modifiedshape.id);
shape.x = modifiedshape.x; shape.x = modifiedshape.x;
...@@ -244,7 +220,6 @@ function AnnotationDrawing(props) { ...@@ -244,7 +220,6 @@ function AnnotationDrawing(props) {
} }
}; };
/** */ /** */
const updateCurrentShapeInShapes = () => { const updateCurrentShapeInShapes = () => {
const index = shapes.findIndex((s) => s.id === currentShape.id); const index = shapes.findIndex((s) => s.id === currentShape.id);
...@@ -265,7 +240,7 @@ function AnnotationDrawing(props) { ...@@ -265,7 +240,7 @@ function AnnotationDrawing(props) {
pos.y /= props.scale; pos.y /= props.scale;
let shape = null; let shape = null;
switch (props.activeTool) { switch (props.activeTool) {
case 'rectangle': case SHAPES_TOOL.RECTANGLE:
shape = { shape = {
fill: props.fillColor, fill: props.fillColor,
height: 1, height: 1,
...@@ -283,18 +258,19 @@ function AnnotationDrawing(props) { ...@@ -283,18 +258,19 @@ function AnnotationDrawing(props) {
setIsDrawing(true); setIsDrawing(true);
setShapes([...shapes, shape]); setShapes([...shapes, shape]);
setCurrentShape(shape); setCurrentShape(shape);
case 'ellipse': break;
case SHAPES_TOOL.ELLIPSE:
shape = { shape = {
fill: props.fillColor, fill: props.fillColor,
height: 1, height: 1,
id: uuidv4(), id: uuidv4(),
radiusX: 1,
radiusY: 1,
rotation: 0, rotation: 0,
scaleX: 1, scaleX: 1,
scaleY: 1, scaleY: 1,
stroke: props.strokeColor, stroke: props.strokeColor,
strokeWidth: props.strokeWidth, strokeWidth: props.strokeWidth,
radiusX: 1,
radiusY: 1,
type: props.activeTool, type: props.activeTool,
width: 1, width: 1,
x: pos.x, x: pos.x,
...@@ -305,7 +281,7 @@ function AnnotationDrawing(props) { ...@@ -305,7 +281,7 @@ function AnnotationDrawing(props) {
setCurrentShape(shape); setCurrentShape(shape);
break; break;
case 'text': case SHAPES_TOOL.TEXT:
shape = { shape = {
fill: props.fillColor, fill: props.fillColor,
fontSize: 50, fontSize: 50,
...@@ -314,7 +290,7 @@ function AnnotationDrawing(props) { ...@@ -314,7 +290,7 @@ function AnnotationDrawing(props) {
scaleX: 1, scaleX: 1,
scaleY: 1, scaleY: 1,
text: 'text', text: 'text',
type: 'text', type: SHAPES_TOOL.TEXT,
x: pos.x, x: pos.x,
y: pos.y, y: pos.y,
}; };
...@@ -322,7 +298,7 @@ function AnnotationDrawing(props) { ...@@ -322,7 +298,7 @@ function AnnotationDrawing(props) {
setShapes([...shapes, shape]); setShapes([...shapes, shape]);
setCurrentShape(shape); setCurrentShape(shape);
break; break;
case 'freehand': case SHAPES_TOOL.FREEHAND:
// Not totally functionnal // Not totally functionnal
setIsDrawing(true); setIsDrawing(true);
shape = { shape = {
...@@ -342,14 +318,14 @@ function AnnotationDrawing(props) { ...@@ -342,14 +318,14 @@ function AnnotationDrawing(props) {
scaleY: 1, scaleY: 1,
stroke: props.strokeColor, stroke: props.strokeColor,
strokeWidth: props.strokeWidth, strokeWidth: props.strokeWidth,
type: 'freehand', type: SHAPES_TOOL.FREEHAND,
x: 0, x: 0,
y: 0, y: 0,
}; };
setShapes([...shapes, shape]); setShapes([...shapes, shape]);
setCurrentShape(shape); setCurrentShape(shape);
break; break;
case 'polygon': case SHAPES_TOOL.POLYGON:
setIsDrawing(true); setIsDrawing(true);
shape = { shape = {
fill: props.fillColor, fill: props.fillColor,
...@@ -360,14 +336,14 @@ function AnnotationDrawing(props) { ...@@ -360,14 +336,14 @@ function AnnotationDrawing(props) {
scaleY: 1, scaleY: 1,
stroke: props.strokeColor, stroke: props.strokeColor,
strokeWidth: props.strokeWidth, strokeWidth: props.strokeWidth,
type: 'polygon', type: SHAPES_TOOL.POLYGON,
x: 0, x: 0,
y: 0, y: 0,
}; };
setShapes([...shapes, shape]); setShapes([...shapes, shape]);
setCurrentShape(shape); setCurrentShape(shape);
break; break;
case 'arrow': case SHAPES_TOOL.ARROW:
setIsDrawing(true); setIsDrawing(true);
shape = { shape = {
fill: props.fillColor, fill: props.fillColor,
...@@ -379,12 +355,10 @@ function AnnotationDrawing(props) { ...@@ -379,12 +355,10 @@ function AnnotationDrawing(props) {
scaleX: 1, scaleX: 1,
scaleY: 1, scaleY: 1,
stroke: props.strokeColor, stroke: props.strokeColor,
type: 'arrow', type: SHAPES_TOOL.ARROW,
}; };
setShapes([...shapes, shape]); setShapes([...shapes, shape]);
setCurrentShape(shape); setCurrentShape(shape);
case 'debug':
debug('debug');
break; break;
default: default:
// Handle other cases if any // Handle other cases if any
...@@ -409,7 +383,7 @@ function AnnotationDrawing(props) { ...@@ -409,7 +383,7 @@ function AnnotationDrawing(props) {
pos.y /= props.scale; pos.y /= props.scale;
switch (props.activeTool) { switch (props.activeTool) {
case 'rectangle': case SHAPES_TOOL.RECTANGLE:
setCurrentShape({ setCurrentShape({
...currentShape, ...currentShape,
...@@ -417,7 +391,8 @@ function AnnotationDrawing(props) { ...@@ -417,7 +391,8 @@ function AnnotationDrawing(props) {
width: pos.x - currentShape.x, width: pos.x - currentShape.x,
}); });
updateCurrentShapeInShapes(); updateCurrentShapeInShapes();
case 'ellipse': break;
case SHAPES_TOOL.ELLIPSE:
// prevent negative radius for ellipse // prevent negative radius for ellipse
if (pos.x < currentShape.x) { if (pos.x < currentShape.x) {
...@@ -427,7 +402,6 @@ function AnnotationDrawing(props) { ...@@ -427,7 +402,6 @@ function AnnotationDrawing(props) {
pos.y = currentShape.y; pos.y = currentShape.y;
} }
setCurrentShape({ setCurrentShape({
...currentShape, ...currentShape,
height: pos.y - currentShape.y, height: pos.y - currentShape.y,
...@@ -438,7 +412,7 @@ function AnnotationDrawing(props) { ...@@ -438,7 +412,7 @@ function AnnotationDrawing(props) {
updateCurrentShapeInShapes(); updateCurrentShapeInShapes();
break; break;
case 'freehand': case SHAPES_TOOL.FREEHAND:
const shape = { ...currentShape }; const shape = { ...currentShape };
shape.lines.push({ shape.lines.push({
points: [pos.x, pos.y, pos.x, pos.y], points: [pos.x, pos.y, pos.x, pos.y],
...@@ -448,14 +422,14 @@ function AnnotationDrawing(props) { ...@@ -448,14 +422,14 @@ function AnnotationDrawing(props) {
setCurrentShape(shape); setCurrentShape(shape);
updateCurrentShapeInShapes(); updateCurrentShapeInShapes();
break; break;
case 'polygon': case SHAPES_TOOL.POLYGON:
const polygonShape = { ...currentShape }; const polygonShape = { ...currentShape };
polygonShape.points[2] = pos.x; polygonShape.points[2] = pos.x;
polygonShape.points[3] = pos.y; polygonShape.points[3] = pos.y;
setCurrentShape(polygonShape); setCurrentShape(polygonShape);
updateCurrentShapeInShapes(); updateCurrentShapeInShapes();
break; break;
case 'arrow': case SHAPES_TOOL.ARROW:
// TODO improve // TODO improve
const arrowShape = {}; const arrowShape = {};
// update points // update points
......
import {
Button, ClickAwayListener, Divider, Grid, MenuItem, MenuList, Paper, Popover,
} from '@mui/material';
import Typography from '@mui/material/Typography';
import ToggleButton from '@mui/material/ToggleButton';
import TitleIcon from '@mui/icons-material/Title';
import ImageIcon from '@mui/icons-material/Image';
import DeleteIcon from '@mui/icons-material/Delete';
import ArrowOutwardIcon from '@mui/icons-material/ArrowOutward';
import RectangleIcon from '@mui/icons-material/CheckBoxOutlineBlank';
import CircleIcon from '@mui/icons-material/RadioButtonUnchecked';
import PolygonIcon from '@mui/icons-material/Timeline';
import GestureIcon from '@mui/icons-material/Gesture';
import React, { useEffect } from 'react';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
import StrokeColorIcon from '@mui/icons-material/BorderColor';
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
import LineWeightIcon from '@mui/icons-material/LineWeight';
import FormatColorFillIcon from '@mui/icons-material/FormatColorFill';
import ClosedPolygonIcon from '@mui/icons-material/ChangeHistory';
import OpenPolygonIcon from '@mui/icons-material/ShowChart';
import AddPhotoAlternateIcon from '@mui/icons-material/AddPhotoAlternate';
import PropTypes from 'prop-types';
import { styled } from '@mui/material/styles';
import { SketchPicker } from 'react-color';
import { v4 as uuidv4 } from 'uuid';
import CategoryIcon from '@mui/icons-material/Category';
import CursorIcon from '../icons/Cursor';
import ImageFormField from './ImageFormField';
const StyledToggleButtonGroup = styled(ToggleButtonGroup)(({ theme }) => ({
'&:first-of-type': {
borderRadius: theme.shape.borderRadius,
},
'&:not(:first-of-type)': {
borderRadius: theme.shape.borderRadius,
},
border: 'none',
margin: theme.spacing(0.5),
}));
const StyledDivider = styled(Divider)(({ theme }) => ({
margin: theme.spacing(1, 0.5),
}));
const StyledLi = styled('li')(({ theme }) => ({
display:'flex',
wordBreak: 'break-word',
}));
const StyledUl = styled('ul')(({ theme }) => ({
display:'flex',
flexDirection: 'column',
gap: '5px',
listStyle: 'none',
paddingLeft: '0',
}));
const StyledPaper = styled(Paper)(({ theme }) => ({
padding: '5px',
}));
const StyledDivButtonImage = styled('div')(({ theme }) => ({
display: 'flex',
justifyContent: 'flex-end',
marginTop: '5px',
}));
const rgbaToObj = (rgba = 'rgba(255,255,255,0.5)') => {
const rgbaArray = rgba.split(',');
const r = Number(rgbaArray[0].split('(')[1]);
const g = Number(rgbaArray[1]);
const b = Number(rgbaArray[2]);
const a = Number(rgbaArray[3].split(')')[0]);
return {
// eslint-disable-next-line sort-keys
r, g, b, a,
};
};
const objToRgba = (obj = {
// eslint-disable-next-line sort-keys
r: 255, g: 255, b: 255, a: 0.5,
}) => `rgba(${obj.r},${obj.g},${obj.b},${obj.a})`;
/** Check if we are using an overlay tool or selecting the overlay view */
function isShapeTool(activeTool) {
switch (activeTool) {
case 'rectangle':
case 'ellipse':
case 'arrow':
case 'polygon':
case 'freehand':
case 'shapes':
return true;
break;
default:
return false;
}
}
/** All the stuff to manage to choose the drawing tool */
function AnnotationFormDrawing({ updateToolState, toolState, handleImgChange, shapes,deleteShape }) {
useEffect(() => {
}, [toolState.fillColor, toolState.strokeColor, toolState.strokeWidth]);
/** */
const openChooseLineWeight = (e) => {
updateToolState({
...toolState,
lineWeightPopoverOpen: true,
popoverLineWeightAnchorEl: e.currentTarget,
});
};
/** Close color popover window */
const closeChooseColor = (e) => {
updateToolState({
...toolState,
colorPopoverOpen: false,
currentColorType: null,
popoverAnchorEl: null,
});
};
/** Update color : fillColor or strokeColor */
const updateStrokeColor = (color) => {
updateToolState({
...toolState,
[toolState.currentColorType]: objToRgba(color.rgb),
});
};
/** */
const openChooseColor = (e) => {
updateToolState({
...toolState,
colorPopoverOpen: true,
currentColorType: e.currentTarget.value,
popoverAnchorEl: e.currentTarget,
});
};
/** */
const handleCloseLineWeight = (e) => {
updateToolState({
...toolState,
lineWeightPopoverOpen: false,
popoverLineWeightAnchorEl: null,
});
};
/** */
const handleLineWeightSelect = (e) => {
updateToolState({
...toolState,
lineWeightPopoverOpen: false,
popoverLineWeightAnchorEl: null,
strokeWidth: e.currentTarget.value,
});
};
const changeTool = (e, tool) => {
updateToolState({
...toolState,
activeTool: tool,
});
};
const changeClosedMode = (e) => {
updateToolState({
...toolState,
closedMode: e.currentTarget.value,
});
};
/**
*
*/
const addImage = () => {
const data = {
id: image?.id,
uuid: uuidv4(),
};
updateToolState({
...toolState,
image: { id: null },
imageEvent: data,
});
};
const {
activeTool,
closedMode,
image,
lineWeightPopoverOpen,
popoverLineWeightAnchorEl,
fillColor,
strokeColor,
strokeWidth,
colorPopoverOpen,
popoverAnchorEl,
currentColorType,
} = toolState;
return (
<StyledPaper>
<div>
<Grid container>
<Grid item xs={12}>
<Typography variant="overline">
Overlay
</Typography>
</Grid>
<Grid item xs={12}>
<StyledToggleButtonGroup
value={activeTool} // State or props ?
exclusive
onChange={changeTool}
aria-label="tool selection"
size="small"
>
<ToggleButton value="edit" aria-label="select cursor">
<CursorIcon />
</ToggleButton>
<ToggleButton value="shapes" aria-label="select cursor">
<CategoryIcon />
</ToggleButton>
<ToggleButton value="images" aria-label="select cursor">
<ImageIcon />
</ToggleButton>
<ToggleButton value="text" aria-label="select text">
<TitleIcon />
</ToggleButton>
<ToggleButton value="delete" aria-label="select cursor">
<DeleteIcon />
</ToggleButton>
</StyledToggleButtonGroup>
{
activeTool === 'edit' && (
<StyledUl>
{shapes && shapes.map((shape) => (
<StyledLi key={shape.id}>
{shape.id}
<Button onClick={() => deleteShape(shape.id)}>
<DeleteIcon />
</Button>
</StyledLi>
))}
</StyledUl>
)
}
{
isShapeTool(activeTool) && (
<>
<StyledToggleButtonGroup
value={activeTool} // State or props ?
exclusive
onChange={changeTool}
aria-label="tool selection"
size="small"
>
<ToggleButton value="rectangle" aria-label="add a rectangle">
<RectangleIcon />
</ToggleButton>
<ToggleButton value="ellipse" aria-label="add a circle">
<CircleIcon />
</ToggleButton>
<ToggleButton value="arrow" aria-label="add an arrow">
<ArrowOutwardIcon />
</ToggleButton>
<ToggleButton value="polygon" aria-label="add a polygon">
<PolygonIcon />
</ToggleButton>
<ToggleButton value="freehand" aria-label="free hand polygon">
<GestureIcon />
</ToggleButton>
</StyledToggleButtonGroup>
<div>
<Grid container>
<Grid item xs={12}>
<Typography variant="overline">
Style
</Typography>
</Grid>
<Grid item xs={12}>
<ToggleButtonGroup
aria-label="style selection"
size="small"
>
<ToggleButton
value="strokeColor"
aria-label="select color"
onClick={openChooseColor}
>
<StrokeColorIcon style={{ fill: strokeColor }} />
<ArrowDropDownIcon />
</ToggleButton>
<ToggleButton
value="strokeColor"
aria-label="select line weight"
onClick={openChooseLineWeight}
>
<LineWeightIcon />
<ArrowDropDownIcon />
</ToggleButton>
<ToggleButton
value="fillColor"
aria-label="select color"
onClick={openChooseColor}
>
<FormatColorFillIcon style={{ fill: fillColor }} />
<ArrowDropDownIcon />
</ToggleButton>
</ToggleButtonGroup>
<StyledDivider flexItem orientation="vertical" />
{ /* close / open polygon mode only for freehand drawing mode. */
activeTool === 'freehand'
? (
<ToggleButtonGroup
size="small"
value={closedMode}
onChange={changeClosedMode}
>
<ToggleButton value="closed">
<ClosedPolygonIcon />
</ToggleButton>
<ToggleButton value="open">
<OpenPolygonIcon />
</ToggleButton>
</ToggleButtonGroup>
)
: null
}
</Grid>
</Grid>
</div>
</>
)
}
{
activeTool === 'images' ? (
<>
<Grid container>
<ImageFormField xs={8} value={image} onChange={handleImgChange} />
</Grid>
<StyledDivButtonImage>
<Button variant="contained" onClick={addImage}>
<AddPhotoAlternateIcon />
</Button>
</StyledDivButtonImage>
</>
) : (<></>)
}
{
activeTool === 'text' && (
<Typography>
Ajouter un input text
</Typography>
)
}
</Grid>
</Grid>
</div>
<Popover
open={lineWeightPopoverOpen}
anchorEl={popoverLineWeightAnchorEl}
>
<Paper>
<ClickAwayListener onClickAway={handleCloseLineWeight}>
<MenuList autoFocus role="listbox">
{[1, 3, 5, 10, 50].map((option, index) => (
<MenuItem
key={option}
onClick={handleLineWeightSelect}
value={option}
selected={option == strokeWidth}
role="option"
aria-selected={option == strokeWidth}
>
{option}
</MenuItem>
))}
</MenuList>
</ClickAwayListener>
</Paper>
</Popover>
<Popover
open={colorPopoverOpen}
anchorEl={popoverAnchorEl}
onClose={closeChooseColor}
>
<SketchPicker
disableAlpha={false}
color={rgbaToObj(toolState[currentColorType])}
onChangeComplete={updateStrokeColor}
/>
</Popover>
</StyledPaper>
);
}
AnnotationFormDrawing.propTypes = {
handleImgChange: PropTypes.func,
toolState: PropTypes.object,
updateToolState: PropTypes.func,
shapes: PropTypes.object,
deleteShape: PropTypes.func,
};
export default AnnotationFormDrawing;
import {
Button, Grid, Paper,
} from '@mui/material';
import Typography from '@mui/material/Typography';
import ToggleButton from '@mui/material/ToggleButton';
import TitleIcon from '@mui/icons-material/Title';
import ImageIcon from '@mui/icons-material/Image';
import DeleteIcon from '@mui/icons-material/Delete';
import React, { useEffect } from 'react';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
import PropTypes from 'prop-types';
import { styled } from '@mui/material/styles';
import CategoryIcon from '@mui/icons-material/Category';
import CursorIcon from '../../icons/Cursor';
import AnnotationFormOverlayTool from './AnnotationFormOverlayTool';
import { OVERLAY_TOOL } from '../../AnnotationCreationUtils';
const StyledToggleButtonGroup = styled(ToggleButtonGroup)(({ theme }) => ({
'&:first-of-type': {
borderRadius: theme.shape.borderRadius,
},
'&:not(:first-of-type)': {
borderRadius: theme.shape.borderRadius,
},
border: 'none',
margin: theme.spacing(0.5),
}));
const StyledPaper = styled(Paper)(({ theme }) => ({
padding: '5px',
}));
/** All the stuff to manage to choose the drawing tool */
function AnnotationFormOverlay({
updateToolState, toolState, shapes, deleteShape,
}) {
useEffect(() => {
}, [toolState.fillColor, toolState.strokeColor, toolState.strokeWidth]);
const changeTool = (e, tool) => {
updateToolState({
...toolState,
activeTool: tool,
});
};
const {
activeTool,
} = toolState;
return (
<StyledPaper>
<div>
<Grid container>
<Grid item xs={12}>
<Typography variant="overline">
Overlay
</Typography>
</Grid>
<Grid item xs={12}>
<StyledToggleButtonGroup
value={activeTool} // State or props ?
exclusive
onChange={changeTool}
aria-label="tool selection"
size="small"
>
<ToggleButton value={OVERLAY_TOOL.EDIT} aria-label="select cursor">
<CursorIcon />
</ToggleButton>
<ToggleButton value={OVERLAY_TOOL.SHAPE} aria-label="select cursor">
<CategoryIcon />
</ToggleButton>
<ToggleButton value={OVERLAY_TOOL.IMAGE} aria-label="select cursor">
<ImageIcon />
</ToggleButton>
<ToggleButton value={OVERLAY_TOOL.TEXT} aria-label="select text">
<TitleIcon />
</ToggleButton>
<ToggleButton value={OVERLAY_TOOL.DELETE} aria-label="select cursor">
<DeleteIcon />
</ToggleButton>
</StyledToggleButtonGroup>
<AnnotationFormOverlayTool
toolState={toolState}
updateToolState={updateToolState}
shapes={shapes}
deleteShape={deleteShape}
/>
</Grid>
</Grid>
</div>
</StyledPaper>
);
}
AnnotationFormOverlay.propTypes = {
deleteShape: PropTypes.func.isRequired,
shapes: PropTypes.array.isRequired,
toolState: PropTypes.shape({
activeTool: PropTypes.string.isRequired,
closedMode: PropTypes.bool.isRequired,
fillColor: PropTypes.string.isRequired,
image: PropTypes.shape({
id: PropTypes.string,
}).isRequired,
strokeColor: PropTypes.string.isRequired,
strokeWidth: PropTypes.number.isRequired,
updateColor: PropTypes.func.isRequired,
}).isRequired,
updateToolState: PropTypes.func.isRequired,
};
export default AnnotationFormOverlay;
import ToggleButton from '@mui/material/ToggleButton';
import RectangleIcon from '@mui/icons-material/CheckBoxOutlineBlank';
import CircleIcon from '@mui/icons-material/RadioButtonUnchecked';
import ArrowOutwardIcon from '@mui/icons-material/ArrowOutward';
import PolygonIcon from '@mui/icons-material/Timeline';
import GestureIcon from '@mui/icons-material/Gesture';
import PropTypes from 'prop-types';
import React from 'react';
import { styled } from '@mui/material/styles';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
import { Button } from '@mui/material';
import DeleteIcon from '@mui/icons-material/Delete';
import AnnotationFormOverlayToolOptions from './AnnotationFormOverlayToolOptions';
import { isShapesTool, OVERLAY_TOOL, SHAPES_TOOL } from '../../AnnotationCreationUtils';
const StyledLi = styled('li')(({ theme }) => ({
display: 'flex',
wordBreak: 'break-word',
}));
const StyledUl = styled('ul')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: '5px',
listStyle: 'none',
paddingLeft: '0',
}));
// TODO WIP code duplicated
const StyledToggleButtonGroup = styled(ToggleButtonGroup)(({ theme }) => ({
'&:first-of-type': {
borderRadius: theme.shape.borderRadius,
},
'&:not(:first-of-type)': {
borderRadius: theme.shape.borderRadius,
},
border: 'none',
margin: theme.spacing(0.5),
}));
/** All the form part for the overlay view */
function AnnotationFormOverlayTool({
toolState, updateToolState, shapes, deleteShape,
}) {
/** Change the active overlay tool */
const changeTool = (e, tool) => {
updateToolState({
...toolState,
activeTool: tool,
});
};
return (
<>
{toolState.activeTool}
{
toolState.activeTool === OVERLAY_TOOL.EDIT && (
<StyledUl>
{shapes && shapes.map((shape) => (
<StyledLi key={shape.id}>
{shape.id}
<Button onClick={() => deleteShape(shape.id)}>
<DeleteIcon />
</Button>
</StyledLi>
))}
</StyledUl>
)
}
{
isShapesTool(toolState.activeTool) && (
<StyledToggleButtonGroup
value={toolState.activeTool} // State or props ?
exclusive
onChange={changeTool}
aria-label="tool selection"
size="small"
>
<ToggleButton value={SHAPES_TOOL.RECTANGLE} aria-label="add a rectangle">
<RectangleIcon />
</ToggleButton>
<ToggleButton value={SHAPES_TOOL.ELLIPSE} aria-label="add a circle">
<CircleIcon />
</ToggleButton>
<ToggleButton value={SHAPES_TOOL.ARROW} aria-label="add an arrow">
<ArrowOutwardIcon />
</ToggleButton>
<ToggleButton value={SHAPES_TOOL.POLYGON} aria-label="add a polygon">
<PolygonIcon />
</ToggleButton>
<ToggleButton value={SHAPES_TOOL.FREEHAND} aria-label="free hand polygon">
<GestureIcon />
</ToggleButton>
</StyledToggleButtonGroup>
)
}
<AnnotationFormOverlayToolOptions
toolState={toolState}
updateToolState={updateToolState}
/>
</>
);
}
AnnotationFormOverlayTool.propTypes = {
toolState: PropTypes.shape({
activeTool: PropTypes.string.isRequired,
closedMode: PropTypes.bool.isRequired,
fillColor: PropTypes.string.isRequired,
image: PropTypes.shape({
id: PropTypes.string,
}).isRequired,
strokeColor: PropTypes.string.isRequired,
strokeWidth: PropTypes.number.isRequired,
updateColor: PropTypes.func.isRequired,
}).isRequired,
updateToolState: PropTypes.func.isRequired,
};
export default AnnotationFormOverlayTool;
import {
Button,
ClickAwayListener, Divider, Grid, MenuItem, MenuList, Paper, Popover,
} from '@mui/material';
import Typography from '@mui/material/Typography';
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
import ToggleButton from '@mui/material/ToggleButton';
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
import StrokeColorIcon from '@mui/icons-material/BorderColor';
import LineWeightIcon from '@mui/icons-material/LineWeight';
import FormatColorFillIcon from '@mui/icons-material/FormatColorFill';
import React, { useState } from 'react';
import ClosedPolygonIcon from '@mui/icons-material/ChangeHistory';
import OpenPolygonIcon from '@mui/icons-material/ShowChart';
import PropTypes from 'prop-types';
import { styled } from '@mui/material/styles';
import { SketchPicker } from 'react-color';
import AddPhotoAlternateIcon from '@mui/icons-material/AddPhotoAlternate';
import { v4 as uuidv4 } from 'uuid';
import ImageFormField from './ImageFormField';
import { isShapesTool, OVERLAY_TOOL } from '../../AnnotationCreationUtils';
const StyledDivider = styled(Divider)(({ theme }) => ({
margin: theme.spacing(1, 0.5),
}));
const StyledDivButtonImage = styled('div')(({ theme }) => ({
display: 'flex',
justifyContent: 'flex-end',
marginTop: '5px',
}));
/** Utils functions to convert string to object */
const rgbaToObj = (rgba = 'rgba(255,255,255,0.5)') => {
const rgbaArray = rgba.split(',');
return {
// eslint-disable-next-line sort-keys
r: Number(rgbaArray[0].split('(')[1]),
// eslint-disable-next-line sort-keys
g: Number(rgbaArray[1]),
// eslint-disable-next-line sort-keys
b: Number(rgbaArray[2]),
// eslint-disable-next-line sort-keys
a: Number(rgbaArray[3].split(')')[0]),
};
};
/** Convert color object to rgba string */
const objToRgba = (obj = {
// eslint-disable-next-line sort-keys
r: 255, g: 255, b: 255, a: 0.5,
}) => `rgba(${obj.r},${obj.g},${obj.b},${obj.a})`;
/** All the tools options for the overlay options */
function AnnotationFormOverlayToolOptions({ updateToolState, toolState }) {
// set toolOptionsValue
const [toolOptions, setToolOptions] = useState({
colorPopoverOpen: false,
currentColorType: null,
lineWeightPopoverOpen: false,
popoverAnchorEl: null,
popoverLineWeightAnchorEl: null,
});
// Set unused default color to avoid error on render
const currentColor = toolOptions.currentColorType ? rgbaToObj(toolState[toolOptions.currentColorType]) : 'rgba(255, 0, 0, 0.5)';
// Fonction to manage option displaying
/** */
const openChooseLineWeight = (e) => {
setToolOptions({
...toolOptions,
lineWeightPopoverOpen: true,
popoverLineWeightAnchorEl: e.currentTarget,
});
};
/** */
const handleLineWeightSelect = (e) => {
setToolOptions({
...toolOptions,
lineWeightPopoverOpen: false,
popoverLineWeightAnchorEl: null,
});
updateToolState({
...toolState,
strokeWidth: e.currentTarget.value,
});
};
/** Close color popover window */
const closeChooseColor = (e) => {
setToolOptions({
...toolOptions,
colorPopoverOpen: false,
currentColorType: null,
popoverAnchorEl: null,
});
};
/** */
const openChooseColor = (e) => {
console.log('openChooseColor', e.currentTarget.value);
setToolOptions({
...toolOptions,
colorPopoverOpen: true,
currentColorType: e.currentTarget.value,
popoverAnchorEl: e.currentTarget,
});
};
/** */
const handleCloseLineWeight = (e) => {
setToolOptions({
...toolOptions,
lineWeightPopoverOpen: false,
popoverLineWeightAnchorEl: null,
});
};
/** closed mode change */
const changeClosedMode = (e) => {
updateToolState({
...toolState,
closedMode: e.currentTarget.value,
});
};
/** Update color : fillColor or strokeColor */
const updateColor = (color) => {
updateToolState({
...toolState,
[toolOptions.currentColorType]: objToRgba(color.rgb),
});
};
const addImage = () => {
const data = {
id: toolState?.image?.id,
uuid: uuidv4(),
};
updateToolState({
...toolState,
image: { id: null },
imageEvent: data,
});
};
const handleImgChange = (newUrl, imgRef) => {
updateToolState({
...toolState,
image: { ...toolState.image, id: newUrl },
});
};
return (
<div>
{
isShapesTool(toolState.activeTool) && (
<Grid container>
<Grid item xs={12}>
<Typography variant="overline">
Style
</Typography>
</Grid>
<Grid item xs={12}>
<ToggleButtonGroup
aria-label="style selection"
size="small"
>
<ToggleButton
value="strokeColor"
aria-label="select color"
onClick={openChooseColor}
>
<StrokeColorIcon style={{ fill: toolState.strokeColor }} />
<ArrowDropDownIcon />
</ToggleButton>
<ToggleButton
value="strokeColor"
aria-label="select line weight"
onClick={openChooseLineWeight}
>
<LineWeightIcon />
<ArrowDropDownIcon />
</ToggleButton>
<ToggleButton
value="fillColor"
aria-label="select color"
onClick={openChooseColor}
>
<FormatColorFillIcon style={{ fill: toolState.fillColor }} />
<ArrowDropDownIcon />
</ToggleButton>
</ToggleButtonGroup>
<StyledDivider flexItem orientation="vertical" />
{ /* close / open polygon mode only for freehand drawing mode. */
toolState.activeTool === 'freehand'
&& (
<ToggleButtonGroup
size="small"
value={toolState.closedMode}
onChange={changeClosedMode}
>
<ToggleButton value="closed">
<ClosedPolygonIcon />
</ToggleButton>
<ToggleButton value="open">
<OpenPolygonIcon />
</ToggleButton>
</ToggleButtonGroup>
)
}
</Grid>
<Popover
open={toolOptions.lineWeightPopoverOpen}
anchorEl={toolOptions.popoverLineWeightAnchorEl}
>
<Paper>
<ClickAwayListener onClickAway={handleCloseLineWeight}>
<MenuList autoFocus role="listbox">
{[1, 3, 5, 10, 50].map((option, index) => (
<MenuItem
key={option}
onClick={handleLineWeightSelect}
value={option}
selected={option === toolState.strokeWidth}
role="option"
aria-selected={option === toolState.strokeWidth}
>
{option}
</MenuItem>
))}
</MenuList>
</ClickAwayListener>
</Paper>
</Popover>
<Popover
open={toolOptions.colorPopoverOpen}
anchorEl={toolOptions.popoverAnchorEl}
onClose={closeChooseColor}
>
<SketchPicker
disableAlpha={false}
color={currentColor}
onChangeComplete={updateColor}
/>
</Popover>
</Grid>
)
}
{
toolState.activeTool === OVERLAY_TOOL.IMAGE && (
<>
<Grid container>
<ImageFormField xs={8} value={toolState.image} onChange={handleImgChange} />
</Grid>
<StyledDivButtonImage>
<Button variant="contained" onClick={addImage}>
<AddPhotoAlternateIcon />
</Button>
</StyledDivButtonImage>
</>
)
}
{
toolState.activeTool === 'text' && (
// <TextField
// value={toolState.text
// onChange={(ev) => onChange(ev.target.value)}
// error={imgUrl !== '' && !imgIsValid}
// margin="dense"
// label="Image URL"
// type="url"
// fullWidth
// inputRef={inputRef}
// />
' TODO add input'
)
}
</div>
);
}
AnnotationFormOverlayToolOptions.propTypes = {
toolState: PropTypes.shape({
activeTool: PropTypes.string.isRequired,
closedMode: PropTypes.bool.isRequired,
fillColor: PropTypes.string.isRequired,
image: PropTypes.shape({
id: PropTypes.string,
}).isRequired,
strokeColor: PropTypes.string.isRequired,
strokeWidth: PropTypes.number.isRequired,
updateColor: PropTypes.func.isRequired,
}).isRequired,
updateToolState: PropTypes.func.isRequired,
};
export default AnnotationFormOverlayToolOptions;
...@@ -10,10 +10,11 @@ const StyledRoot = styled('div')(({ theme }) => ({ ...@@ -10,10 +10,11 @@ const StyledRoot = styled('div')(({ theme }) => ({
})); }));
const StyledTextField = styled(TextField)(({ theme }) => ({ const StyledTextField = styled(TextField)(({ theme }) => ({
marginTop:"0", marginBottom: '0',
marginBottom:"0", marginTop: '0',
})); }));
/** Image input field for the annotation form */
function ImageFormField({ value: image, onChange }) { function ImageFormField({ value: image, onChange }) {
const inputRef = useRef(null); const inputRef = useRef(null);
const [imgIsValid, setImgIsValid] = useState(false); const [imgIsValid, setImgIsValid] = useState(false);
......
...@@ -5,7 +5,7 @@ import { Ellipse, Transformer } from 'react-konva'; ...@@ -5,7 +5,7 @@ import { Ellipse, Transformer } from 'react-konva';
function EllipseNode({ function EllipseNode({
onShapeClick, shape, activeTool, isSelected, onShapeClick, shape, activeTool, isSelected,
onTransform, handleDragEnd onTransform, handleDragEnd,
}) { }) {
const shapeRef = useRef(); const shapeRef = useRef();
const trRef = useRef(); const trRef = useRef();
...@@ -53,13 +53,13 @@ function EllipseNode({ ...@@ -53,13 +53,13 @@ function EllipseNode({
EllipseNode.propTypes = { EllipseNode.propTypes = {
fill: PropTypes.string, fill: PropTypes.string.isRequired,
height: PropTypes.number, height: PropTypes.number,
onShapeClick: PropTypes.func.isRequired, onShapeClick: PropTypes.func.isRequired,
selectedShapeId: PropTypes.string, selectedShapeId: PropTypes.string,
shape: PropTypes.object.isRequired, shape: PropTypes.object.isRequired,
stroke: PropTypes.string, stroke: PropTypes.string.isRequired,
strokeWidth: PropTypes.number, strokeWidth: PropTypes.number.isRequired,
width: PropTypes.number, width: PropTypes.number,
x: PropTypes.number, x: PropTypes.number,
y: PropTypes.number, y: PropTypes.number,
...@@ -71,9 +71,6 @@ EllipseNode.defaultProps = { ...@@ -71,9 +71,6 @@ EllipseNode.defaultProps = {
y: 100, y: 100,
width: 100, width: 100,
height: 100, height: 100,
fill: 'red',
stroke: 'black',
strokeWidth: 1,
}; };
export default EllipseNode; export default EllipseNode;
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Layer } from 'react-konva'; import { Layer } from 'react-konva';
import Rectangle from './Rectangle'; import Rectangle from './Rectangle';
import EllipseNode from './EllipseNode'; import EllipseNode from './EllipseNode';
import TextNode from './TextNode'; import TextNode from './TextNode';
import LineNode from './LineNode';
import ArrowNode from './ArrowNode'; import ArrowNode from './ArrowNode';
import Polygon from './Polygon'; import Polygon from './Polygon';
import Freehand from './Freehand'; import Freehand from './Freehand';
import ImageShape from './Image'; import ImageShape from './Image';
/** Loads Konva and display in function of their type */ /** Loads Konva and display in function of their type */
function ParentComponent({ function ParentComponent({
shapes, onShapeClick, selectedShapeId, activeTool, isMouseOverSave,
scale, width, height, onTransform, handleDragEnd, scale, width, height, onTransform, handleDragEnd,
isMouseOverSave,trview shapes, onShapeClick, selectedShapeId, activeTool,
}) { }) {
// TODO Simplify these state // TODO Simplify these state
const [selectedShape, setSelectedShape] = useState(null); const [selectedShape, setSelectedShape] = useState(null);
...@@ -54,11 +51,11 @@ function ParentComponent({ ...@@ -54,11 +51,11 @@ function ParentComponent({
<Rectangle <Rectangle
{...{ {...{
activeTool, activeTool,
handleDragEnd,
isSelected, isSelected,
onShapeClick: handleShapeClick, onShapeClick: handleShapeClick,
shape,
onTransform, onTransform,
handleDragEnd, shape,
}} }}
key={i} key={i}
/> />
...@@ -68,11 +65,11 @@ function ParentComponent({ ...@@ -68,11 +65,11 @@ function ParentComponent({
<TextNode <TextNode
{...{ {...{
activeTool, activeTool,
handleDragEnd,
isSelected, isSelected,
onShapeClick: handleShapeClick, onShapeClick: handleShapeClick,
shape,
onTransform, onTransform,
handleDragEnd, shape,
}} }}
key={i} key={i}
/> />
...@@ -82,11 +79,11 @@ function ParentComponent({ ...@@ -82,11 +79,11 @@ function ParentComponent({
<EllipseNode <EllipseNode
{...{ {...{
activeTool, activeTool,
handleDragEnd,
isSelected, isSelected,
onShapeClick: handleShapeClick, onShapeClick: handleShapeClick,
shape,
onTransform, onTransform,
handleDragEnd, shape,
}} }}
key={i} key={i}
/> />
...@@ -96,11 +93,11 @@ function ParentComponent({ ...@@ -96,11 +93,11 @@ function ParentComponent({
<Freehand <Freehand
{...{ {...{
activeTool, activeTool,
handleDragEnd,
isSelected, isSelected,
onShapeClick: handleShapeClick, onShapeClick: handleShapeClick,
shape,
onTransform, onTransform,
handleDragEnd, shape,
}} }}
key={i} key={i}
/> />
...@@ -110,11 +107,11 @@ function ParentComponent({ ...@@ -110,11 +107,11 @@ function ParentComponent({
<Polygon <Polygon
{...{ {...{
activeTool, activeTool,
handleDragEnd,
isSelected, isSelected,
onShapeClick: handleShapeClick, onShapeClick: handleShapeClick,
shape,
onTransform, onTransform,
handleDragEnd, shape,
}} }}
key={i} key={i}
/> />
...@@ -124,11 +121,11 @@ function ParentComponent({ ...@@ -124,11 +121,11 @@ function ParentComponent({
<ArrowNode <ArrowNode
{...{ {...{
activeTool, activeTool,
handleDragEnd,
isSelected, isSelected,
onShapeClick: handleShapeClick, onShapeClick: handleShapeClick,
shape,
onTransform, onTransform,
handleDragEnd, shape,
}} }}
key={i} key={i}
/> />
...@@ -138,18 +135,16 @@ function ParentComponent({ ...@@ -138,18 +135,16 @@ function ParentComponent({
<ImageShape <ImageShape
{...{ {...{
activeTool, activeTool,
handleDragEnd,
isSelected, isSelected,
onShapeClick: handleShapeClick, onShapeClick: handleShapeClick,
shape,
onTransform, onTransform,
handleDragEnd, shape,
src: shape.src, src: shape.src,
}} }}
key={i} key={i}
/> />
); );
default:
return null;
} }
})} })}
</Layer> </Layer>
...@@ -157,19 +152,15 @@ function ParentComponent({ ...@@ -157,19 +152,15 @@ function ParentComponent({
} }
ParentComponent.propTypes = { ParentComponent.propTypes = {
shapes: PropTypes.arrayOf(PropTypes.object).isRequired, activeTool: PropTypes.string.isRequired,
handleDragEnd: PropTypes.func.isRequired,
height: PropTypes.number.isRequired,
isMouseOverSave: PropTypes.bool.isRequired,
onShapeClick: PropTypes.func.isRequired, onShapeClick: PropTypes.func.isRequired,
selectedShapeIdProp: PropTypes.string, onTransform: PropTypes.func.isRequired,
activeTool: PropTypes.string, scale: PropTypes.number.isRequired,
scale: PropTypes.number, selectedShapeId: PropTypes.string.isRequired,
width: PropTypes.number, shapes: PropTypes.arrayOf(PropTypes.object).isRequired,
height: PropTypes.number, width: PropTypes.number.isRequired,
onTransform: PropTypes.func,
handleDragEnd: PropTypes.func,
};
ParentComponent.defaultProps = {
selectedShapeIdProp: null,
}; };
export default ParentComponent; export default ParentComponent;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment