-
Notifications
You must be signed in to change notification settings - Fork 120
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: graph events #84
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -184,6 +184,34 @@ Example: | |
``` | ||
|
||
See this [example `<SelectionDot />` component](./example/src/components/CustomSelectionDot.tsx). | ||
### `events` | ||
An array of events to be marked in the graph. The position is calculated based on the `date` property of each event relatively to `points` of the graph. | ||
|
||
### `EventComponent` | ||
A component that is used to render an event. | ||
|
||
See this [example `<GraphEvent/>` component](./example/src/components/GraphEvent.tsx). | ||
|
||
### `EventTooltipComponent` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please create some default component EventTooltip and link it here as example (same asi SelectionDot) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Default component created in the fixup 5ff9fd7. |
||
An additional event component that is rendered if the `SelectionDot` overlaps an `Event`. | ||
See this [example `<GraphEventTooltip/>` component](./example/src/components/GraphEventTooltip.tsx). | ||
### `onEventHover` | ||
This comment was marked as outdated.
Sorry, something went wrong. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The library does not work with any tap gestures so far. The only user interaction so far is created by the pan gesture which is also the gesture that enables the new event functionality of this PR. I would prefer to not add this functionality to not make the PR too big. The |
||
Callback called when an `Event` is hovered on. | ||
|
||
Example: | ||
```jsx | ||
<LineGraph | ||
points={priceHistory} | ||
color="#4484B2" | ||
animated={true} | ||
enablePanGesture={true} | ||
events={transactionEvents} | ||
EventComponent={DefaultEventComponent} | ||
/> | ||
``` | ||
> Events related props require `animated` and `enablePanGesture` to be `true`. | ||
|
||
<img src="./img/events.gif" align="right" height="250" /> | ||
|
||
## Sponsor | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import React, { useEffect } from 'react' | ||
import { | ||
runOnJS, | ||
useDerivedValue, | ||
useSharedValue, | ||
withSpring, | ||
withTiming, | ||
} from 'react-native-reanimated' | ||
|
||
import { | ||
Circle, | ||
Group, | ||
TwoPointConicalGradient, | ||
vec, | ||
} from '@shopify/react-native-skia' | ||
import { EventComponentProps } from '../../../src/LineGraphProps' | ||
|
||
const EVENT_SIZE = 6 | ||
const ACTIVE_EVENT_SIZE = 8 | ||
const ENTERING_ANIMATION_DURATION = 750 | ||
|
||
export function GraphEvent({ | ||
isGraphActive, | ||
fingerX, | ||
eventX, | ||
eventY, | ||
color, | ||
index, | ||
onEventHover, | ||
}: EventComponentProps) { | ||
const isEventActive = useDerivedValue(() => { | ||
// If the finger is on X position of the event. | ||
if ( | ||
isGraphActive.value && | ||
Math.abs(fingerX.value - eventX) < ACTIVE_EVENT_SIZE | ||
) { | ||
if (onEventHover) runOnJS(onEventHover)(index, true) | ||
|
||
return true | ||
} | ||
|
||
if (onEventHover) runOnJS(onEventHover)(index, false) | ||
return false | ||
}) | ||
|
||
const dotRadius = useDerivedValue(() => | ||
withSpring(isEventActive.value ? ACTIVE_EVENT_SIZE : EVENT_SIZE) | ||
) | ||
const gradientEndRadius = useDerivedValue(() => | ||
withSpring(dotRadius.value / 2) | ||
) | ||
const animatedOpacity = useSharedValue(0) | ||
|
||
useEffect(() => { | ||
// Entering opacity animation triggered on the first render. | ||
animatedOpacity.value = withTiming(1, { | ||
duration: ENTERING_ANIMATION_DURATION, | ||
}) | ||
}, [animatedOpacity]) | ||
|
||
return ( | ||
<Group opacity={animatedOpacity}> | ||
<Circle cx={eventX} cy={eventY} r={dotRadius} color={color}> | ||
<TwoPointConicalGradient | ||
start={vec(eventX, eventY)} | ||
startR={0} | ||
end={vec(eventX, eventY)} | ||
endR={gradientEndRadius} | ||
colors={['white', color]} | ||
/> | ||
</Circle> | ||
</Group> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import React from 'react' | ||
import Animated, { FadeIn, FadeOut } from 'react-native-reanimated' | ||
import { Dimensions, Platform, StyleSheet, Text, View } from 'react-native' | ||
import { EventTooltipComponentProps } from '../../../src/LineGraphProps' | ||
|
||
export type TransactionEventTooltipProps = EventTooltipComponentProps<{}> | ||
|
||
const SCREEN_WIDTH = Dimensions.get('screen').width | ||
const ANIMATION_DURATION = 200 | ||
const TOOLTIP_LEFT_OFFSET = 25 | ||
const TOOLTIP_RIGHT_OFFSET = 145 | ||
|
||
export const GraphEventTooltip = ({ | ||
eventX, | ||
eventY, | ||
}: TransactionEventTooltipProps) => { | ||
const tooltipPositionStyle = { | ||
left: | ||
eventX > SCREEN_WIDTH / 2 | ||
? eventX - TOOLTIP_RIGHT_OFFSET | ||
: eventX + TOOLTIP_LEFT_OFFSET, | ||
top: eventY, | ||
} | ||
return ( | ||
<Animated.View | ||
style={[styles.tooltip, tooltipPositionStyle]} | ||
entering={FadeIn.duration(ANIMATION_DURATION)} | ||
exiting={FadeOut.duration(ANIMATION_DURATION)} | ||
> | ||
<View style={styles.content}> | ||
<Text style={styles.textNote}> | ||
Here you can display {'\n'} | ||
any information you {'\n'} | ||
want about the event. | ||
</Text> | ||
</View> | ||
</Animated.View> | ||
) | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
tooltip: { | ||
position: 'absolute', | ||
backgroundColor: 'white', | ||
paddingHorizontal: 10, | ||
|
||
borderRadius: 20, | ||
// add shadow based on platform | ||
...Platform.select({ | ||
ios: { | ||
shadowColor: 'black', | ||
shadowOffset: { width: 0, height: 2 }, | ||
shadowOpacity: 0.5, | ||
shadowRadius: 3, | ||
}, | ||
android: { | ||
elevation: 3, | ||
}, | ||
}), | ||
}, | ||
content: { | ||
paddingVertical: 12, | ||
}, | ||
textNote: { | ||
color: 'gray', | ||
fontSize: 10, | ||
}, | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Link EventComponent file here as example (same as SelectionDot)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Linked in the fixup 5ff9fd7.