fix: add liquidity ux polish (#2024)

* zoom out on intiial

* adjust initial zoom ranges

* remove unneeded reactga event

* adjust full range warning copy

* update zoom

* adjust zoom ranges and label around current price
This commit is contained in:
Justin Domingue 2021-07-13 08:23:24 -07:00 committed by GitHub
parent 2bc2a2c76e
commit bf30013b6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 52 additions and 43 deletions

@ -40,6 +40,8 @@ const Tooltip = styled.text`
// flips the handles draggers when close to the container edges
const FLIP_HANDLE_THRESHOLD_PX = 20
const compare = (a1: [number, number], a2: [number, number]): boolean => a1[0] !== a2[0] || a1[1] !== a2[1]
export const Brush = ({
id,
xScale,
@ -49,7 +51,8 @@ export const Brush = ({
setBrushExtent,
innerWidth,
innerHeight,
colors,
westHandleColor,
eastHandleColor,
}: {
id: string
xScale: ScaleLinear<number, number>
@ -59,10 +62,8 @@ export const Brush = ({
setBrushExtent: (extent: [number, number]) => void
innerWidth: number
innerHeight: number
colors: {
west: string
east: string
}
westHandleColor: string
eastHandleColor: string
}) => {
const brushRef = useRef<SVGGElement | null>(null)
const brushBehavior = useRef<BrushBehavior<SVGGElement> | null>(null)
@ -84,13 +85,13 @@ export const Brush = ({
const scaled = (selection as [number, number]).map(xScale.invert) as [number, number]
// avoid infinite render loop by checking for change
if (type === 'end' && (brushExtent[0] !== scaled[0] || brushExtent[1] !== scaled[1])) {
if (type === 'end' && compare(brushExtent, scaled)) {
setBrushExtent(scaled)
}
setLocalBrushExtent(scaled)
},
[xScale.invert, brushExtent, setBrushExtent]
[xScale, brushExtent, setBrushExtent]
)
// keep local and external brush extent in sync
@ -114,10 +115,7 @@ export const Brush = ({
brushBehavior.current(select(brushRef.current))
if (
previousBrushExtent &&
(brushExtent[0] !== previousBrushExtent[0] || brushExtent[1] !== previousBrushExtent[1])
) {
if (previousBrushExtent && compare(brushExtent, previousBrushExtent)) {
select(brushRef.current)
.transition()
.call(brushBehavior.current.move as any, brushExtent.map(xScale))
@ -136,9 +134,7 @@ export const Brush = ({
if (!brushRef.current || !brushBehavior.current) return
brushBehavior.current.move(select(brushRef.current) as any, brushExtent.map(xScale) as any)
// dependency on brushExtent would start an update loop
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [xScale])
}, [brushExtent, xScale])
useEffect(() => {
setShowLabels(true)
@ -154,8 +150,8 @@ export const Brush = ({
<>
<defs>
<linearGradient id={`${id}-gradient-selection`} x1="0%" y1="100%" x2="100%" y2="100%">
<stop stopColor={colors.west} />
<stop stopColor={colors.east} offset="1" />
<stop stopColor={westHandleColor} />
<stop stopColor={eastHandleColor} offset="1" />
</linearGradient>
{/* clips at exactly the svg area */}
@ -186,7 +182,7 @@ export const Brush = ({
}, 1)`}
>
<g clipPath={`url(#${id}-handles-clip)`}>
<Handle color={colors.west} d={brushHandlePath(innerHeight)} />
<Handle color={westHandleColor} d={brushHandlePath(innerHeight)} />
<HandleAccent d={brushHandleAccentPath()} />
</g>
@ -208,7 +204,7 @@ export const Brush = ({
}, 1)`}
>
<g clipPath={`url(#${id}-handles-clip)`}>
<Handle color={colors.east} d={brushHandlePath(innerHeight)} />
<Handle color={eastHandleColor} d={brushHandlePath(innerHeight)} />
<HandleAccent d={brushHandleAccentPath()} />
</g>
@ -228,8 +224,7 @@ export const Brush = ({
),
[
brushLabelValue,
colors.east,
colors.west,
eastHandleColor,
flipEastHandle,
flipWestHandle,
hovering,
@ -238,6 +233,7 @@ export const Brush = ({
innerWidth,
localBrushExtent,
showLabels,
westHandleColor,
xScale,
]
)

@ -24,7 +24,7 @@ export function Chart({
}: LiquidityChartRangeInputProps) {
const svgRef = useRef<SVGSVGElement | null>(null)
const [zoom, setZoom] = useState<ZoomTransform>()
const [zoom, setZoom] = useState<ZoomTransform | null>(null)
const [innerHeight, innerWidth] = useMemo(
() => [height - margins.top - margins.bottom, width - margins.left - margins.right],
@ -34,7 +34,7 @@ export function Chart({
const { xScale, yScale } = useMemo(() => {
const scales = {
xScale: scaleLinear()
.domain([(1 - zoomLevels.initial) * current, (1 + zoomLevels.initial) * current] as number[])
.domain([current * zoomLevels.initialMin, current * zoomLevels.initialMax] as number[])
.range([0, innerWidth]),
yScale: scaleLinear()
.domain([0, max(series, yAccessor)] as number[])
@ -47,7 +47,12 @@ export function Chart({
}
return scales
}, [zoomLevels.initial, current, innerWidth, series, innerHeight, zoom])
}, [current, zoomLevels.initialMin, zoomLevels.initialMax, innerWidth, series, innerHeight, zoom])
useEffect(() => {
// reset zoom as necessary
setZoom(null)
}, [zoomLevels])
useEffect(() => {
if (!brushDomain) {
@ -121,10 +126,8 @@ export function Chart({
innerWidth={innerWidth}
innerHeight={innerHeight}
setBrushExtent={onBrushDomainChange}
colors={{
west: styles.brush.handle.west,
east: styles.brush.handle.east,
}}
westHandleColor={styles.brush.handle.west}
eastHandleColor={styles.brush.handle.east}
/>
</g>
</svg>

@ -45,7 +45,7 @@ export default function Zoom({
}) {
const zoomBehavior = useRef<ZoomBehavior<Element, unknown>>()
const [zoomIn, zoomOut, reset] = useMemo(
const [zoomIn, zoomOut, reset, initial] = useMemo(
() => [
() =>
svg &&
@ -65,6 +65,12 @@ export default function Zoom({
select(svg as Element)
.transition()
.call(zoomBehavior.current.scaleTo, 1),
() =>
svg &&
zoomBehavior.current &&
select(svg as Element)
.transition()
.call(zoomBehavior.current.scaleTo, 0.5),
],
[svg, zoomBehavior]
)
@ -72,7 +78,6 @@ export default function Zoom({
useEffect(() => {
if (!svg) return
// zoom
zoomBehavior.current = zoom()
.scaleExtent([zoomLevels.min, zoomLevels.max])
.translateExtent([
@ -88,7 +93,12 @@ export default function Zoom({
select(svg as Element)
.call(zoomBehavior.current)
.on('mousedown.zoom', null)
}, [innerHeight, innerWidth, setZoom, svg, xScale, zoomBehavior, zoomLevels.max, zoomLevels.min])
}, [innerHeight, innerWidth, setZoom, svg, xScale, zoomBehavior, zoomLevels, zoomLevels.max, zoomLevels.min])
useEffect(() => {
// reset zoom to initial on zoomLevel chang
initial()
}, [initial, zoomLevels])
return (
<Wrapper count={showClear ? 3 : 2}>

@ -20,17 +20,20 @@ import { ZoomLevels } from './types'
const ZOOM_LEVELS: Record<FeeAmount, ZoomLevels> = {
[FeeAmount.LOW]: {
initial: 0.002,
initialMin: 0.999,
initialMax: 1.001,
min: 0.001,
max: 2,
max: 1.5,
},
[FeeAmount.MEDIUM]: {
initial: 0.3,
initialMin: 0.5,
initialMax: 2,
min: 0.01,
max: 20,
},
[FeeAmount.HIGH]: {
initial: 0.3,
initialMin: 0.5,
initialMax: 2,
min: 0.01,
max: 20,
},
@ -95,11 +98,6 @@ export default function LiquidityChartRangeInput({
let leftRangeValue = Number(domain[0])
const rightRangeValue = Number(domain[1])
ReactGA.event({
category: 'Liquidity',
action: 'Chart brushed',
})
if (leftRangeValue <= 0) {
leftRangeValue = 1 / 10 ** 6
}
@ -133,7 +131,9 @@ export default function LiquidityChartRangeInput({
if (d === 'w' && ticksAtLimit[Bound.LOWER]) return '0'
if (d === 'e' && ticksAtLimit[Bound.UPPER]) return '∞'
const percent = (((x < price ? -1 : 1) * (Math.max(x, price) - Math.min(x, price))) / Math.min(x, price)) * 100
//const percent = (((x < price ? -1 : 1) * (Math.max(x, price) - Math.min(x, price))) / Math.min(x, price)) * 100
const percent = (x < price ? -1 : 1) * ((Math.max(x, price) - Math.min(x, price)) / price) * 100
return price ? `${format(Math.abs(percent) > 1 ? '.2~s' : '.2~f')(percent)}%` : ''
},

@ -16,7 +16,8 @@ export interface Margins {
}
export interface ZoomLevels {
initial: number
initialMin: number
initialMax: number
min: number
max: number
}

@ -842,8 +842,7 @@ export default function AddLiquidity({
<RowFixed>
<TYPE.yellow ml="12px" fontSize="13px" margin={0} fontWeight={400}>
<Trans>
On Uniswap V3, setting a range across all prices like V2 is less capital efficient
than a concentrated one. Learn more{' '}
Full range positions may earn less fees than concentrated positions. Learn more{' '}
<ExternalLink
style={{ color: theme.yellow3, textDecoration: 'underline' }}
href={''}