I see in the canvas that the view box is set to the height and width of the device window. For use cases like ours where the map screen has a header/footer it causes the Polyline
to appear away from the finger.
import Svg, { Polyline } from 'react-native-svg';
import type { ICanvasProps } from './types';
import React, { FC } from 'react';
const Canvas: FC<ICanvasProps> = ({
path,
colorLine,
widthLine,
fillColorCanvas,
containerSize,
}) => {
return (
<Svg
height="100%"
width="100%"
viewBox={`0 0 ${containerSize.width} ${containerSize.height}`}
>
<Polyline
fill={fillColorCanvas}
stroke={colorLine}
points={path}
strokeWidth={widthLine}
/>
</Svg>
);
};
export default Canvas;
import React, {
useRef,
RefObject,
useCallback,
forwardRef,
useMemo,
useState,
} from 'react';
import MapView from 'react-native-maps';
import { StyleSheet, useWindowDimensions, View } from 'react-native';
import { Canvas } from '../canvas';
import { GestureHandler } from '../gesture';
import type { IMapProps } from './types';
import {
DEFAULT_ACTIVE_COLOR_LINE_WIDTH,
DEFAULT_FILL_BACKGROUND_CANVAS,
DEFAULT_BACKGROUND_VIEW_CANVAS,
DEFAULT_INDEX_INITIAL_LAT_LNG,
DEFAULT_CREATED_NEW_POLYGON,
DEFAULT_ACTIVE_COLOR_LINE,
DEFAULT_UNIT_DISTANCE,
DEFAULT_DRAW_MODE,
} from './contstant';
import * as _GEO from 'geolib';
import type { ILocationProps } from './types';
import useValidator from '../hooks/use-validator';
export default forwardRef<MapView, IMapProps>((props, ref) => {
useValidator(props);
const {
points,
children,
colorLine = DEFAULT_ACTIVE_COLOR_LINE,
widthLine = DEFAULT_ACTIVE_COLOR_LINE_WIDTH,
onEndDraw,
isDrawMode = DEFAULT_DRAW_MODE,
renderPath,
onStartDraw,
unitDistance = DEFAULT_UNIT_DISTANCE,
onChangePoints,
createdPolygon = DEFAULT_CREATED_NEW_POLYGON,
fillColorCanvas = DEFAULT_FILL_BACKGROUND_CANVAS,
styleViewGesture,
backgroundCanvas = DEFAULT_BACKGROUND_VIEW_CANVAS,
...rest
} = props;
const internalRef = useRef<MapView>(null);
const mapRef = (ref as RefObject<MapView>) || internalRef;
const { width, height } = useWindowDimensions();
const [containerSize, setContainerSize] = useState({ width, height });
const containerStyle = useMemo(
() => [
{ zIndex: 1, backgroundColor: backgroundCanvas },
StyleSheet.absoluteFill,
styleViewGesture,
],
[backgroundCanvas, styleViewGesture],
);
const path = useMemo(
() => points.map((item) => `${item.x},${item.y}`).join(' '),
[points],
);
const calculatedCenterPolygon = (coordinates: ILocationProps[]) =>
Promise.resolve(_GEO.getCenter(coordinates));
const convertPointToCoordinates = useCallback(
(polygons) => {
if (polygons && polygons.length > 0) {
calculatedCenterPolygon(polygons).then((centerLatLng) => {
if (onEndDraw && centerLatLng) {
const distance = _GEO.convertDistance(
_GEO.getPathLength(polygons),
unitDistance,
);
const initialLatLng = polygons[DEFAULT_INDEX_INITIAL_LAT_LNG];
const lastLatLng = polygons[polygons.length - 1];
onEndDraw({
polygons,
distance,
centerLatLng,
initialLatLng,
lastLatLng,
});
}
});
}
},
[onEndDraw, unitDistance],
);
const convertByPoint = useCallback(
async (item) => await mapRef.current?.coordinateForPoint(item),
[mapRef],
);
const handleEndDraw = useCallback(
async (data) => {
await Promise.all(data.map(convertByPoint)).then(convertPointToCoordinates);
},
[convertByPoint, convertPointToCoordinates],
);
const handleSetContainerSize = useCallback((event) => { // <---Added this function to calculate size of View container
setContainerSize({
width: event.nativeEvent.layout.width,
height: event.nativeEvent.layout.height,
});
}, []);
const hasCanvas = useMemo(() => {
return (
<View style={containerStyle} onLayout={handleSetContainerSize}>
<>
{renderPath ? (
renderPath(path)
) : (
<Canvas
containerSize={containerSize} // <--------- Passing to canvas here
path={path}
widthLine={widthLine}
colorLine={colorLine}
fillColorCanvas={fillColorCanvas}
/>
)}
<GestureHandler
onEndTouchEvents={handleEndDraw}
onStartTouchEvents={onStartDraw}
onChangeTouchEvents={onChangePoints}
/>
</>
</View>
);
}, [
containerSize,
handleSetContainerSize,
path,
widthLine,
colorLine,
renderPath,
onStartDraw,
handleEndDraw,
containerStyle,
onChangePoints,
fillColorCanvas,
]);
const hasMap = (
<MapView scrollEnabled={!isDrawMode} ref={mapRef} {...rest}>
{children}
</MapView>
);
return (
<>
{hasMap}
{!createdPolygon && hasCanvas}
</>
);
});
Just a suggestion, feel free to use or update as you want. Thanks!