refactor(mobile): drawing mouse to pointer events, field colors and actions feedback, touch action

This commit is contained in:
enes 2024-09-03 10:14:43 +02:00
parent 757012399a
commit b20ffe6e87

View File

@ -9,7 +9,6 @@ import {
} from '@mui/material'
import styles from './style.module.scss'
import React, { useEffect, useState } from 'react'
import * as PDFJS from 'pdfjs-dist'
import { ProfileMetadata, User, UserRole } from '../../types'
import { MouseState, PdfPage, DrawnField, DrawTool } from '../../types/drawing'
import { truncate } from 'lodash'
@ -22,10 +21,10 @@ import { useScale } from '../../hooks/useScale'
import { AvatarIconButton } from '../UserAvatarIconButton'
import { LoadingSpinner } from '../LoadingSpinner'
PDFJS.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.mjs',
import.meta.url
).toString()
const DEFAULT_START_SIZE = {
width: 140,
height: 40
} as const
interface Props {
selectedFiles: File[]
@ -46,6 +45,8 @@ export const DrawPDFFields = (props: Props) => {
clicked: false
})
const [activeDrawField, setActiveDrawField] = useState<number>()
useEffect(() => {
if (selectedFiles) {
/**
@ -77,10 +78,12 @@ export const DrawPDFFields = (props: Props) => {
* Drawing events
*/
useEffect(() => {
window.addEventListener('mouseup', onMouseUp)
window.addEventListener('pointerup', handlePointerUp)
window.addEventListener('pointercancel', handlePointerUp)
return () => {
window.removeEventListener('mouseup', onMouseUp)
window.removeEventListener('pointerup', handlePointerUp)
window.removeEventListener('pointercancel', handlePointerUp)
}
}, [])
@ -96,10 +99,7 @@ export const DrawPDFFields = (props: Props) => {
* @param event Mouse event
* @param page PdfPage where press happened
*/
const onMouseDown = (
event: React.MouseEvent<HTMLDivElement>,
page: PdfPage
) => {
const handlePointerDown = (event: React.PointerEvent, page: PdfPage) => {
// Proceed only if left click
if (event.button !== 0) return
@ -112,8 +112,8 @@ export const DrawPDFFields = (props: Props) => {
const newField: DrawnField = {
left: to(page.width, mouseX),
top: to(page.width, mouseY),
width: 0,
height: 0,
width: event.pointerType === 'mouse' ? 0 : DEFAULT_START_SIZE.width,
height: event.pointerType === 'mouse' ? 0 : DEFAULT_START_SIZE.height,
counterpart: '',
type: selectedTool.identifier
}
@ -132,7 +132,7 @@ export const DrawPDFFields = (props: Props) => {
* Drawing is finished, resets all the variables used to draw
* @param event Mouse event
*/
const onMouseUp = () => {
const handlePointerUp = () => {
setMouseState((prev) => {
return {
...prev,
@ -144,16 +144,13 @@ export const DrawPDFFields = (props: Props) => {
}
/**
* After {@link onMouseDown} create an drawing element, this function gets called on every pixel moved
* After {@link handlePointerDown} create an drawing element, this function gets called on every pixel moved
* which alters the newly created drawing element, resizing it while mouse move
* @param event Mouse event
* @param page PdfPage where moving is happening
*/
const onMouseMove = (
event: React.MouseEvent<HTMLDivElement>,
page: PdfPage
) => {
if (mouseState.clicked && selectedTool) {
const handlePointerMove = (event: React.PointerEvent, page: PdfPage) => {
if (mouseState.clicked && selectedTool && event.pointerType === 'mouse') {
const lastElementIndex = page.drawnFields.length - 1
const lastDrawnField = page.drawnFields[lastElementIndex]
@ -187,9 +184,12 @@ export const DrawPDFFields = (props: Props) => {
* mouseY - offsetY
*
* @param event Mouse event
* @param drawnField Which we are moving
* @param drawnFieldIndex Which we are moving
*/
const onDrawnFieldMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {
const handleDrawnFieldPointerDown = (
event: React.PointerEvent,
drawnFieldIndex: number
) => {
event.stopPropagation()
// Proceed only if left click
@ -197,6 +197,7 @@ export const DrawPDFFields = (props: Props) => {
const drawingRectangleCoords = getMouseCoordinates(event)
setActiveDrawField(drawnFieldIndex)
setMouseState({
dragging: true,
clicked: false,
@ -212,8 +213,8 @@ export const DrawPDFFields = (props: Props) => {
* @param event Mouse event
* @param drawnField which we are moving
*/
const onDrawnFieldMouseMove = (
event: React.MouseEvent<HTMLDivElement>,
const handleDrawnFieldPointerMove = (
event: React.PointerEvent,
drawnField: DrawnField,
pageWidth: number
) => {
@ -228,8 +229,8 @@ export const DrawPDFFields = (props: Props) => {
let left = to(pageWidth, mouseX - coordsOffset.mouseX)
let top = to(pageWidth, mouseY - coordsOffset.mouseY)
const rightLimit = to(pageWidth, rect.width) - drawnField.width - 3
const bottomLimit = to(pageWidth, rect.height) - drawnField.height - 3
const rightLimit = to(pageWidth, rect.width) - drawnField.width
const bottomLimit = to(pageWidth, rect.height) - drawnField.height
if (left < 0) left = 0
if (top < 0) top = 0
@ -247,16 +248,17 @@ export const DrawPDFFields = (props: Props) => {
/**
* Fired when clicked on the resize handle, sets the state for a resize action
* @param event Mouse event
* @param drawnField which we are resizing
* @param drawnFieldIndex which we are resizing
*/
const onResizeHandleMouseDown = (
event: React.MouseEvent<HTMLSpanElement>
const handleResizePointerDown = (
event: React.PointerEvent,
drawnFieldIndex: number
) => {
// Proceed only if left click
if (event.button !== 0) return
event.stopPropagation()
setActiveDrawField(drawnFieldIndex)
setMouseState({
resizing: true
})
@ -267,8 +269,8 @@ export const DrawPDFFields = (props: Props) => {
* @param event Mouse event
* @param drawnField which we are resizing
*/
const onResizeHandleMouseMove = (
event: React.MouseEvent<HTMLSpanElement>,
const handleResizePointerMove = (
event: React.PointerEvent,
drawnField: DrawnField,
pageWidth: number
) => {
@ -298,8 +300,8 @@ export const DrawPDFFields = (props: Props) => {
* @param pdfPageIndex pdf page index
* @param drawnFileIndex drawn file index
*/
const onRemoveHandleMouseDown = (
event: React.MouseEvent<HTMLSpanElement>,
const handleRemovePointerDown = (
event: React.PointerEvent,
pdfFileIndex: number,
pdfPageIndex: number,
drawnFileIndex: number
@ -317,20 +319,18 @@ export const DrawPDFFields = (props: Props) => {
* so select can work properly
* @param event Mouse event
*/
const onUserSelectHandleMouseDown = (
event: React.MouseEvent<HTMLDivElement>
) => {
const handleUserSelectPointerDown = (event: React.PointerEvent) => {
event.stopPropagation()
}
/**
* Gets the mouse coordinates relative to a element in the `event` param
* @param event MouseEvent
* @param event PointerEvent
* @param customTarget mouse coordinates relative to this element, if not provided
* event.target will be used
*/
const getMouseCoordinates = (
event: React.MouseEvent<HTMLElement>,
event: React.PointerEvent,
customTarget?: HTMLElement | null
) => {
const target = customTarget ? customTarget : event.currentTarget
@ -346,7 +346,6 @@ export const DrawPDFFields = (props: Props) => {
rect
}
}
/**
* Renders the pdf pages and drawing elements
*/
@ -363,11 +362,11 @@ export const DrawPDFFields = (props: Props) => {
className={`image-wrapper ${styles.pdfImageWrapper} ${selectedTool ? styles.drawing : ''}`}
>
<img
onMouseMove={(event) => {
onMouseMove(event, page)
onPointerMove={(event) => {
handlePointerMove(event, page)
}}
onMouseDown={(event) => {
onMouseDown(event, page)
onPointerDown={(event) => {
handlePointerDown(event, page)
}}
draggable="false"
src={page.image}
@ -378,29 +377,52 @@ export const DrawPDFFields = (props: Props) => {
return (
<div
key={drawnFieldIndex}
onMouseDown={onDrawnFieldMouseDown}
onMouseMove={(event) => {
onDrawnFieldMouseMove(event, drawnField, page.width)
onPointerDown={(event) =>
handleDrawnFieldPointerDown(event, drawnFieldIndex)
}
onPointerMove={(event) => {
handleDrawnFieldPointerMove(event, drawnField, page.width)
}}
className={styles.drawingRectangle}
style={{
backgroundColor: drawnField.counterpart
? `#${npubToHex(drawnField.counterpart)?.substring(0, 6)}4b`
: undefined,
borderColor: drawnField.counterpart
? `#${npubToHex(drawnField.counterpart)?.substring(0, 6)}`
: undefined,
left: inPx(from(page.width, drawnField.left)),
top: inPx(from(page.width, drawnField.top)),
width: inPx(from(page.width, drawnField.width)),
height: inPx(from(page.width, drawnField.height)),
pointerEvents: mouseState.clicked ? 'none' : 'all'
pointerEvents: mouseState.clicked ? 'none' : 'all',
touchAction: 'none',
opacity:
mouseState.dragging &&
activeDrawField === drawnFieldIndex
? 0.8
: undefined
}}
>
<span
onMouseDown={onResizeHandleMouseDown}
onMouseMove={(event) => {
onResizeHandleMouseMove(event, drawnField, page.width)
onPointerDown={(event) =>
handleResizePointerDown(event, drawnFieldIndex)
}
onPointerMove={(event) => {
handleResizePointerMove(event, drawnField, page.width)
}}
className={styles.resizeHandle}
style={{
background:
mouseState.resizing &&
activeDrawField === drawnFieldIndex
? 'var(--primary-main)'
: undefined
}}
></span>
<span
onMouseDown={(event) => {
onRemoveHandleMouseDown(
onPointerDown={(event) => {
handleRemovePointerDown(
event,
fileIndex,
pageIndex,
@ -412,7 +434,7 @@ export const DrawPDFFields = (props: Props) => {
<Close fontSize="small" />
</span>
<div
onMouseDown={onUserSelectHandleMouseDown}
onPointerDown={handleUserSelectPointerDown}
className={styles.userSelect}
>
<FormControl fullWidth size="small">