Continues on drawing / rotation

This commit is contained in:
Steve Ruiz 2021-05-28 17:25:43 +01:00
parent 79c254a938
commit c95c54dae6
11 changed files with 311 additions and 324 deletions

View file

@ -7,7 +7,6 @@ import CenterHandle from './center-handle'
import CornerHandle from './corner-handle'
import EdgeHandle from './edge-handle'
import RotateHandle from './rotate-handle'
import Selected from '../selected'
export default function Bounds() {
const isBrushing = useSelector((s) => s.isIn('brushSelecting'))
@ -32,7 +31,6 @@ export default function Bounds() {
${(bounds.minY + bounds.maxY) / 2})
translate(${bounds.minX},${bounds.minY})`}
>
<Selected bounds={bounds} />
<CenterHandle bounds={bounds} />
<EdgeHandle size={size} bounds={bounds} edge={Edge.Top} />
<EdgeHandle size={size} bounds={bounds} edge={Edge.Right} />

View file

@ -1,5 +1,5 @@
import styled from 'styles'
import state from 'state'
import state, { useSelector } from 'state'
import inputs from 'state/inputs'
import React, { useCallback, useRef } from 'react'
import useZoomEvents from 'hooks/useZoomEvents'
@ -9,6 +9,7 @@ import Page from './page'
import Brush from './brush'
import Bounds from './bounds/bounding-box'
import BoundsBg from './bounds/bounds-bg'
import Selected from './selected'
export default function Canvas() {
const rCanvas = useRef<SVGSVGElement>(null)
@ -17,6 +18,8 @@ export default function Canvas() {
useCamera(rGroup)
const isReady = useSelector((s) => s.isIn('ready'))
const handlePointerDown = useCallback((e: React.PointerEvent) => {
rCanvas.current.setPointerCapture(e.pointerId)
state.send('POINTED_CANVAS', inputs.pointerDown(e, 'canvas'))
@ -40,12 +43,15 @@ export default function Canvas() {
onPointerUp={handlePointerUp}
>
<Defs />
<MainGroup ref={rGroup}>
<BoundsBg />
<Page />
<Bounds />
<Brush />
</MainGroup>
{isReady && (
<g ref={rGroup}>
<BoundsBg />
<Page />
<Bounds />
<Selected />
<Brush />
</g>
)}
</MainSVG>
)
}
@ -63,5 +69,3 @@ const MainSVG = styled('svg', {
userSelect: 'none',
},
})
const MainGroup = styled('g', {})

View file

@ -1,6 +1,6 @@
import { getShapeUtils } from "lib/shape-utils"
import { useSelector } from "state"
import { deepCompareArrays, getPage } from "utils/utils"
import { getShapeUtils } from 'lib/shape-utils'
import { useSelector } from 'state'
import { deepCompareArrays, getPage } from 'utils/utils'
export default function Defs() {
const currentPageShapeIds = useSelector(({ data }) => {
@ -20,6 +20,6 @@ export default function Defs() {
export function Def({ id }: { id: string }) {
const shape = useSelector(({ data }) => getPage(data).shapes[id])
if (!shape) return null
return getShapeUtils(shape).render(shape)
}

View file

@ -1,48 +1,48 @@
import styled from 'styles'
import { useSelector } from 'state'
import {
deepCompareArrays,
getBoundsCenter,
getPage,
getSelectedShapes,
} from 'utils/utils'
import * as vec from 'utils/vec'
import { deepCompareArrays, getPage } from 'utils/utils'
import { getShapeUtils } from 'lib/shape-utils'
import { Bounds } from 'types'
import useShapeEvents from 'hooks/useShapeEvents'
import { useRef } from 'react'
export default function Selected({ bounds }: { bounds: Bounds }) {
export default function Selected() {
const currentPageShapeIds = useSelector(({ data }) => {
return Array.from(data.selectedIds.values())
}, deepCompareArrays)
const isSelecting = useSelector((s) => s.isIn('selecting'))
if (!isSelecting) return null
return (
<g>
{currentPageShapeIds.map((id) => (
<ShapeOutline key={id} id={id} bounds={bounds} />
<ShapeOutline key={id} id={id} />
))}
</g>
)
}
export function ShapeOutline({ id, bounds }: { id: string; bounds: Bounds }) {
export function ShapeOutline({ id }: { id: string }) {
const rIndicator = useRef<SVGUseElement>(null)
const shape = useSelector(({ data }) => getPage(data).shapes[id])
const shapeBounds = getShapeUtils(shape).getBounds(shape)
const events = useShapeEvents(id, rIndicator)
if (!shape) return null
const transform = `
rotate(${shape.rotation * (180 / Math.PI)},
${getShapeUtils(shape).getCenter(shape)})
translate(${shape.point})`
return (
<Indicator
ref={rIndicator}
as="use"
href={'#' + id}
transform={`rotate(${shape.rotation * (180 / Math.PI)},${getBoundsCenter(
shapeBounds
)}) translate(${vec.sub(shape.point, [bounds.minX, bounds.minY])})`}
transform={transform}
{...events}
/>
)

View file

@ -1,10 +1,10 @@
import React, { useCallback, useRef, memo } from 'react'
import state, { useSelector } from 'state'
import inputs from 'state/inputs'
import React, { useRef, memo } from 'react'
import { useSelector } from 'state'
import styled from 'styles'
import { getShapeUtils } from 'lib/shape-utils'
import { getPage } from 'utils/utils'
import { ShapeStyles } from 'types'
import useShapeEvents from 'hooks/useShapeEvents'
function Shape({ id, isSelecting }: { id: string; isSelecting: boolean }) {
const isHovered = useSelector((state) => state.data.hoveredId === id)
@ -15,42 +15,7 @@ function Shape({ id, isSelecting }: { id: string; isSelecting: boolean }) {
const rGroup = useRef<SVGGElement>(null)
const handlePointerDown = useCallback(
(e: React.PointerEvent) => {
e.stopPropagation()
rGroup.current.setPointerCapture(e.pointerId)
state.send('POINTED_SHAPE', inputs.pointerDown(e, id))
},
[id]
)
const handlePointerUp = useCallback(
(e: React.PointerEvent) => {
e.stopPropagation()
rGroup.current.releasePointerCapture(e.pointerId)
state.send('STOPPED_POINTING', inputs.pointerUp(e))
},
[id]
)
const handlePointerEnter = useCallback(
(e: React.PointerEvent) => {
state.send('HOVERED_SHAPE', inputs.pointerEnter(e, id))
},
[id, shape]
)
const handlePointerMove = useCallback(
(e: React.PointerEvent) => {
state.send('MOVED_OVER_SHAPE', inputs.pointerEnter(e, id))
},
[id, shape]
)
const handlePointerLeave = useCallback(
() => state.send('UNHOVERED_SHAPE', { target: id }),
[id]
)
const events = useShapeEvents(id, rGroup)
// This is a problem with deleted shapes. The hooks in this component
// may sometimes run before the hook in the Page component, which means
@ -58,19 +23,18 @@ function Shape({ id, isSelecting }: { id: string; isSelecting: boolean }) {
// detects the change and pulls this component.
if (!shape) return null
const transform = `
rotate(${shape.rotation * (180 / Math.PI)},
${getShapeUtils(shape).getCenter(shape)})
translate(${shape.point})`
return (
<StyledGroup
ref={rGroup}
isHovered={isHovered}
isSelected={isSelected}
transform={`rotate(${shape.rotation * (180 / Math.PI)},${getShapeUtils(
shape
).getCenter(shape)}) translate(${shape.point})`}
onPointerDown={handlePointerDown}
onPointerUp={handlePointerUp}
onPointerEnter={handlePointerEnter}
onPointerLeave={handlePointerLeave}
onPointerMove={handlePointerMove}
transform={transform}
{...events}
>
{isSelecting && <HoverIndicator as="use" href={'#' + id} />}
<StyledShape id={id} style={shape.style} />