Adjust pointer events for shapes
This commit is contained in:
parent
5d12a2fd54
commit
552c8457ef
8 changed files with 80 additions and 296 deletions
|
@ -19,7 +19,7 @@ function ExpandDef() {
|
||||||
const zoom = useSelector((s) => tld.getCurrentCamera(s.data).zoom)
|
const zoom = useSelector((s) => tld.getCurrentCamera(s.data).zoom)
|
||||||
return (
|
return (
|
||||||
<filter id="expand">
|
<filter id="expand">
|
||||||
<feMorphology operator="dilate" radius={1 / zoom} />
|
<feMorphology operator="dilate" radius={0.5 / zoom} />
|
||||||
</filter>
|
</filter>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,8 +127,9 @@ const TranslatedShape = memo(
|
||||||
}: TranslatedShapeProps) => {
|
}: TranslatedShapeProps) => {
|
||||||
const rGroup = useRef<SVGGElement>(null)
|
const rGroup = useRef<SVGGElement>(null)
|
||||||
const events = useShapeEvents(shape.id, isCurrentParent, rGroup)
|
const events = useShapeEvents(shape.id, isCurrentParent, rGroup)
|
||||||
|
const utils = getShapeUtils(shape)
|
||||||
|
|
||||||
const center = getShapeUtils(shape).getCenter(shape)
|
const center = utils.getCenter(shape)
|
||||||
const rotation = shape.rotation * (180 / Math.PI)
|
const rotation = shape.rotation * (180 / Math.PI)
|
||||||
const transform = `
|
const transform = `
|
||||||
rotate(${rotation}, ${center})
|
rotate(${rotation}, ${center})
|
||||||
|
@ -136,7 +137,13 @@ const TranslatedShape = memo(
|
||||||
`
|
`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g ref={rGroup} transform={transform} pointerEvents="all" {...events}>
|
<g
|
||||||
|
ref={rGroup}
|
||||||
|
id={shape.id}
|
||||||
|
transform={transform}
|
||||||
|
filter={isHovered ? 'url(#expand)' : 'none'}
|
||||||
|
{...events}
|
||||||
|
>
|
||||||
{isEditing && shape.type === ShapeType.Text ? (
|
{isEditing && shape.type === ShapeType.Text ? (
|
||||||
<EditingTextShape shape={shape} />
|
<EditingTextShape shape={shape} />
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -1,209 +0,0 @@
|
||||||
import React, { useRef, memo, useEffect } from 'react'
|
|
||||||
import state, { useSelector } from 'state'
|
|
||||||
import styled from 'styles'
|
|
||||||
import { getShapeUtils } from 'state/shape-utils'
|
|
||||||
import { deepCompareArrays } from 'utils'
|
|
||||||
import tld from 'utils/tld'
|
|
||||||
import useShapeEvents from 'hooks/useShapeEvents'
|
|
||||||
import useShape from 'hooks/useShape'
|
|
||||||
import vec from 'utils/vec'
|
|
||||||
import { getShapeStyle } from 'state/shape-styles'
|
|
||||||
import { Shape as _Shape } from 'types'
|
|
||||||
|
|
||||||
interface ShapeProps {
|
|
||||||
shape: _Shape
|
|
||||||
parent?: _Shape
|
|
||||||
}
|
|
||||||
|
|
||||||
function Shape({ shape, parent }: ShapeProps): JSX.Element {
|
|
||||||
const rGroup = useRef<SVGGElement>(null)
|
|
||||||
|
|
||||||
const { id, isHidden, children } = shape
|
|
||||||
const style = getShapeStyle(shape.style)
|
|
||||||
const { strokeWidth } = style
|
|
||||||
|
|
||||||
const center = getShapeUtils(shape).getCenter(shape)
|
|
||||||
const rotation = shape.rotation * (180 / Math.PI)
|
|
||||||
const parentPoint = parent?.point || [0, 0]
|
|
||||||
|
|
||||||
const transform = `
|
|
||||||
translate(${vec.neg(parentPoint)})
|
|
||||||
rotate(${rotation}, ${center})
|
|
||||||
translate(${shape.point})
|
|
||||||
`
|
|
||||||
|
|
||||||
const isCurrentParent = false
|
|
||||||
|
|
||||||
const events = useShapeEvents(shape.id, isCurrentParent, rGroup)
|
|
||||||
|
|
||||||
// From here on, not reactive—if we're here, we can trust that the
|
|
||||||
// shape in state is a shape with changes that we need to render.
|
|
||||||
|
|
||||||
const { isParent, isForeignObject, canStyleFill } = getShapeUtils(shape)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StyledGroup
|
|
||||||
id={id + '-group'}
|
|
||||||
ref={rGroup}
|
|
||||||
transform={transform}
|
|
||||||
isCurrentParent={isCurrentParent}
|
|
||||||
{...events}
|
|
||||||
>
|
|
||||||
{isForeignObject ? (
|
|
||||||
<ForeignObjectHover id={id} />
|
|
||||||
) : (
|
|
||||||
<EventSoak
|
|
||||||
as="use"
|
|
||||||
href={'#' + id}
|
|
||||||
strokeWidth={strokeWidth + 8}
|
|
||||||
variant={canStyleFill ? 'filled' : 'hollow'}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!isHidden &&
|
|
||||||
(isForeignObject ? (
|
|
||||||
<ForeignObjectRender id={id} />
|
|
||||||
) : (
|
|
||||||
<RealShape
|
|
||||||
id={id}
|
|
||||||
isParent={isParent}
|
|
||||||
shape={shape}
|
|
||||||
strokeWidth={strokeWidth}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
|
|
||||||
{isParent &&
|
|
||||||
children.map((shapeId) => (
|
|
||||||
<Shape
|
|
||||||
key={shapeId}
|
|
||||||
shape={tld.getShape(state.data, shapeId)}
|
|
||||||
parent={shape}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</StyledGroup>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default memo(Shape)
|
|
||||||
|
|
||||||
// function Def({ id }: { id: string }) {
|
|
||||||
// const shape = useShape(id)
|
|
||||||
// if (!shape) return null
|
|
||||||
// return getShapeUtils(shape).render(shape, { isEditing: false })
|
|
||||||
// }
|
|
||||||
|
|
||||||
interface RealShapeProps {
|
|
||||||
id: string
|
|
||||||
isParent: boolean
|
|
||||||
strokeWidth: number
|
|
||||||
shape: _Shape
|
|
||||||
}
|
|
||||||
|
|
||||||
const RealShape = memo(
|
|
||||||
function RealShape({ shape }: RealShapeProps) {
|
|
||||||
return getShapeUtils(shape).render(shape, { isEditing: false })
|
|
||||||
},
|
|
||||||
(prev, next) => {
|
|
||||||
return (
|
|
||||||
prev.shape &&
|
|
||||||
next.shape &&
|
|
||||||
next.shape !== prev.shape &&
|
|
||||||
getShapeUtils(next.shape).shouldRender(next.shape, prev.shape)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const ForeignObjectHover = memo(function ForeignObjectHover({
|
|
||||||
id,
|
|
||||||
}: {
|
|
||||||
id: string
|
|
||||||
}) {
|
|
||||||
const size = useSelector((s) => {
|
|
||||||
const shape = tld.getPage(s.data).shapes[id]
|
|
||||||
if (shape === undefined) return [0, 0]
|
|
||||||
const bounds = getShapeUtils(shape).getBounds(shape)
|
|
||||||
|
|
||||||
return [bounds.width, bounds.height]
|
|
||||||
}, deepCompareArrays)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<EventSoak
|
|
||||||
as="rect"
|
|
||||||
width={size[0]}
|
|
||||||
height={size[1]}
|
|
||||||
strokeWidth={1.5}
|
|
||||||
variant={'ghost'}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
const ForeignObjectRender = memo(function ForeignObjectRender({
|
|
||||||
id,
|
|
||||||
}: {
|
|
||||||
id: string
|
|
||||||
}) {
|
|
||||||
const shape = useShape(id)
|
|
||||||
|
|
||||||
const rFocusable = useRef<HTMLTextAreaElement>(null)
|
|
||||||
|
|
||||||
const isEditing = useSelector((s) => s.data.editingId === id)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isEditing) {
|
|
||||||
setTimeout(() => {
|
|
||||||
const elm = rFocusable.current
|
|
||||||
if (!elm) return
|
|
||||||
elm.focus()
|
|
||||||
}, 0)
|
|
||||||
}
|
|
||||||
}, [isEditing])
|
|
||||||
|
|
||||||
if (shape === undefined) return null
|
|
||||||
|
|
||||||
return getShapeUtils(shape).render(shape, { isEditing, ref: rFocusable })
|
|
||||||
})
|
|
||||||
|
|
||||||
const EventSoak = styled('use', {
|
|
||||||
opacity: 0,
|
|
||||||
strokeLinecap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
variants: {
|
|
||||||
variant: {
|
|
||||||
ghost: {
|
|
||||||
pointerEvents: 'all',
|
|
||||||
filter: 'none',
|
|
||||||
opacity: 0,
|
|
||||||
},
|
|
||||||
hollow: {
|
|
||||||
pointerEvents: 'stroke',
|
|
||||||
},
|
|
||||||
filled: {
|
|
||||||
pointerEvents: 'all',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const StyledGroup = styled('g', {
|
|
||||||
outline: 'none',
|
|
||||||
|
|
||||||
'& > *[data-shy=true]': {
|
|
||||||
opacity: 0,
|
|
||||||
},
|
|
||||||
|
|
||||||
'&:hover': {
|
|
||||||
'& > *[data-shy=true]': {
|
|
||||||
opacity: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
variants: {
|
|
||||||
isCurrentParent: {
|
|
||||||
true: {
|
|
||||||
'& > *[data-shy=true]': {
|
|
||||||
opacity: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
|
@ -7,7 +7,6 @@ import {
|
||||||
getBoundsFromPoints,
|
getBoundsFromPoints,
|
||||||
translateBounds,
|
translateBounds,
|
||||||
pointInBounds,
|
pointInBounds,
|
||||||
pointInCircle,
|
|
||||||
circleFromThreePoints,
|
circleFromThreePoints,
|
||||||
isAngleBetween,
|
isAngleBetween,
|
||||||
getPerfectDashProps,
|
getPerfectDashProps,
|
||||||
|
@ -102,8 +101,8 @@ const arrow = registerShapeUtils<ArrowShape>({
|
||||||
return shape.handles !== prev.handles || shape.style !== prev.style
|
return shape.handles !== prev.handles || shape.style !== prev.style
|
||||||
},
|
},
|
||||||
|
|
||||||
render(shape, { isHovered }) {
|
render(shape) {
|
||||||
const { id, bend, handles, style } = shape
|
const { bend, handles, style } = shape
|
||||||
const { start, end, bend: _bend } = handles
|
const { start, end, bend: _bend } = handles
|
||||||
|
|
||||||
const isStraightLine =
|
const isStraightLine =
|
||||||
|
@ -146,11 +145,11 @@ const arrow = registerShapeUtils<ArrowShape>({
|
||||||
<path
|
<path
|
||||||
d={path}
|
d={path}
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="transparent"
|
|
||||||
strokeWidth={Math.max(8, strokeWidth * 2)}
|
strokeWidth={Math.max(8, strokeWidth * 2)}
|
||||||
strokeDasharray="none"
|
strokeDasharray="none"
|
||||||
strokeDashoffset="none"
|
strokeDashoffset="none"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={path}
|
d={path}
|
||||||
|
@ -160,6 +159,7 @@ const arrow = registerShapeUtils<ArrowShape>({
|
||||||
strokeDasharray={strokeDasharray}
|
strokeDasharray={strokeDasharray}
|
||||||
strokeDashoffset={strokeDashoffset}
|
strokeDashoffset={strokeDashoffset}
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -206,6 +206,7 @@ const arrow = registerShapeUtils<ArrowShape>({
|
||||||
strokeDasharray="none"
|
strokeDasharray="none"
|
||||||
strokeDashoffset="none"
|
strokeDashoffset="none"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d={path}
|
d={path}
|
||||||
|
@ -215,6 +216,7 @@ const arrow = registerShapeUtils<ArrowShape>({
|
||||||
strokeDasharray={strokeDasharray}
|
strokeDasharray={strokeDasharray}
|
||||||
strokeDashoffset={strokeDashoffset}
|
strokeDashoffset={strokeDashoffset}
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -223,7 +225,7 @@ const arrow = registerShapeUtils<ArrowShape>({
|
||||||
const sw = strokeWidth * 1.618
|
const sw = strokeWidth * 1.618
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g id={id} filter={isHovered ? 'url(#expand)' : 'none'}>
|
<g pointerEvents="all">
|
||||||
{shaftPath}
|
{shaftPath}
|
||||||
{shape.decorations.start === Decoration.Arrow && (
|
{shape.decorations.start === Decoration.Arrow && (
|
||||||
<path
|
<path
|
||||||
|
@ -235,6 +237,7 @@ const arrow = registerShapeUtils<ArrowShape>({
|
||||||
strokeDasharray="none"
|
strokeDasharray="none"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
|
pointerEvents="stroke"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{shape.decorations.end === Decoration.Arrow && (
|
{shape.decorations.end === Decoration.Arrow && (
|
||||||
|
@ -247,6 +250,7 @@ const arrow = registerShapeUtils<ArrowShape>({
|
||||||
strokeDasharray="none"
|
strokeDasharray="none"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
|
pointerEvents="stroke"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</g>
|
</g>
|
||||||
|
@ -308,21 +312,8 @@ const arrow = registerShapeUtils<ArrowShape>({
|
||||||
return vec.add(shape.point, vec.med(start.point, end.point))
|
return vec.add(shape.point, vec.med(start.point, end.point))
|
||||||
},
|
},
|
||||||
|
|
||||||
hitTest(shape, point) {
|
hitTest() {
|
||||||
const { start, end } = shape.handles
|
return true
|
||||||
if (shape.bend === 0) {
|
|
||||||
return (
|
|
||||||
vec.distanceToLineSegment(
|
|
||||||
start.point,
|
|
||||||
end.point,
|
|
||||||
vec.sub(point, shape.point)
|
|
||||||
) < 4
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const [cx, cy, r] = getCtp(shape)
|
|
||||||
|
|
||||||
return !pointInCircle(point, vec.add(shape.point, [cx, cy]), r - 4)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
hitTestBounds(this, shape, brushBounds) {
|
hitTestBounds(this, shape, brushBounds) {
|
||||||
|
|
|
@ -41,13 +41,14 @@ const draw = registerShapeUtils<DrawShape>({
|
||||||
},
|
},
|
||||||
|
|
||||||
render(shape, { isHovered }) {
|
render(shape, { isHovered }) {
|
||||||
const { id, points, style } = shape
|
const { points, style } = shape
|
||||||
|
|
||||||
const styles = getShapeStyle(style)
|
const styles = getShapeStyle(style)
|
||||||
|
|
||||||
const strokeWidth = +styles.strokeWidth
|
const strokeWidth = +styles.strokeWidth
|
||||||
|
|
||||||
const shouldFill =
|
const shouldFill =
|
||||||
|
style.isFilled &&
|
||||||
points.length > 3 &&
|
points.length > 3 &&
|
||||||
vec.dist(points[0], points[points.length - 1]) < +styles.strokeWidth * 2
|
vec.dist(points[0], points[points.length - 1]) < +styles.strokeWidth * 2
|
||||||
|
|
||||||
|
@ -58,11 +59,11 @@ const draw = registerShapeUtils<DrawShape>({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<circle
|
<circle
|
||||||
id={id}
|
|
||||||
r={strokeWidth * 0.618}
|
r={strokeWidth * 0.618}
|
||||||
fill={styles.stroke}
|
fill={styles.stroke}
|
||||||
stroke={styles.stroke}
|
stroke={styles.stroke}
|
||||||
strokeWidth={sw}
|
strokeWidth={sw}
|
||||||
|
pointerEvents="all"
|
||||||
filter={isHovered ? 'url(#expand)' : 'none'}
|
filter={isHovered ? 'url(#expand)' : 'none'}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -80,15 +81,15 @@ const draw = registerShapeUtils<DrawShape>({
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g id={id}>
|
<>
|
||||||
{shouldFill && (
|
{shouldFill && (
|
||||||
<path
|
<path
|
||||||
d={polygonPathData}
|
d={polygonPathData}
|
||||||
strokeWidth="0"
|
|
||||||
stroke="none"
|
stroke="none"
|
||||||
fill={styles.fill}
|
fill={styles.fill}
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
|
pointerEvents="fill"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<path
|
<path
|
||||||
|
@ -98,9 +99,10 @@ const draw = registerShapeUtils<DrawShape>({
|
||||||
strokeWidth={strokeWidth}
|
strokeWidth={strokeWidth}
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
|
pointerEvents="all"
|
||||||
filter={isHovered ? 'url(#expand)' : 'none'}
|
filter={isHovered ? 'url(#expand)' : 'none'}
|
||||||
/>
|
/>
|
||||||
</g>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,29 +131,29 @@ const draw = registerShapeUtils<DrawShape>({
|
||||||
const sw = strokeWidth * 1.618
|
const sw = strokeWidth * 1.618
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g id={id}>
|
<>
|
||||||
{style.dash !== DashStyle.Solid && (
|
|
||||||
<path
|
|
||||||
d={path}
|
|
||||||
fill="transparent"
|
|
||||||
stroke="transparent"
|
|
||||||
strokeWidth={strokeWidth * 2}
|
|
||||||
strokeLinejoin="round"
|
|
||||||
strokeLinecap="round"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<path
|
<path
|
||||||
d={path}
|
d={path}
|
||||||
fill={shouldFill ? styles.fill : 'none'}
|
fill={shouldFill ? styles.fill : 'none'}
|
||||||
|
stroke="transparent"
|
||||||
|
strokeWidth={Math.min(4, strokeWidth * 2)}
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeLinecap="round"
|
||||||
|
pointerEvents={shouldFill ? 'all' : 'stroke'}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d={path}
|
||||||
|
fill="transparent"
|
||||||
stroke={styles.stroke}
|
stroke={styles.stroke}
|
||||||
strokeWidth={sw}
|
strokeWidth={sw}
|
||||||
strokeDasharray={strokeDasharray}
|
strokeDasharray={strokeDasharray}
|
||||||
strokeDashoffset={strokeDashoffset}
|
strokeDashoffset={strokeDashoffset}
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
|
pointerEvents="stroke"
|
||||||
filter={isHovered ? 'url(#expand)' : 'none'}
|
filter={isHovered ? 'url(#expand)' : 'none'}
|
||||||
/>
|
/>
|
||||||
</g>
|
</>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -174,13 +176,8 @@ const draw = registerShapeUtils<DrawShape>({
|
||||||
return getBoundsCenter(this.getBounds(shape))
|
return getBoundsCenter(this.getBounds(shape))
|
||||||
},
|
},
|
||||||
|
|
||||||
hitTest(shape, point) {
|
hitTest() {
|
||||||
const pt = vec.sub(point, shape.point)
|
return true
|
||||||
const min = +getShapeStyle(shape.style).strokeWidth
|
|
||||||
return shape.points.some(
|
|
||||||
(curr, i) =>
|
|
||||||
i > 0 && vec.distanceToLineSegment(shape.points[i - 1], curr, pt) < min
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
hitTestBounds(this, shape, brushBounds) {
|
hitTestBounds(this, shape, brushBounds) {
|
||||||
|
|
|
@ -58,16 +58,16 @@ const ellipse = registerShapeUtils<EllipseShape>({
|
||||||
const path = pathCache.get(shape)
|
const path = pathCache.get(shape)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g id={id}>
|
<g id={id} pointerEvents={style.isFilled ? 'all' : 'stroke'}>
|
||||||
{style.isFilled && (
|
{style.isFilled && (
|
||||||
<ellipse
|
<ellipse
|
||||||
id={id}
|
|
||||||
cx={radiusX}
|
cx={radiusX}
|
||||||
cy={radiusY}
|
cy={radiusY}
|
||||||
rx={rx}
|
rx={rx}
|
||||||
ry={ry}
|
ry={ry}
|
||||||
stroke="none"
|
stroke="none"
|
||||||
fill={styles.fill}
|
fill={styles.fill}
|
||||||
|
pointerEvents="fill"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<path
|
<path
|
||||||
|
@ -75,6 +75,7 @@ const ellipse = registerShapeUtils<EllipseShape>({
|
||||||
fill={styles.stroke}
|
fill={styles.stroke}
|
||||||
stroke={styles.stroke}
|
stroke={styles.stroke}
|
||||||
strokeWidth={strokeWidth}
|
strokeWidth={strokeWidth}
|
||||||
|
pointerEvents="all"
|
||||||
filter={isHovered ? 'url(#expand)' : 'none'}
|
filter={isHovered ? 'url(#expand)' : 'none'}
|
||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
|
@ -97,7 +98,6 @@ const ellipse = registerShapeUtils<EllipseShape>({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ellipse
|
<ellipse
|
||||||
id={id}
|
|
||||||
cx={radiusX}
|
cx={radiusX}
|
||||||
cy={radiusY}
|
cy={radiusY}
|
||||||
rx={rx}
|
rx={rx}
|
||||||
|
@ -107,6 +107,7 @@ const ellipse = registerShapeUtils<EllipseShape>({
|
||||||
strokeWidth={sw}
|
strokeWidth={sw}
|
||||||
strokeDasharray={strokeDasharray}
|
strokeDasharray={strokeDasharray}
|
||||||
strokeDashoffset={strokeDashoffset}
|
strokeDashoffset={strokeDashoffset}
|
||||||
|
pointerEvents={style.isFilled ? 'all' : 'stroke'}
|
||||||
filter={isHovered ? 'url(#expand)' : 'none'}
|
filter={isHovered ? 'url(#expand)' : 'none'}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
|
@ -28,19 +28,20 @@ const polyline = registerShapeUtils<PolylineShape>({
|
||||||
shouldRender(shape, prev) {
|
shouldRender(shape, prev) {
|
||||||
return shape.points !== prev.points || shape.style !== prev.style
|
return shape.points !== prev.points || shape.style !== prev.style
|
||||||
},
|
},
|
||||||
render(shape, { isHovered }) {
|
render(shape) {
|
||||||
const { id, points } = shape
|
const { points, style } = shape
|
||||||
|
|
||||||
const styles = getShapeStyle(shape.style)
|
const styles = getShapeStyle(style)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<polyline
|
<polyline
|
||||||
id={id}
|
|
||||||
points={points.toString()}
|
points={points.toString()}
|
||||||
stroke={styles.stroke}
|
stroke={styles.stroke}
|
||||||
strokeWidth={styles.strokeWidth}
|
strokeWidth={styles.strokeWidth * 1.618}
|
||||||
fill={shape.style.isFilled ? styles.fill : 'none'}
|
fill={shape.style.isFilled ? styles.fill : 'none'}
|
||||||
filter={isHovered ? 'url(#expand)' : 'none'}
|
pointerEvents={style.isFilled ? 'all' : 'stroke'}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -62,19 +63,8 @@ const polyline = registerShapeUtils<PolylineShape>({
|
||||||
return [bounds.minX + bounds.width / 2, bounds.minY + bounds.height / 2]
|
return [bounds.minX + bounds.width / 2, bounds.minY + bounds.height / 2]
|
||||||
},
|
},
|
||||||
|
|
||||||
hitTest(shape, point) {
|
hitTest() {
|
||||||
const pt = vec.sub(point, shape.point)
|
return true
|
||||||
let prev = shape.points[0]
|
|
||||||
|
|
||||||
for (let i = 1; i < shape.points.length; i++) {
|
|
||||||
const curr = shape.points[i]
|
|
||||||
if (vec.distanceToLineSegment(prev, curr, pt) < 4) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
prev = curr
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
},
|
},
|
||||||
|
|
||||||
hitTestBounds(this, shape, brushBounds) {
|
hitTestBounds(this, shape, brushBounds) {
|
||||||
|
@ -126,7 +116,7 @@ const polyline = registerShapeUtils<PolylineShape>({
|
||||||
|
|
||||||
canTransform: true,
|
canTransform: true,
|
||||||
canChangeAspectRatio: true,
|
canChangeAspectRatio: true,
|
||||||
canStyleFill: false,
|
canStyleFill: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
export default polyline
|
export default polyline
|
||||||
|
|
|
@ -39,26 +39,29 @@ const rectangle = registerShapeUtils<RectangleShape>({
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g id={id}>
|
<>
|
||||||
<rect
|
{style.isFilled && (
|
||||||
rx={radius}
|
<rect
|
||||||
ry={radius}
|
rx={radius}
|
||||||
x={+styles.strokeWidth / 2}
|
ry={radius}
|
||||||
y={+styles.strokeWidth / 2}
|
x={+styles.strokeWidth / 2}
|
||||||
width={Math.max(0, size[0] - strokeWidth)}
|
y={+styles.strokeWidth / 2}
|
||||||
height={Math.max(0, size[1] - strokeWidth)}
|
width={Math.max(0, size[0] - strokeWidth)}
|
||||||
strokeWidth={0}
|
height={Math.max(0, size[1] - strokeWidth)}
|
||||||
fill={styles.fill}
|
strokeWidth={0}
|
||||||
stroke={styles.stroke}
|
fill={styles.fill}
|
||||||
/>
|
stroke={styles.stroke}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<path
|
<path
|
||||||
d={pathData}
|
d={pathData}
|
||||||
fill={styles.stroke}
|
fill={styles.stroke}
|
||||||
stroke={styles.stroke}
|
stroke={styles.stroke}
|
||||||
strokeWidth={styles.strokeWidth}
|
strokeWidth={styles.strokeWidth}
|
||||||
filter={isHovered ? 'url(#expand)' : 'none'}
|
filter={isHovered ? 'url(#expand)' : 'none'}
|
||||||
|
pointerEvents={style.isFilled ? 'all' : 'stroke'}
|
||||||
/>
|
/>
|
||||||
</g>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,17 +101,21 @@ const rectangle = registerShapeUtils<RectangleShape>({
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g id={id}>
|
<>
|
||||||
<rect
|
<rect
|
||||||
x={sw / 2}
|
x={sw / 2}
|
||||||
y={sw / 2}
|
y={sw / 2}
|
||||||
width={w}
|
width={w}
|
||||||
height={h}
|
height={h}
|
||||||
fill={styles.fill}
|
fill={styles.fill}
|
||||||
stroke="none"
|
stroke="transparent"
|
||||||
|
strokeWidth={sw}
|
||||||
|
pointerEvents={style.isFilled ? 'all' : 'stroke'}
|
||||||
/>
|
/>
|
||||||
<g filter={isHovered ? 'url(#expand)' : 'none'}>{paths}</g>
|
<g filter={isHovered ? 'url(#expand)' : 'none'} pointerEvents="stroke">
|
||||||
</g>
|
{paths}
|
||||||
|
</g>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue