Skip to content
This repository was archived by the owner on Apr 7, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@
- [Example](pages/components/overlay/controls?id=example)
- [Custom components](pages/components/overlay/custom)
- [Graph models](pages/models/index)
- [DirectedGraph](pages/models/directed-graph)
- [Description](pages/models/directed-graph?id=description)
- [Usage](pages/models/directed-graph?id=usage)
- [Properties](pages/models/directed-graph?id=properties)
- [Example](pages/models/directed-graph?id=example)
- [UndirectedGraph](pages/models/undirected-graph)
- [Description](pages/models/undirected-graph?id=description)
- [Usage](pages/models/undirected-graph?id=usage)
- [Properties](pages/models/undirected-graph?id=properties)
- [Example](pages/models/undirected-graph?id=example)
- [Settings](pages/settings/index)
- [Graph components settings](pages/settings/components/index)
- [Vertex](pages/settings/components/vertex)
Expand Down
6 changes: 0 additions & 6 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -262,11 +262,6 @@
depth: 6,
hideOtherSidebarContent: false // whether or not to hide other sidebar content
},
timeUpdater: {
text: 'Last updated: {docsify-updated}',
formatUpdated: '{YYYY}-{MM}-{DD}',
whereToPlace: 'top'
},
copyCode: {
buttonText: '<svg><use href="assets/icons.svg#copy" /></svg>'
},
Expand Down Expand Up @@ -382,7 +377,6 @@
<script src="https://unpkg.com/docsify-plugin-flexible-alerts"></script>
<script src="//cdn.jsdelivr.net/npm/docsify-sidebar-collapse/dist/docsify-sidebar-collapse.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/@sujaykumarh/docsify-plugin-title@1.x/dist/plugin.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/docsify-updated/src/time-updater.min.js"></script>

<!-- Prism (syntax highlighting) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.25.0/components/prism-jsx.min.js"></script>
Expand Down
2 changes: 2 additions & 0 deletions docs/pages/components/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Components

## Description

Graph components provide the core functionality of the library. Their main functionalities involve rendering the graph structure representation on the canvas, responding to user gestures and other interactions, as well as dynamically visualizing graph modifications.

## Available components
Expand Down
11 changes: 11 additions & 0 deletions docs/pages/models/directed-graph.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# DirectedGraph

## Description

This model is used to create the **object** representing the **directed graph**. More details about [features](pages/models/index?id=features) can be found in [this](pages/models/index) page.

## Usage

## Properties

## Example
15 changes: 15 additions & 0 deletions docs/pages/models/index.md
Original file line number Diff line number Diff line change
@@ -1 +1,16 @@
# Graph models

## Description

Graph models are **classes** used to **create objects modelling graphs**. They information about graph **vertices** and **edges** which connect them.

Models also store graph-related **data**. Each graph **vertex** and **edge** can **hold data** which can be then used by the [custom renderer](pages/renderers/index) to **render** graph component with **desired appearance**.

Graph models make it possible to **modify graph** (add/remove vertices/edges) **without** the necessity to **re-render** the whole graph structure.

## Features

## Available graph models

- [DirectedGraph](pages/models/directed-graph)
- [UndirectedGraph](pages/models/undirected-graph)
11 changes: 11 additions & 0 deletions docs/pages/models/undirected-graph.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# UndirectedGraph

## Description

This model is used to create the **object** representing the **undirected graph**. More details about [features](pages/models/index?id=features) can be found in [this](pages/models/index) page.

## Usage

## Properties

## Example
209 changes: 123 additions & 86 deletions src/examples/Graph.tsx
Original file line number Diff line number Diff line change
@@ -1,105 +1,142 @@
import { useMemo, useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { TouchableOpacity } from 'react-native-gesture-handler';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { StyleSheet } from 'react-native';
import {
DirectedGraphData,
DirectedGraph,
GraphView,
Easing,
useSharedValue,
withRepeat,
withSequence,
withTiming
} from 'react-native-reanimated';

import GraphViewControls from '@/components/controls/GraphViewControls';
import GraphView from '@/components/views/GraphView';
import { DirectedGraph } from '@/models/graphs';

import {
DefaultEdgeLabelRenderer,
DirectedEdgeData,
DirectedGraphComponent,
DefaultEdgeLabelRenderer
} from 'react-native-smart-graph';
FocusPoints,
FocusSettings,
ObjectFit,
VertexData,
VertexPressHandler
} from '..';

const GRAPH: DirectedGraphData = {
vertices: [{ key: 'V1' }, { key: 'V2' }, { key: 'V3' }],
const FOCUS_SETTINGS: FocusSettings = {
alignment: {
horizontalAlignment: 'left',
horizontalOffset: 25
},
animation: {
duration: 250,
easing: Easing.inOut(Easing.ease)
},
disableGestures: false,
vertexScale: 4
};

const GRAPH: {
edges: DirectedEdgeData<string>[];
vertices: VertexData<string>[];
} = {
edges: [
{ key: 'E1', from: 'V1', to: 'V2' },
{ key: 'E2', from: 'V1', to: 'V3' },
{ key: 'E3', from: 'V2', to: 'V3' },
{ key: 'E4', from: 'V3', to: 'V1' },
{ key: 'E5', from: 'V3', to: 'V2' },
{ key: 'E6', from: 'V3', to: 'V1' }
]
{ key: 'E3', from: 'V1', to: 'V4' }
],
vertices: [{ key: 'V1' }, { key: 'V2' }, { key: 'V3' }, { key: 'V4' }]
};

export default function Graph() {
const [scale, setScale] = useState(1);
const [objectFit, setObjectFit] = useState<ObjectFit>('contain');

const graph = useMemo(() => new DirectedGraph<string, unknown>(), []);
const focusPoints = useMemo<FocusPoints>(
// TODO - add information in docs about useMemo
() => ({
0.25: { key: 'V1', vertexScale: 10 },
0.5: {
key: 'V2',
vertexScale: 2,
alignment: { horizontalAlignment: 'left', horizontalOffset: 25 }
},
0.8: {
key: 'V3',
alignment: {
verticalAlignment: 'top',
verticalOffset: 0,
horizontalAlignment: 'left',
horizontalOffset: 0
}
}
}),
[]
);

const graph = useMemo(() => new DirectedGraph(GRAPH), []);
const multiStepFocusProgress = useSharedValue(0);

const increaseScale = () =>
setScale(prev => Math.min(Math.round(10 * prev + 2) / 10, 2));
const decreaseScale = () =>
setScale(prev => Math.max(Math.round(10 * prev - 2) / 10, 0.2));
useEffect(() => {
graph.insertBatch(GRAPH);
}, [graph]);

useEffect(() => {
multiStepFocusProgress.value = withRepeat(
withSequence(
withTiming(1, { duration: 5000, easing: Easing.linear }),
withTiming(0, { duration: 5000, easing: Easing.linear })
),
-1
);
}, []);

const handleVertexLongPress = useCallback<VertexPressHandler<string>>(
({ vertex: { key } }) => {
console.log('long press', key);
},
[]
);

const handleVertexPress = useCallback<VertexPressHandler<string>>(
({ vertex: { key } }) => {
graph.focus(key, FOCUS_SETTINGS);
},
[graph]
);

return (
<>
<GraphView objectFit='contain' padding={50}>
<DirectedGraphComponent
renderers={{
label: DefaultEdgeLabelRenderer
}}
settings={{
// --- Graph components settings ---
components: {
arrow: {
scale
}
},
// --- End of graph components settings ---
placement: {
strategy: 'circle',
minVertexSpacing: 100
}
}}
graph={graph}
/>
</GraphView>
{/* Helper overlay to change dimensions */}
<View style={styles.overlay}>
<View style={styles.buttonsContainer}>
<TouchableOpacity onPress={decreaseScale} style={styles.button}>
<Text style={styles.buttonText}>-</Text>
</TouchableOpacity>
<Text style={styles.radiusText}>{scale}</Text>
<TouchableOpacity onPress={increaseScale} style={styles.button}>
<Text style={styles.buttonText}>+</Text>
</TouchableOpacity>
</View>
</View>
</>
<GraphView objectFit={objectFit} padding={25} scales={[0.25, 1, 10]}>
<DirectedGraphComponent
renderers={{
label: DefaultEdgeLabelRenderer
}}
settings={{
events: {
onVertexLongPress: handleVertexLongPress,
onVertexPress: handleVertexPress
},
placement: {
strategy: 'orbits'
},
focus: {
points: focusPoints,
progress: multiStepFocusProgress
}
}}
graph={graph}
/>
<GraphViewControls
onObjectFitChange={setObjectFit}
style={styles.controls}
/>
</GraphView>
);
}

const styles = StyleSheet.create({
overlay: {
...StyleSheet.absoluteFillObject,
justifyContent: 'flex-end',
pointerEvents: 'box-none'
},
buttonsContainer: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
marginBottom: 50
},
button: {
backgroundColor: '#edcf46',
width: 40,
height: 40,
justifyContent: 'center',
borderRadius: 5
},
buttonText: {
fontSize: 30,
lineHeight: 30,
fontWeight: 'bold',
textAlign: 'center'
},
radiusText: {
fontSize: 30,
color: '#fff',
fontWeight: 'bold',
width: 75,
textAlign: 'center'
controls: {
position: 'absolute',
top: 40,
right: 10
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import {
updateTransitionPoints
} from './utils';

// TODO - add handling of cases when the transition was interrupted from outside

const focusStartState: StateHandler = props => {
'worklet';
const {
Expand Down Expand Up @@ -218,6 +216,7 @@ const STATE_HANDLERS: Record<MachineState, StateHandler> = {
};

type MachineContext = {
reset(): void;
update(
currentProgress: number,
previousProgress: number,
Expand Down Expand Up @@ -259,7 +258,16 @@ export const useStateMachine = (

return useMemo<MachineContext>(
() => ({
// Resets the machine state
reset() {
'worklet';
// Trun off the focus without any transition
// focusContext.endFocus(null);
state.value = MachineState.BLUR;
targetKey.value = null;
},
state,
// Updates the state of the machine
update(
currentProgress,
previousProgress,
Expand All @@ -283,6 +291,7 @@ export const useStateMachine = (
targetKey,
vertexRadius
});
console.log(result);
} while (result !== state.value);
state.value = result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@ function MultiStepVertexFocusProvider({
const initialStep = useSharedValue(-1);
const previousStep = useSharedValue(-1);

// State machine
// Used to ensure that the transition between the current graph
// position and the focus point is smooth
const syncProgress = useSharedValue(0);

// State machine
const stateMachine = useStateMachine(
focusContext,
canvasDataContext,
Expand All @@ -73,6 +75,7 @@ function MultiStepVertexFocusProvider({

const updateInitialStep = useWorkletCallback(
(progress: null | number, data: Array<FocusStepData>) => {
stateMachine.reset();
if (progress === null) {
initialStep.value = -1;
return;
Expand Down