Files
grungnet/src/components/map/MapNotes.tsx

171 lines
4.2 KiB
TypeScript
Raw Normal View History

2021-07-17 12:48:04 +10:00
import { useState, useEffect, useRef } from "react";
2020-11-03 17:15:39 +11:00
import shortid from "shortid";
import { Group } from "react-konva";
2021-07-17 12:48:04 +10:00
import Konva from "konva";
2020-11-03 16:21:39 +11:00
2021-03-12 11:02:58 +11:00
import { useInteractionEmitter } from "../../contexts/MapInteractionContext";
import { useMapStage } from "../../contexts/MapStageContext";
import { useUserId } from "../../contexts/UserIdContext";
2020-11-03 16:21:39 +11:00
import Vector2 from "../../helpers/Vector2";
import { getRelativePointerPosition } from "../../helpers/konva";
import useGridSnapping from "../../hooks/useGridSnapping";
2020-11-03 16:21:39 +11:00
2020-11-05 14:41:33 +11:00
import Note from "../note/Note";
2020-11-03 17:15:39 +11:00
2021-07-17 12:48:04 +10:00
import { Map } from "../../types/Map";
import { Note as NoteType } from "../../types/Note";
import {
NoteAddEventHander,
NoteChangeEventHandler,
NoteDragEventHandler,
NoteMenuOpenEventHandler,
} from "../../types/Events";
2020-11-03 16:21:39 +11:00
const defaultNoteSize = 2;
2021-07-17 12:48:04 +10:00
type MapNoteProps = {
2021-07-17 17:25:41 +10:00
map: Map | null;
2021-07-17 12:48:04 +10:00
active: boolean;
onNoteAdd: NoteAddEventHander;
onNoteChange: NoteChangeEventHandler;
notes: NoteType[];
onNoteMenuOpen: NoteMenuOpenEventHandler;
draggable: boolean;
onNoteDragStart: NoteDragEventHandler;
onNoteDragEnd: NoteDragEventHandler;
fadeOnHover: boolean;
};
2020-11-03 17:15:39 +11:00
function MapNotes({
map,
active,
onNoteAdd,
2020-11-04 15:03:34 +11:00
onNoteChange,
2020-11-03 17:15:39 +11:00
notes,
2020-11-04 15:03:34 +11:00
onNoteMenuOpen,
2020-11-05 12:28:28 +11:00
draggable,
2020-11-05 14:41:33 +11:00
onNoteDragStart,
onNoteDragEnd,
2021-01-28 16:26:28 +11:00
fadeOnHover,
2021-07-17 12:48:04 +10:00
}: MapNoteProps) {
2021-03-12 11:02:58 +11:00
const interactionEmitter = useInteractionEmitter();
const userId = useUserId();
const mapStageRef = useMapStage();
2020-11-03 16:21:39 +11:00
const [isBrushDown, setIsBrushDown] = useState(false);
2021-07-17 12:48:04 +10:00
const [noteData, setNoteData] = useState<NoteType | null>(null);
2020-11-03 16:21:39 +11:00
2021-07-17 12:48:04 +10:00
const creatingNoteRef = useRef<Konva.Group>(null);
2020-11-04 15:03:34 +11:00
const snapPositionToGrid = useGridSnapping();
2020-11-03 16:21:39 +11:00
useEffect(() => {
if (!active) {
return;
}
const mapStage = mapStageRef.current;
function getBrushPosition() {
2021-07-17 12:48:04 +10:00
if (!mapStage) {
return;
}
const mapImage = mapStage.findOne("#mapImage");
let position = getRelativePointerPosition(mapImage);
2021-07-17 12:48:04 +10:00
if (!position) {
return;
}
2021-07-17 17:25:41 +10:00
if (map?.snapToGrid) {
position = snapPositionToGrid(position);
}
return Vector2.divide(position, {
x: mapImage.width(),
y: mapImage.height(),
});
}
function handleBrushDown() {
const brushPosition = getBrushPosition();
2021-07-17 12:48:04 +10:00
if (!brushPosition || !userId) {
return;
}
2020-11-05 12:28:28 +11:00
setNoteData({
x: brushPosition.x,
y: brushPosition.y,
size: defaultNoteSize,
text: "",
id: shortid.generate(),
lastModified: Date.now(),
lastModifiedBy: userId,
visible: true,
locked: false,
color: "yellow",
2021-01-25 10:03:20 +11:00
textOnly: false,
2020-11-05 12:28:28 +11:00
});
setIsBrushDown(true);
2020-11-03 16:21:39 +11:00
}
function handleBrushMove() {
2020-11-27 12:23:57 +11:00
if (noteData) {
const brushPosition = getBrushPosition();
2021-07-17 12:48:04 +10:00
if (!brushPosition) {
return;
}
setNoteData((prev) => {
if (!prev) {
return prev;
}
return {
...prev,
x: brushPosition.x,
y: brushPosition.y,
};
});
2020-11-27 12:23:57 +11:00
setIsBrushDown(true);
}
2020-11-03 16:21:39 +11:00
}
function handleBrushUp() {
2021-07-17 12:48:04 +10:00
if (noteData && creatingNoteRef.current) {
2020-11-04 15:03:34 +11:00
onNoteAdd(noteData);
onNoteMenuOpen(noteData.id, creatingNoteRef.current);
}
2020-11-03 17:15:39 +11:00
setNoteData(null);
2020-11-03 16:21:39 +11:00
setIsBrushDown(false);
}
2021-07-17 12:48:04 +10:00
interactionEmitter?.on("dragStart", handleBrushDown);
interactionEmitter?.on("drag", handleBrushMove);
interactionEmitter?.on("dragEnd", handleBrushUp);
2020-11-03 16:21:39 +11:00
return () => {
2021-07-17 12:48:04 +10:00
interactionEmitter?.off("dragStart", handleBrushDown);
interactionEmitter?.off("drag", handleBrushMove);
interactionEmitter?.off("dragEnd", handleBrushUp);
2020-11-03 16:21:39 +11:00
};
});
return (
<Group>
2020-11-03 17:15:39 +11:00
{notes.map((note) => (
2020-11-05 14:41:33 +11:00
<Note
2020-11-04 15:03:34 +11:00
note={note}
map={map}
key={note.id}
onNoteMenuOpen={onNoteMenuOpen}
2020-11-05 15:30:22 +11:00
draggable={draggable && !note.locked}
2020-11-04 15:03:34 +11:00
onNoteChange={onNoteChange}
2020-11-05 14:41:33 +11:00
onNoteDragStart={onNoteDragStart}
onNoteDragEnd={onNoteDragEnd}
2021-01-28 16:26:28 +11:00
fadeOnHover={fadeOnHover}
2020-11-04 15:03:34 +11:00
/>
2020-11-03 17:15:39 +11:00
))}
2020-11-04 15:03:34 +11:00
<Group ref={creatingNoteRef}>
2021-07-17 12:48:04 +10:00
{isBrushDown && noteData && <Note note={noteData} map={map} />}
2020-11-04 15:03:34 +11:00
</Group>
2020-11-03 16:21:39 +11:00
</Group>
);
}
export default MapNotes;