Continues on drawing / rotation
This commit is contained in:
parent
79c254a938
commit
c95c54dae6
11 changed files with 311 additions and 324 deletions
|
@ -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} />
|
||||
|
|
|
@ -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', {})
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -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} />
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue