perf improvements around selected / hovered shapes
This commit is contained in:
parent
2cfeea0449
commit
8ff8b87a9e
26 changed files with 643 additions and 612 deletions
|
@ -2,11 +2,9 @@ import * as React from 'react'
|
|||
import { Edge, Corner } from 'types'
|
||||
import { useSelector } from 'state'
|
||||
import {
|
||||
deepCompareArrays,
|
||||
getBoundsCenter,
|
||||
getCurrentCamera,
|
||||
getPage,
|
||||
getSelectedIds,
|
||||
getSelectedShapes,
|
||||
isMobile,
|
||||
} from 'utils'
|
||||
|
@ -24,25 +22,22 @@ export default function Bounds(): JSX.Element {
|
|||
|
||||
const bounds = useSelector((s) => s.values.selectedBounds)
|
||||
|
||||
const selectedIds = useSelector(
|
||||
(s) => Array.from(s.values.selectedIds.values()),
|
||||
deepCompareArrays
|
||||
)
|
||||
|
||||
const rotation = useSelector(({ data }) =>
|
||||
getSelectedIds(data).size === 1 ? getSelectedShapes(data)[0].rotation : 0
|
||||
const rotation = useSelector((s) =>
|
||||
s.values.selectedIds.length === 1
|
||||
? getSelectedShapes(s.data)[0].rotation
|
||||
: 0
|
||||
)
|
||||
|
||||
const isAllLocked = useSelector((s) => {
|
||||
const page = getPage(s.data)
|
||||
return selectedIds.every((id) => page.shapes[id]?.isLocked)
|
||||
return s.values.selectedIds.every((id) => page.shapes[id]?.isLocked)
|
||||
})
|
||||
|
||||
const isSingleHandles = useSelector((s) => {
|
||||
const page = getPage(s.data)
|
||||
return (
|
||||
selectedIds.length === 1 &&
|
||||
page.shapes[selectedIds[0]]?.handles !== undefined
|
||||
s.values.selectedIds.length === 1 &&
|
||||
page.shapes[s.values.selectedIds[0]]?.handles !== undefined
|
||||
)
|
||||
})
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { useRef } from 'react'
|
|||
import state, { useSelector } from 'state'
|
||||
import inputs from 'state/inputs'
|
||||
import styled from 'styles'
|
||||
import { deepCompareArrays, getPage } from 'utils'
|
||||
import { getPage } from 'utils'
|
||||
|
||||
function handlePointerDown(e: React.PointerEvent<SVGRectElement>) {
|
||||
if (!inputs.canAccept(e.pointerId)) return
|
||||
|
@ -31,28 +31,30 @@ export default function BoundsBg(): JSX.Element {
|
|||
|
||||
const isSelecting = useSelector((s) => s.isIn('selecting'))
|
||||
|
||||
const selectedIds = useSelector(
|
||||
(s) => Array.from(s.values.selectedIds.values()),
|
||||
deepCompareArrays
|
||||
)
|
||||
|
||||
const rotation = useSelector((s) => {
|
||||
const selectedIds = s.values.selectedIds
|
||||
|
||||
if (selectedIds.length === 1) {
|
||||
const { shapes } = getPage(s.data)
|
||||
const selected = Array.from(s.values.selectedIds.values())[0]
|
||||
return shapes[selected]?.rotation
|
||||
const selected = selectedIds[0]
|
||||
const page = getPage(s.data)
|
||||
|
||||
return page.shapes[selected]?.rotation
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
})
|
||||
|
||||
const isAllHandles = useSelector((s) => {
|
||||
const page = getPage(s.data)
|
||||
const selectedIds = Array.from(s.values.selectedIds.values())
|
||||
return (
|
||||
selectedIds.length === 1 &&
|
||||
page.shapes[selectedIds[0]]?.handles !== undefined
|
||||
)
|
||||
const selectedIds = s.values.selectedIds
|
||||
|
||||
if (selectedIds.length === 1) {
|
||||
const page = getPage(s.data)
|
||||
const selected = selectedIds[0]
|
||||
|
||||
return (
|
||||
selectedIds.length === 1 && page.shapes[selected]?.handles !== undefined
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
if (isAllHandles) return null
|
||||
|
|
|
@ -3,18 +3,14 @@ import { getShapeUtils } from 'state/shape-utils'
|
|||
import { useRef } from 'react'
|
||||
import { useSelector } from 'state'
|
||||
import styled from 'styles'
|
||||
import { deepCompareArrays, getPage } from 'utils'
|
||||
import { getPage } from 'utils'
|
||||
import vec from 'utils/vec'
|
||||
|
||||
export default function Handles(): JSX.Element {
|
||||
const selectedIds = useSelector(
|
||||
(s) => Array.from(s.values.selectedIds.values()),
|
||||
deepCompareArrays
|
||||
)
|
||||
|
||||
const shape = useSelector(
|
||||
({ data }) =>
|
||||
selectedIds.length === 1 && getPage(data).shapes[selectedIds[0]]
|
||||
(s) =>
|
||||
s.values.selectedIds.length === 1 &&
|
||||
getPage(s.data).shapes[s.values.selectedIds[0]]
|
||||
)
|
||||
|
||||
const isSelecting = useSelector((s) =>
|
||||
|
|
|
@ -13,6 +13,10 @@ import Handles from './bounds/handles'
|
|||
import useCanvasEvents from 'hooks/useCanvasEvents'
|
||||
import ContextMenu from './context-menu/context-menu'
|
||||
|
||||
function resetError() {
|
||||
null
|
||||
}
|
||||
|
||||
export default function Canvas(): JSX.Element {
|
||||
const rCanvas = useRef<SVGSVGElement>(null)
|
||||
const rGroup = useRef<SVGGElement>(null)
|
||||
|
@ -28,12 +32,7 @@ export default function Canvas(): JSX.Element {
|
|||
return (
|
||||
<ContextMenu>
|
||||
<MainSVG ref={rCanvas} {...events}>
|
||||
<ErrorBoundary
|
||||
FallbackComponent={ErrorFallback}
|
||||
onReset={() => {
|
||||
// reset the state of your app so the error doesn't happen again
|
||||
}}
|
||||
>
|
||||
<ErrorBoundary FallbackComponent={ErrorFallback} onReset={resetError}>
|
||||
<Defs />
|
||||
{isReady && (
|
||||
<g ref={rGroup} id="shapes">
|
||||
|
|
|
@ -5,14 +5,7 @@ import {
|
|||
IconButton as _IconButton,
|
||||
RowButton,
|
||||
} from 'components/shared'
|
||||
import {
|
||||
commandKey,
|
||||
deepCompareArrays,
|
||||
getSelectedIds,
|
||||
getShape,
|
||||
isMobile,
|
||||
setToArray,
|
||||
} from 'utils'
|
||||
import { commandKey, deepCompareArrays, getShape, isMobile } from 'utils'
|
||||
import state, { useSelector } from 'state'
|
||||
import {
|
||||
AlignType,
|
||||
|
@ -82,7 +75,7 @@ export default function ContextMenu({
|
|||
children: React.ReactNode
|
||||
}): JSX.Element {
|
||||
const selectedShapeIds = useSelector(
|
||||
(s) => setToArray(getSelectedIds(s.data)),
|
||||
(s) => s.values.selectedIds,
|
||||
deepCompareArrays
|
||||
)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { getShapeStyle } from 'state/shape-styles'
|
||||
import { getShapeUtils } from 'state/shape-utils'
|
||||
import React, { memo } from 'react'
|
||||
import React from 'react'
|
||||
import { useSelector } from 'state'
|
||||
import { getCurrentCamera } from 'utils'
|
||||
import { DotCircle, Handle } from './misc'
|
||||
|
@ -12,28 +12,32 @@ export default function Defs(): JSX.Element {
|
|||
|
||||
return (
|
||||
<defs>
|
||||
{shapeIdsToRender.map((id) => (
|
||||
<Def key={id} id={id} />
|
||||
))}
|
||||
<DotCircle id="dot" r={4} />
|
||||
<Handle id="handle" r={4} />
|
||||
<ExpandDef />
|
||||
{shapeIdsToRender.map((id) => (
|
||||
<Def key={id} id={id} />
|
||||
))}
|
||||
</defs>
|
||||
)
|
||||
}
|
||||
|
||||
const Def = memo(function Def({ id }: { id: string }) {
|
||||
function Def({ id }: { id: string }) {
|
||||
const shape = useShapeDef(id)
|
||||
|
||||
if (!shape) return null
|
||||
|
||||
const style = getShapeStyle(shape.style)
|
||||
|
||||
return React.cloneElement(
|
||||
getShapeUtils(shape).render(shape, { isEditing: false }),
|
||||
{ id, ...style }
|
||||
return (
|
||||
<>
|
||||
{React.cloneElement(
|
||||
getShapeUtils(shape).render(shape, { isEditing: false }),
|
||||
{ id, ...style, strokeWidth: undefined }
|
||||
)}
|
||||
</>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function ExpandDef() {
|
||||
const zoom = useSelector((s) => getCurrentCamera(s.data).zoom)
|
||||
|
|
43
components/canvas/hovered-shape.tsx
Normal file
43
components/canvas/hovered-shape.tsx
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { memo } from 'react'
|
||||
import { getShape } from 'utils'
|
||||
import { getShapeUtils } from 'state/shape-utils'
|
||||
import vec from 'utils/vec'
|
||||
import styled from 'styles'
|
||||
import { useSelector } from 'state'
|
||||
import { getShapeStyle } from 'state/shape-styles'
|
||||
|
||||
function HoveredShape({ id }: { id: string }) {
|
||||
const transform = useSelector((s) => {
|
||||
const shape = getShape(s.data, id)
|
||||
const center = getShapeUtils(shape).getCenter(shape)
|
||||
const rotation = shape.rotation * (180 / Math.PI)
|
||||
const parentPoint = getShape(s.data, shape.parentId)?.point || [0, 0]
|
||||
|
||||
return `
|
||||
translate(${vec.neg(parentPoint)})
|
||||
rotate(${rotation}, ${center})
|
||||
translate(${shape.point})
|
||||
`
|
||||
})
|
||||
|
||||
const strokeWidth = useSelector((s) => {
|
||||
const shape = getShape(s.data, id)
|
||||
const style = getShapeStyle(shape.style)
|
||||
return +style.strokeWidth
|
||||
})
|
||||
|
||||
return (
|
||||
<g transform={transform}>
|
||||
<StyledHoverShape href={'#' + id} strokeWidth={strokeWidth + 8} />
|
||||
<text>hello</text>
|
||||
</g>
|
||||
)
|
||||
}
|
||||
|
||||
const StyledHoverShape = styled('use', {
|
||||
stroke: '$selected',
|
||||
filter: 'url(#expand)',
|
||||
opacity: 0.1,
|
||||
})
|
||||
|
||||
export default memo(HoveredShape)
|
|
@ -1,5 +1,6 @@
|
|||
import { useSelector } from 'state'
|
||||
import Shape from './shape'
|
||||
import HoveredShape from './hovered-shape'
|
||||
import usePageShapes from 'hooks/usePageShapes'
|
||||
|
||||
/*
|
||||
|
@ -8,22 +9,22 @@ on the current page. Kind of expensive but only happens
|
|||
here; and still cheaper than any other pattern I've found.
|
||||
*/
|
||||
|
||||
const noOffset = [0, 0]
|
||||
|
||||
export default function Page(): JSX.Element {
|
||||
const currentPageShapeIds = usePageShapes()
|
||||
|
||||
const isSelecting = useSelector((s) => s.isIn('selecting'))
|
||||
|
||||
const visiblePageShapeIds = usePageShapes()
|
||||
|
||||
const hoveredShapeId = useSelector((s) => {
|
||||
return visiblePageShapeIds.find((id) => id === s.data.hoveredId)
|
||||
})
|
||||
|
||||
return (
|
||||
<g pointerEvents={isSelecting ? 'all' : 'none'}>
|
||||
{currentPageShapeIds.map((shapeId) => (
|
||||
<Shape
|
||||
key={shapeId}
|
||||
id={shapeId}
|
||||
isSelecting={isSelecting}
|
||||
parentPoint={noOffset}
|
||||
/>
|
||||
{isSelecting && hoveredShapeId && (
|
||||
<HoveredShape key={hoveredShapeId} id={hoveredShapeId} />
|
||||
)}
|
||||
{visiblePageShapeIds.map((id) => (
|
||||
<Shape key={id} id={id} isSelecting={isSelecting} />
|
||||
))}
|
||||
</g>
|
||||
)
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import styled from 'styles'
|
||||
import { useSelector } from 'state'
|
||||
import { deepCompareArrays, getPage, getSelectedIds, setToArray } from 'utils'
|
||||
import { deepCompareArrays, getPage } from 'utils'
|
||||
import { getShapeUtils } from 'state/shape-utils'
|
||||
import { memo } from 'react'
|
||||
|
||||
export default function Selected(): JSX.Element {
|
||||
const currentSelectedShapeIds = useSelector(
|
||||
({ data }) => setToArray(getSelectedIds(data)),
|
||||
(s) => s.values.selectedIds,
|
||||
deepCompareArrays
|
||||
)
|
||||
|
||||
|
|
|
@ -2,31 +2,150 @@ import React, { useRef, memo, useEffect } from 'react'
|
|||
import { useSelector } from 'state'
|
||||
import styled from 'styles'
|
||||
import { getShapeUtils } from 'state/shape-utils'
|
||||
import { getPage, getSelectedIds, isMobile } from 'utils'
|
||||
import { deepCompareArrays, getPage, getShape } from 'utils'
|
||||
import useShapeEvents from 'hooks/useShapeEvents'
|
||||
import { Shape as _Shape } from 'types'
|
||||
import vec from 'utils/vec'
|
||||
import { getShapeStyle } from 'state/shape-styles'
|
||||
|
||||
const isMobileDevice = isMobile()
|
||||
import useShapeDef from 'hooks/useShape'
|
||||
|
||||
interface ShapeProps {
|
||||
id: string
|
||||
isSelecting: boolean
|
||||
parentPoint: number[]
|
||||
}
|
||||
|
||||
function Shape({ id, isSelecting, parentPoint }: ShapeProps): JSX.Element {
|
||||
function Shape({ id, isSelecting }: ShapeProps): JSX.Element {
|
||||
const rGroup = useRef<SVGGElement>(null)
|
||||
|
||||
const shapeUtils = useSelector((s) => {
|
||||
const shape = getShape(s.data, id)
|
||||
return getShapeUtils(shape)
|
||||
})
|
||||
|
||||
const isHidden = useSelector((s) => {
|
||||
const shape = getShape(s.data, id)
|
||||
return shape.isHidden
|
||||
})
|
||||
|
||||
const children = useSelector((s) => {
|
||||
const shape = getShape(s.data, id)
|
||||
return shape.children
|
||||
}, deepCompareArrays)
|
||||
|
||||
const isParent = shapeUtils.isParent
|
||||
|
||||
const isForeignObject = shapeUtils.isForeignObject
|
||||
|
||||
const strokeWidth = useSelector((s) => {
|
||||
const shape = getShape(s.data, id)
|
||||
const style = getShapeStyle(shape.style)
|
||||
return +style.strokeWidth
|
||||
})
|
||||
|
||||
const transform = useSelector((s) => {
|
||||
const shape = getShape(s.data, id)
|
||||
const center = shapeUtils.getCenter(shape)
|
||||
const rotation = shape.rotation * (180 / Math.PI)
|
||||
const parentPoint = getShape(s.data, shape.parentId)?.point || [0, 0]
|
||||
|
||||
return `
|
||||
translate(${vec.neg(parentPoint)})
|
||||
rotate(${rotation}, ${center})
|
||||
translate(${shape.point})
|
||||
`
|
||||
})
|
||||
|
||||
const events = useShapeEvents(id, isParent, rGroup)
|
||||
|
||||
return (
|
||||
<StyledGroup
|
||||
id={id + '-group'}
|
||||
ref={rGroup}
|
||||
transform={transform}
|
||||
{...events}
|
||||
>
|
||||
{isSelecting &&
|
||||
(isForeignObject ? (
|
||||
<ForeignObjectHover id={id} />
|
||||
) : (
|
||||
<EventSoak
|
||||
as="use"
|
||||
href={'#' + id}
|
||||
strokeWidth={strokeWidth + 8}
|
||||
variant={shapeUtils.canStyleFill ? 'filled' : 'hollow'}
|
||||
/>
|
||||
))}
|
||||
|
||||
{!isHidden &&
|
||||
(isForeignObject ? (
|
||||
<ForeignObjectRender id={id} />
|
||||
) : (
|
||||
<RealShape id={id} isParent={isParent} strokeWidth={strokeWidth} />
|
||||
))}
|
||||
|
||||
{isParent &&
|
||||
children.map((shapeId) => (
|
||||
<Shape key={shapeId} id={shapeId} isSelecting={isSelecting} />
|
||||
))}
|
||||
</StyledGroup>
|
||||
)
|
||||
}
|
||||
|
||||
interface RealShapeProps {
|
||||
id: string
|
||||
isParent: boolean
|
||||
strokeWidth: number
|
||||
}
|
||||
|
||||
const RealShape = memo(function RealShape({
|
||||
id,
|
||||
isParent,
|
||||
strokeWidth,
|
||||
}: RealShapeProps) {
|
||||
return (
|
||||
<StyledShape
|
||||
as="use"
|
||||
data-shy={isParent}
|
||||
href={'#' + id}
|
||||
strokeWidth={strokeWidth}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
const ForeignObjectHover = memo(function ForeignObjectHover({
|
||||
id,
|
||||
}: {
|
||||
id: string
|
||||
}) {
|
||||
const size = useSelector((s) => {
|
||||
const shape = getPage(s.data).shapes[id]
|
||||
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 = useShapeDef(id)
|
||||
|
||||
const rFocusable = useRef<HTMLTextAreaElement>(null)
|
||||
|
||||
const isEditing = useSelector((s) => s.data.editingId === id)
|
||||
|
||||
const isSelected = useSelector((s) => getSelectedIds(s.data).has(id))
|
||||
|
||||
const shape = useSelector((s) => getPage(s.data).shapes[id])
|
||||
|
||||
const events = useShapeEvents(id, getShapeUtils(shape)?.isParent, rGroup)
|
||||
const shapeUtils = getShapeUtils(shape)
|
||||
|
||||
useEffect(() => {
|
||||
if (isEditing) {
|
||||
|
@ -38,85 +157,7 @@ function Shape({ id, isSelecting, parentPoint }: ShapeProps): JSX.Element {
|
|||
}
|
||||
}, [isEditing])
|
||||
|
||||
// This is a problem with deleted shapes. The hooks in this component
|
||||
// may sometimes run before the hook in the Page component, which means
|
||||
// a deleted shape will still be pulled here before the page component
|
||||
// detects the change and pulls this component.
|
||||
if (!shape) return null
|
||||
|
||||
const style = getShapeStyle(shape.style)
|
||||
const shapeUtils = getShapeUtils(shape)
|
||||
|
||||
const { isShy, isParent, isForeignObject } = shapeUtils
|
||||
|
||||
const bounds = shapeUtils.getBounds(shape)
|
||||
const center = shapeUtils.getCenter(shape)
|
||||
const rotation = shape.rotation * (180 / Math.PI)
|
||||
|
||||
const transform = `
|
||||
translate(${vec.neg(parentPoint)})
|
||||
rotate(${rotation}, ${center})
|
||||
translate(${shape.point})
|
||||
`
|
||||
|
||||
return (
|
||||
<StyledGroup
|
||||
id={id + '-group'}
|
||||
ref={rGroup}
|
||||
transform={transform}
|
||||
isSelected={isSelected}
|
||||
device={isMobileDevice ? 'mobile' : 'desktop'}
|
||||
{...events}
|
||||
>
|
||||
{isSelecting && !isShy && (
|
||||
<>
|
||||
{isForeignObject ? (
|
||||
<HoverIndicator
|
||||
as="rect"
|
||||
width={bounds.width}
|
||||
height={bounds.height}
|
||||
strokeWidth={1.5}
|
||||
variant={'ghost'}
|
||||
/>
|
||||
) : (
|
||||
<HoverIndicator
|
||||
as="use"
|
||||
href={'#' + id}
|
||||
strokeWidth={+style.strokeWidth + 5}
|
||||
variant={shapeUtils.canStyleFill ? 'filled' : 'hollow'}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{!shape.isHidden &&
|
||||
(isForeignObject ? (
|
||||
shapeUtils.render(shape, { isEditing, ref: rFocusable })
|
||||
) : (
|
||||
<RealShape id={id} isParent={isParent} shape={shape} />
|
||||
))}
|
||||
|
||||
{isParent &&
|
||||
shape.children.map((shapeId) => (
|
||||
<Shape
|
||||
key={shapeId}
|
||||
id={shapeId}
|
||||
isSelecting={isSelecting}
|
||||
parentPoint={shape.point}
|
||||
/>
|
||||
))}
|
||||
</StyledGroup>
|
||||
)
|
||||
}
|
||||
|
||||
interface RealShapeProps {
|
||||
id: string
|
||||
shape: _Shape
|
||||
isParent: boolean
|
||||
}
|
||||
|
||||
const RealShape = memo(function RealShape({ id, isParent }: RealShapeProps) {
|
||||
return <StyledShape as="use" data-shy={isParent} href={'#' + id} />
|
||||
return shapeUtils.render(shape, { isEditing, ref: rFocusable })
|
||||
})
|
||||
|
||||
const StyledShape = styled('path', {
|
||||
|
@ -125,12 +166,10 @@ const StyledShape = styled('path', {
|
|||
pointerEvents: 'none',
|
||||
})
|
||||
|
||||
const HoverIndicator = styled('path', {
|
||||
stroke: '$selected',
|
||||
const EventSoak = styled('use', {
|
||||
opacity: 0,
|
||||
strokeLinecap: 'round',
|
||||
strokeLinejoin: 'round',
|
||||
fill: 'transparent',
|
||||
filter: 'url(#expand)',
|
||||
variants: {
|
||||
variant: {
|
||||
ghost: {
|
||||
|
@ -150,81 +189,6 @@ const HoverIndicator = styled('path', {
|
|||
|
||||
const StyledGroup = styled('g', {
|
||||
outline: 'none',
|
||||
[`& *[data-shy="true"]`]: {
|
||||
opacity: '0',
|
||||
},
|
||||
[`& ${HoverIndicator}`]: {
|
||||
opacity: '0',
|
||||
},
|
||||
variants: {
|
||||
device: {
|
||||
mobile: {},
|
||||
desktop: {},
|
||||
},
|
||||
isSelected: {
|
||||
true: {
|
||||
[`& *[data-shy="true"]`]: {
|
||||
opacity: '1',
|
||||
},
|
||||
[`& ${HoverIndicator}`]: {
|
||||
opacity: '0.2',
|
||||
},
|
||||
},
|
||||
false: {
|
||||
[`& ${HoverIndicator}`]: {
|
||||
opacity: '0',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
compoundVariants: [
|
||||
{
|
||||
device: 'desktop',
|
||||
isSelected: 'false',
|
||||
css: {
|
||||
[`&:hover ${HoverIndicator}`]: {
|
||||
opacity: '0.16',
|
||||
},
|
||||
[`&:hover *[data-shy="true"]`]: {
|
||||
opacity: '1',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
device: 'desktop',
|
||||
isSelected: 'true',
|
||||
css: {
|
||||
[`&:hover ${HoverIndicator}`]: {
|
||||
opacity: '0.25',
|
||||
},
|
||||
[`&:active ${HoverIndicator}`]: {
|
||||
opacity: '0.25',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
// function Label({ children }: { children: React.ReactNode }) {
|
||||
// return (
|
||||
// <text
|
||||
// y={4}
|
||||
// x={4}
|
||||
// fontSize={12}
|
||||
// fill="black"
|
||||
// stroke="none"
|
||||
// alignmentBaseline="text-before-edge"
|
||||
// pointerEvents="none"
|
||||
// >
|
||||
// {children}
|
||||
// </text>
|
||||
// )
|
||||
// }
|
||||
|
||||
// function pp(n: number[]) {
|
||||
// return '[' + n.map((v) => v.toFixed(1)).join(', ') + ']'
|
||||
// }
|
||||
|
||||
export { HoverIndicator }
|
||||
|
||||
export default memo(Shape)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue