# ReactNative

### [#](#/pages/reactNativeFirstSteps#information) General Information

GeotoolkitJS, now with support for Skia rendering engine brings native rendering solution to react-native.

While solving a lot of problems of when using WebView and rendering on WebView's HTML Canvas, there are some limitations with this version of GeotoolkitJS to support native rendering with Skia rendering engine:

- In some cases, it can have lower rendering performance especially with large dataset compare to WebView's Canvas


However, the benefits are:

- Better development process by fully support react-native, and code sharing between react and react-native
- Provides native looks and feels for mobile applications
- Higher UI performance because separation of canvas rendering processes and UI rendering processes


Now let's dive into an example.

This tutorial introduces how to use GeotoolkitJS with react-native through adding a simple PolylineChart widget.

### [#](#/pages/reactNativeFirstSteps#setUpEnvironment) Set up enviroment & run the app

Details can be found in https://reactnative.dev/docs/0.70/environment-setup

### [#](#/pages/reactNativeFirstSteps#howToDebug) Debugging the app

For ReactNative version 0.70, the detail on debugging can be found in https://reactnative.dev/docs/0.70/debugging.
However, since we are using react-native-skia, a native module uses JSI for synchronous native methods access, remote debugging is no longer possible.

**Note: Debuging with distribution GeoToolkit is also possible. As long as the app is not in Release mode, Flipper should work.**

### Use Flipper to debug

1. Download Flipper (Mobile App and ReactNative debugger tool) at https://fbflipper.com/
2. Enable Hermes debugger:
### Android
Hermes is enabled by default, performance in Android is worse compare to iOS, we might also need to disable Hermes on Android except when debugger for better performance.
### iOS
In examples/reactnative/ios/Podfile: change `:hermes_enabled => false` to `:hermes_enabled => true` to enable Hermes JS engine.
Hermes can help optimize performance and provides browser-like debugging experience through Flipper. We keep it disabled because we observed worse performance when rendering with Skia engine.
3. Open Flipper and connect with desired application.
It should automatically pick running application.
Sometimes it will show "No available app", but it also works as long as it detects running JS ReactNative server.

4. If Hermes enabled, you'll able to select Hermes debugger as below:

### Android
Push Ctrl+P, in opened window to enter file name which you will debug. The first file in the list of files is the one you need.

It provides browser-like debugger:

### iOS
It provides browser-like debugger:



## Examples on how to use GeoToolkit with ReactNative

### [#](#/pages/reactNativeFirstSteps#addCanvas) Add ReactNative Canvas Element (CarnacView)

GeotoolkitJS ReactNative module provides CarnacView to render graphic inside. So the next step is to add CarnacView inside any View component in you react-native app.

You also need to import necessary module from GeotoolkitJS. In this case, we use `@int` as an alias for relative path to GeotoolkitJS modules.

main
```ts
import {CarnacView} from '@int/reactnative/plot/CarnacView';
export const firstApp = () => {
    return (
        <View style={{flex: 1}}>
            <CarnacView
                style={{flex: 1}} // Expand CarnacView to fill its parent container
            >
            </CarnacView>
        </View>
    );
}
```

### [#](#/pages/reactNativeFirstSteps#import) Import module

For LineChart, you also need other modules like: ChartWidget, ChartType, and other necessary React/ReactNative components

main
```ts
import React, {useEffect, useMemo, useRef} from 'react';
import {Text, View} from 'react-native';
import {ChartType} from '@int/geotoolkit/charts/ChartType';
import {ChartWidget} from '@int/geotoolkit/charts/widgets/ChartWidget';
import {KnownColors} from '@int/geotoolkit/util/ColorUtil';
import {DataTable} from '@int/geotoolkit/data/DataTable';
import {SelectionMode} from '@int/geotoolkit/charts/SelectionMode';
import {AnnotationLocation} from '@int/geotoolkit/layout/AnnotationLocation';
```

### [#](#/pages/reactNativeFirstSteps#addWidget) Adding ChartWidget

After necessary libraries are loaded, we can create a simple ChartWidget which is a general chart object and pass all chart options.

ChartWidget options can be referenced in ChartWidget documentations.

Creating ChartWidget using `useMemo` react hook so that the widget only get created once.

In this case, we are adding LineChart for 2 lines, so we need to add LineChart into ChartWidget as well.

main
```ts
const widget = useMemo(() => {
    const widget = new ChartWidget({
        'data': new DataTable({
            'cols': [
                {
                    'id': 'x',
                    'data': [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50]
                },
                {
                    'id': 'y1',
                    'name': 'Oil',
                    'data': [20, 42, 29, 40, 60, 57, 70, 92, 75, 81, 93, 98, 101, 123, 132,
                    125, 105, 112, 117, 104, 105, 107, 96, 101, 109, 100]
                },
                {
                    'id': 'y2',
                    'name': 'Gas',
                    'data': [15, 17, 22, 30, 27, 31, 40, 42, 50, 51, 50, 60, 57, 59, 61, 50, 49, 53, 57, 50, 53, 52, 55, 59, 52, 57]
                },
            ]
        }),
        'axis': {
            'x-axis': {
                'location': AnnotationLocation.South,
                'title': {
                    'text': 'Day',
                    'textstyle': '#757575'
                }
            },
            'y-axis': {
                'location': AnnotationLocation.West,
                'dimension': {
                    'neatlimits': true
                },
                'title': {
                    'text': 'Volume (gal)',
                    'textstyle': '#757575'
                }
            }
        },
        'selectionmode': SelectionMode.Vertical
    });
    widget.addChart({
        'type': ChartType.LineChart,
        'series': {
            'x': 'x', // Reference 'x' data from the DataSource
            'y': [{
                'data': 'y1', // Reference 'y1' data from the DataSource
                'linestyle': {
                    'color': KnownColors.Orange,
                    'width': 2.5
                }
            }, {
                'data': 'y2', // Reference 'y2' data from the DataSource
                'linestyle': {
                    'color': KnownColors.Blue,
                    'width': 2.5
                }
            }]
        },
        'axis': {
            'x': 'x-axis',
            'y': 'y-axis'
        }
    });
    return widget;
}, []);
```

### [#](#/pages/reactNativeFirstSteps#connectWidget) Connect ChartWidget and CarnacView

In order for CarnacView to render the widget, we need to add the widget in `root` props.

main
```ts

return (
    <View style={{flex: 1}}>
        <CarnacView
            style={{flex: 1}} // Expand CarnacView to fill its parent container
            root={widget}
        >
        </CarnacView>
    </View>
);
```

### [#](#/pages/reactNativeFirstSteps#disposeWidget) Dispose ChartWidget

Important note is to also dipose the widget when this react component unmounted. We can do that using `useEffect` hook.

main
```ts

useEffect(() => () => {
    if (widget != null) {
        widget.dispose();
    }
}, [widget]);
```

### [#](#/pages/reactNativeFirstSteps#overallWidget) Finishing the widget

The below is the code how is our react LineChart component when piece everything together looks like.

main
```ts
import React, {useEffect, useMemo, useRef} from 'react';
import {Text, View} from 'react-native';

import {CarnacView} from '@int/reactnative/plot/CarnacView';
import {ChartType} from '@int/geotoolkit/charts/ChartType';
import {ChartWidget} from '@int/geotoolkit/charts/widgets/ChartWidget';
import {KnownColors} from '@int/geotoolkit/util/ColorUtil';
import {DataTable} from '@int/geotoolkit/data/DataTable';
import {SelectionMode} from '@int/geotoolkit/charts/SelectionMode';
import {AnnotationLocation} from '@int/geotoolkit/layout/AnnotationLocation';

export const LineChart = () => {
    const widget = useMemo(() => {
        const widget = new ChartWidget({
            'data': new DataTable({
                'cols': [
                    {
                        'id': 'x',
                        'data': [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50]
                    },
                    {
                        'id': 'y1',
                        'name': 'Oil',
                        'data': [20, 42, 29, 40, 60, 57, 70, 92, 75, 81, 93, 98, 101, 123, 132,
                        125, 105, 112, 117, 104, 105, 107, 96, 101, 109, 100]
                    },
                    {
                        'id': 'y2',
                        'name': 'Gas',
                        'data': [15, 17, 22, 30, 27, 31, 40, 42, 50, 51, 50, 60, 57, 59, 61, 50, 49, 53, 57, 50, 53, 52, 55, 59, 52, 57]
                    },
                ]
            }),
            'axis': {
                'x-axis': {
                    'location': AnnotationLocation.South,
                    'title': {
                        'text': 'Day',
                        'textstyle': '#757575'
                    }
                },
                'y-axis': {
                    'location': AnnotationLocation.West,
                    'dimension': {
                        'neatlimits': true
                    },
                    'title': {
                        'text': 'Volume (gal)',
                        'textstyle': '#757575'
                    }
                }
            },
            'selectionmode': SelectionMode.Vertical
        });
        widget.addChart({
            'type': ChartType.LineChart,
            'series': {
                'x': 'x', // Reference 'x' data from the DataSource
                'y': [{
                    'data': 'y1', // Reference 'y1' data from the DataSource
                    'linestyle': {
                        'color': KnownColors.Orange,
                        'width': 2.5
                    }
                }, {
                    'data': 'y2', // Reference 'y2' data from the DataSource
                    'linestyle': {
                        'color': KnownColors.Blue,
                        'width': 2.5
                    }
                }]
            },
            'axis': {
                'x': 'x-axis',
                'y': 'y-axis'
            }
        });
        return widget;
    }, []);

    useEffect(() => () => {
        if (widget != null) {
            widget.dispose();
        }
    }, []);

    return (
        <View style={{flex: 1}}>
            <CarnacView
                style={{flex: 1}}
                root={widget}
            >
            </CarnacView>
        </View>
    );
};
```

### [#](#/pages/reactNativeFirstSteps#tooltipComponent) Create tooltip component

In react-native, we cannot inject jsx/tsx on the fly using a string or have something similar to document.createElement.

Creating a specific react-native tooltip component that has structure and format suits specific needs is necessary.

In this part, we also show how to create and set up a tooltip component for your GeotoolkitJS widget.

reactnative module in GeotoolkitJS provides `RNElement`, a special react-native `View` so that it can be manipulated and used in GeotoolkitJS tools.

It's a `View` so you can nest any common react-native component inside.

The code below is the tooltip component will be used for this example.

main
```ts
import React, {forwardRef, useImperativeHandle, useRef} from 'react';
import {Text, TextInput, View} from 'react-native';
import {RNElement} from '@int/reactnative/dom/RNElement';

export const Tooltip = forwardRef((props, ref) => {
    const {metaData} = props;
    const containerRef = useRef(null);
    const textRefs = useRef([]);

    useImperativeHandle(ref, () => ({
        getContainer: () => containerRef.current,
        setData: (data) => {
            metaData.forEach((metaData, index) => {
                textRefs.current[index].setNativeProps({text: data[metaData['id']].toString()});
            });
        }
    }));

    return (
        <RNElement
            ref={containerRef}
            style={{
                borderWidth: 1,
                borderRadius: 3,
                backgroundColor: 'rgba(255, 255, 255, 0.5)',
                zIndex: 999,
                display: 'none',
                padding: 10
            }}
        >
            {metaData.map((metaData, index) => (
                <View key={index} style={{flexDirection: 'row', alignItems: 'center'}}>
                    {metaData['symbolcolor'] != null ?
                        (
                            <View
                                style={{
                                    borderRadius: 5,
                                    backgroundColor: metaData['symbolcolor'],
                                    width: 10,
                                    height: 10,
                                    marginRight: 5
                                }}
                            />
                        ) : null
                    }
                    <Text style={{fontWeight: 'bold', fontSize: 18}}>
                        {metaData['name'] + ': '}
                    </Text>
                    <TextInput
                        style={{fontSize: 18, marginRight: 5}}
                        ref={(ref) => {
                            textRefs.current[index] = ref;
                        }}
                        editable={false}
                    />
                    {metaData['unit'] != null ?
                        (
                            <Text style={{fontSize: 18}}>
                                {metaData['unit']}
                            </Text>
                        ) : null
                    }
                </View>
            ))}
        </RNElement>
    );
});
```

### [#](#/pages/reactNativeFirstSteps#connectTooltip) Connect tooltip component with the widget

The next step is to import `Tooltip` component we created earlier and connect with the widget.

We will use `useRef` hook to create ref to `Tooltip` component as below:

`const tooltipRef = useRef(null);`

And add `Tooltip` component nested inside `CarnacView`.

main
```ts

<View style={{flex: 1}}>
    <CarnacView
        style={{flex: 1}}
        root={widget}
    >
    <Tooltip ref={tooltipRef} metaData={[
        {
            'id': 'x',
            'name': 'Day'
        },
        {
            'id': 'y1',
            'name': 'Oil',
            'unit': 'gal',
            'symbolcolor': KnownColors.Orange
        },
        {
            'id': 'y2',
            'name': 'Gas',
            'unit': 'gal',
            'symbolcolor': KnownColors.Blue
        }
    ]} />
    </CarnacView>
</View>
```

Now we can config `TooltipTool` settings and callback to work with out tooltip.

main
```ts

useEffect(() => {
    if (widget != null) {
        widget.setProperties({
            'tooltip': {
                'alignment': AnchorType.LeftCenter,
                'offsetx': 15,
                'offsety': 50,
                'divelement': tooltipRef.current.getContainer(), // Provide RNElement ref we setup in Tooltip component earlier
                'callback': (eventArgs) => {
                    const selection = widget.getDataSource().getSelection().getSelection(PseudoClass.Hover);
                    if (selection == null) {
                        return '';
                    }
                    const data = {};
                    Object.entries(selection).forEach(([key, indices]) => {
                        data[key] = widget.getDataSource().getDataSeries(key).getValue(indices[0]);
                    });
                    tooltipRef.current.setData(data); // Setting data for tooltip using setData method setup in Tooltip component

                    // Important to return a non-empty string, so the tooltip will show
                    // The returned string does not matter in this case, because we use setText method setup
                    // in Tooltip component to change tooltip text
                    // so returning an empty string to hide tooltip and vice versa.
                    return 'a';
                }
            }
        });
    }
}, [tooltipRef.current]);
```

### [#](#/pages/reactNativeFirstSteps#hoveringBehavior) Emulate hovering behavior

In mobile application, there is no concept of hovering. So we can have similar behavior by adding a timer, whenever user taps and holds for a period of time, then we can show tooltip.

We can do that by providing callbacks for `onTouchStart`, `onTouchMove`, `onTouchEnd` props in CarnacView.

main
```ts

const DEFAULT_HOLD_TIMEOUT = 300;
const crosshairTimeout = useRef(null);

function useToolTipTool (enabled, touchInfo) {
    // Disabled all other tools except TooltipTool, CrossHair and Selection
    if (enabled === true) {
        widget.getToolByName('cross-hair').setPosition(new Point(touchInfo.x, touchInfo.y));
        widget.setProperties({
            'tools': {
                'crosshair': {
                    'enabled': true
                },
                'panning': {
                    'enabled': false
                },
                'selection': {
                    'enabled': true
                },
                'zoom': {
                    'enabled': false
                }
            },
            'tooltip': {
                'enabled': true
            }
        });
    } else {
        widget.setProperties({
            'tools': {
                'crosshair': {
                    'enabled': false
                },
                'panning': {
                    'enabled': true
                },
                'selection': {
                    'enabled': false
                },
                'zoom': {
                    'enabled': true
                }
            },
            'tooltip': {
                'enabled': false
            }
        });
    }
}

function onTouchStart (touchInfo) {
    useToolTipTool(false, touchInfo);
    clearTimeout(crosshairTimeout.current);
    crosshairTimeout.current = setTimeout(() => {
        useToolTipTool(true, touchInfo);
    }, DEFAULT_HOLD_TIMEOUT);
}

function onTouchMove (touchInfo) {
    clearTimeout(crosshairTimeout.current);
}

function onTouchEnd (touchInfo) {
    useToolTipTool(false, touchInfo);
    clearTimeout(crosshairTimeout.current);
}

useEffect(() => () => {
    if (widget != null) {
        widget.dispose();
        // Clear cross-hair timeout when the component is unmounted
        clearTimeout(crosshairTimeout.current);
    }
}, [widget]);

useEffect(() => {
    if (widget != null) {
        // Disabled/hide tooltip when the widget is created
        useToolTipTool(false);
        widget.setProperties({
            'tooltip': {
                'alignment': AnchorType.LeftCenter,
                'offsetx': 15,
                'offsety': 50,
                'divelement': tooltipRef.current.getContainer(),
                'callback': (eventArgs) => {
                    const selection = widget.getDataSource().getSelection().getSelection(PseudoClass.Hover);
                    if (selection == null) {
                        return '';
                    }
                    const data = {};
                    Object.entries(selection).forEach(([key, indices]) => {
                        data[key] = widget.getDataSource().getDataSeries(key).getValue(indices[0]);
                    });
                    tooltipRef.current.setData(data);
                    return 'a';
                }
            }
        });
    }
}, [tooltipRef.current]);

return (
    <View style={{flex: 1}}>
        <CarnacView
            style={{flex: 1}}
            root={widget}
            // Add callbacks to CarnacView props
            onTouchStart={onTouchStart}
            onTouchMove={onTouchMove}
            onTouchEnd={onTouchEnd}
        >
        <Tooltip ref={tooltipRef} metaData={[
            {
                'id': 'x',
                'name': 'Day'
            },
            {
                'id': 'y1',
                'name': 'Oil',
                'unit': 'gal',
                'symbolcolor': KnownColors.Orange
            },
            {
                'id': 'y2',
                'name': 'Gas',
                'unit': 'gal',
                'symbolcolor': KnownColors.Blue
            }
        ]} />
        </CarnacView>
    </View>
);
```

### [#](#/pages/reactNativeFirstSteps#completeCode) Completing the example

The code below is the complete code for this example.

Tooltip component

main
```ts
import React, {forwardRef, useImperativeHandle, useRef} from 'react';
import {Text, TextInput, View} from 'react-native';
import {RNElement} from '@int/reactnative/dom/RNElement';

export const Tooltip = forwardRef((props, ref) => {
    const {metaData} = props;
    const containerRef = useRef(null);
    const textRefs = useRef([]);

    useImperativeHandle(ref, () => ({
        getContainer: () => containerRef.current,
        setData: (data) => {
            metaData.forEach((metaData, index) => {
                textRefs.current[index].setNativeProps({text: data[metaData['id']].toString()});
            });
        }
    }));

    return (
        <RNElement
            ref={containerRef}
            style={{
                borderWidth: 1,
                borderRadius: 3,
                backgroundColor: 'rgba(255, 255, 255, 0.5)',
                zIndex: 999,
                display: 'none',
                padding: 10
            }}
        >
            {metaData.map((metaData, index) => (
                <View key={index} style={{flexDirection: 'row', alignItems: 'center'}}>
                    {metaData['symbolcolor'] != null ?
                        (
                            <View
                                style={{
                                    borderRadius: 5,
                                    backgroundColor: metaData['symbolcolor'],
                                    width: 10,
                                    height: 10,
                                    marginRight: 5
                                }}
                            />
                        ) : null
                    }
                    <Text style={{fontWeight: 'bold', fontSize: 18}}>
                        {metaData['name'] + ': '}
                    </Text>
                    <TextInput
                        style={{fontSize: 18, marginRight: 5}}
                        ref={(ref) => {
                            textRefs.current[index] = ref;
                        }}
                        editable={false}
                    />
                    {metaData['unit'] != null ?
                        (
                            <Text style={{fontSize: 18}}>
                                {metaData['unit']}
                            </Text>
                        ) : null
                    }
                </View>
            ))}
        </RNElement>
    );
});
```

PolylineChart component

main
```ts

import React, {useEffect, useMemo, useRef} from 'react';
import {Text, View} from 'react-native';

import {CarnacView} from '@int/reactnative/plot/CarnacView';
import {ChartType} from '@int/geotoolkit/charts/ChartType';
import {ChartWidget} from '@int/geotoolkit/charts/widgets/ChartWidget';
import {KnownColors} from '@int/geotoolkit/util/ColorUtil';
import {Point} from '@int/geotoolkit/util/Point';
import {DataTable} from '@int/geotoolkit/data/DataTable';
import {SelectionMode} from '@int/geotoolkit/charts/SelectionMode';
import {AnnotationLocation} from '@int/geotoolkit/layout/AnnotationLocation';

import {Tooltip} from './Tooltip';

const DEFAULT_HOLD_TIMEOUT = 300;

export const PolylineChart = () => {
    const tooltipRef = useRef(null);

    const widget = useMemo(() => {
        const widget = new ChartWidget({
            'data': new DataTable({
                'cols': [
                    {
                        'id': 'x',
                        'data': [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50]
                    },
                    {
                        'id': 'y1',
                        'name': 'Oil',
                        'data': [20, 42, 29, 40, 60, 57, 70, 92, 75, 81, 93, 98, 101, 123, 132,
                        125, 105, 112, 117, 104, 105, 107, 96, 101, 109, 100]
                    },
                    {
                        ': 'y2',
                        'name': 'Gas',
                        'data': [15, 17, 22, 30, 27, 31, 40, 42, 50, 51, 50, 60, 57, 59, 61, 50, 49, 53, 57, 50, 53, 52, 55, 59, 52, 57]
                    },
                ]
            }),
            'axis': {
                'x-axis': {
                    'location': AnnotationLocation.South,
                    'title': {
                        'text': 'Day',
                        'textstyle': '#757575'
                    }
                },
                'y-axis': {
                    'location': AnnotationLocation.West,
                    'dimension': {
                        'neatlimits': true
                    },
                    'title': {
                        'text': 'Volume (gal)',
                        'textstyle': '#757575'
                    }
                }
            },
            'selectionmode': SelectionMode.Vertical
        });
        widget.addChart({
            'type': ChartType.LineChart,
            'series': {
                'x': 'x', // Reference 'x' data from the DataSource
                'y': [{
                    'data': 'y1', // Reference 'y1' data from the DataSource
                    'linestyle': {
                        'color': KnownColors.Orange,
                        'width': 2.5
                    }
                }, {
                    'data': 'y2', // Reference 'y2' data from the DataSource
                    'linestyle': {
                        'color': KnownColors.Blue,
                        'width': 2.5
                    }
                }]
            },
            'axis': {
                'x': 'x-axis',
                'y': 'y-axis'
            }
        });
        return widget;
    }, []);
    const crosshairTimeout = useRef(null);

    function useToolTipTool (enabled, touchInfo) {
        // Disabled all other tools except TooltipTool, CrossHair and Selection
        if (enabled === true) {
            widget.getToolByName('cross-hair').setPosition(new Point(touchInfo.x, touchInfo.y));
            widget.setProperties({
                'tools': {
                    'crosshair': {
                        'enabled': true
                    },
                    'panning': {
                        'enabled': false
                    },
                    'selection': {
                        'enabled': true
                    },
                    'zoom': {
                        'enabled': false
                    }
                },
                'tooltip': {
                    'enabled': true
                }
            });
        } else {
            widget.setProperties({
                'tools': {
                    'crosshair': {
                        'enabled': false
                    },
                    'panning': {
                        'enabled': true
                    },
                    'selection': {
                        'enabled': false
                    },
                    'zoom': {
                        'enabled': true
                    }
                },
                'tooltip': {
                    'enabled': false
                }
            });
        }
    }

    function onTouchStart (touchInfo) {
        useToolTipTool(false, touchInfo);
        clearTimeout(crosshairTimeout.current);
        crosshairTimeout.current = setTimeout(() => {
            useToolTipTool(true, touchInfo);
        }, DEFAULT_HOLD_TIMEOUT);
    }

    function onTouchMove (touchInfo) {
        clearTimeout(crosshairTimeout.current);
    }

    function onTouchEnd (touchInfo) {
        useToolTipTool(false, touchInfo);
        clearTimeout(crosshairTimeout.current);
    }

    useEffect(() => () => {
        if (widget != null) {
            widget.dispose();
            clearTimeout(crosshairTimeout.current);
        }
    }, [widget]);

    useEffect(() => {
        if (widget != null) {
            useToolTipTool(false);
            widget.setProperties({
                'tooltip': {
                    'alignment': AnchorType.LeftCenter,
                    'offsetx': 15,
                    'offsety': 50,
                    'divelement': tooltipRef.current.getContainer(), // Provide RNElement ref we setup in Tooltip component earlier
                    'callback': (eventArgs) => {
                        const selection = widget.getDataSource().getSelection().getSelection(PseudoClass.Hover);
                        if (selection == null) {
                            return '';
                        }
                        const data = {};
                        Object.entries(selection).forEach(([key, indices]) => {
                            data[key] = widget.getDataSource().getDataSeries(key).getValue(indices[0]);
                        });
                        tooltipRef.current.setData(data); // Setting data for tooltip using setData method setup in Tooltip component

                        // Important to return a non-empty string, so the tooltip will show
                        // The returned string does not matter in this case, because we use setText method setup
                        // in Tooltip component to change tooltip text
                        // so returning an empty string to hide tooltip and vice versa.
                        return 'a';
                    }
                }
            });
        }
    }, [tooltipRef.current]);

    return (
        <View style={{flex: 1}}>
            <CarnacView
                style={{flex: 1}}
                root={widget}
                // Add callbacks to CarnacView props
                onTouchStart={onTouchStart}
                onTouchMove={onTouchMove}
                onTouchEnd={onTouchEnd}
            >
            <Tooltip ref={tooltipRef} metaData={[
                {
                    'id': 'x',
                    'name': 'Day'
                },
                {
                    'id': 'y1',
                    'name': 'Oil',
                    'unit': 'gal',
                    'symbolcolor': KnownColors.Orange
                },
                {
                    'id': 'y2',
                    'name': 'Gas',
                    'unit': 'gal',
                    'symbolcolor': KnownColors.Blue
                }
            ]} />
            </CarnacView>
        </View>
    );
};
```

The final application

img
### [#](#/pages/reactNativeFirstSteps#faq) FAQ

1. What to do if some command lines do not work properly on M1/M2 Mac?
You can add `arch -arm64` before each command line so it uses the ARM version of the package if available.
For example:
`arch -arm64 react-native run-ios`
2. XCode 15 shows `no template named 'unary_function' in namespace 'std'; did you mean '__unary_function'?` error when builds with iOS 17.
There is 2 ways to fix the error:
  - Open XCode and let XCode fixes it automatically by clicking "Fix" button at the error message appears in XCode
  - Or adding this code in Podfile:
​
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)',
'_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION']
end
end
end
Close
3. When building **Release** mode for iOS using XCode, if you encountered error `'value' is unavailable: introduced in iOS 12.0`.
  - The reason is that because the requirement iOS version is 12.4, but React-Folly version is 11.0.
  - Follow step by step using below instruction by modify XCode project settings:


### [#](#/pages/reactNativeFirstSteps#references) References

The *[Architecture Overview](#/pages/carnac/overview/carnac)* gives information about architecture of the toolkit.