Projekt

Obecné

Profil

Stáhnout (10.5 KB) Statistiky
| Větev: | Tag: | Revize:
1
import { Box } from 'native-base';
2
import React, { useRef } from 'react';
3
import { StyleSheet, Dimensions, TouchableOpacity, GestureResponderEvent } from 'react-native';
4
import { PanGestureHandler, PinchGestureHandler, State, TapGestureHandler } from 'react-native-gesture-handler';
5
import Animated, {
6
    useAnimatedGestureHandler,
7
    useAnimatedStyle,
8
    useSharedValue,
9
} from 'react-native-reanimated';
10
import { PlanImage, Room } from '../../types/plan';
11
import Svg, { Path, SvgXml, Text } from 'react-native-svg';
12

    
13
// @ts-ignore
14
import pointInSvgPolygon from "point-in-svg-polygon"
15

    
16
const CastlePlanView = (props: { mapImage: PlanImage, roomList: Room[], selectedRoom?: Room, fullScreenMode?: boolean, height?: number, setSelectedRoom?: (room: Room) => void }) => {
17

    
18
    const DEFAULT_SCALE = 1
19
    const MIN_SCALE = 0.95
20

    
21
    const MAP_VIEW_SIZE = {
22
        height: 500,
23
        width: "100%"
24
    }
25

    
26
    const { mapImage, roomList, selectedRoom, fullScreenMode, height, setSelectedRoom } = props;
27

    
28
    const panRef = useRef<React.ReactElement>();
29
    const pinchRef = useRef<React.ReactElement>();
30

    
31
    const svgRef = useRef<React.ReactElement>();
32

    
33
    const translateX = useSharedValue(0);
34
    const translateY = useSharedValue(0);
35
    const scale = useSharedValue(DEFAULT_SCALE);
36

    
37
    console.log(mapImage.svg.substring(0, 500))
38

    
39
    const onPanEvent = useAnimatedGestureHandler({
40
        // handle one finger -> drag / move
41
        onStart: (event, ctx: any) => {
42
            if (event.numberOfPointers === 1) {
43
                ctx.startX = translateX.value;
44
                ctx.startY = translateY.value;
45
            }
46
        },
47
        onActive: (event, ctx: any) => {
48
            if (event.numberOfPointers === 1) {
49
                translateX.value = ctx.startX + event.translationX;
50
                translateY.value = ctx.startY + event.translationY;
51
            }
52
        },
53
    });
54

    
55
    const onGestureEvent = useAnimatedGestureHandler({
56
        onStart: (_, ctx: any) => {
57
            ctx.startScale = scale.value;
58
        },
59
        onActive: (event: any, ctx: any) => {
60
            // handle two fingers -> zoom + -
61
            if (event.numberOfPointers === 2) {
62
                scale.value = ctx.startScale * event.scale;
63
            }
64
        },
65
        onEnd: (event) => {
66
            // handle two fingers -> zoom + -
67
            if (event.numberOfPointers === 2) {
68
                if (scale.value < MIN_SCALE) {
69
                    scale.value = MIN_SCALE;
70
                }
71
                // You may add additional logic for maximum scale if needed
72
            }
73
        },
74
    });
75

    
76
    const animatedStyle = useAnimatedStyle(() => {
77
        return {
78
            transform: [
79
                { translateX: translateX.value },
80
                { translateY: translateY.value },
81
                { scale: scale.value },
82
            ],
83
        };
84
    });
85

    
86

    
87
    function calculateStraightLineDistance(x1: number, y1: number, planX: number, planY: number, log?: boolean) {
88
        // Apply scale and translations to both points
89

    
90
        const xOffset = 250
91
        const yOffset = 120
92

    
93
        const x2 = planX + xOffset
94
        const y2 = planY + yOffset
95

    
96

    
97
        const x_distance = Math.abs(x1 - x2);
98
        const y_distance = Math.abs(y1 - y2);
99

    
100
        if (log) {
101
            console.log("Original X: ", x1, "Original Y: ", y1);
102
            console.log("Clicked X: ", planX, "Clicked Y: ", planY);
103
            console.log("Transformed X: ", x2, "Transformed Y: ", y2);
104
            console.log("Scale: ", scale.value, "TranslateX: ", translateX.value, "TranslateY: ", translateY.value);
105
            console.log("X Distance: ", x_distance, "Y Distance: ", y_distance);
106
        }
107
        return x_distance + y_distance;
108
    }
109

    
110

    
111
    const handleSvgPress = (event: GestureResponderEvent) => {
112

    
113
        // Get the raw event coordinates
114
        const rawLocationX = event.nativeEvent.locationX;
115
        const rawLocationY = event.nativeEvent.locationY;
116

    
117
        // Log raw coordinates
118
        console.log("Raw Location X: ", rawLocationX, "Raw Location Y: ", rawLocationY);
119

    
120
        // If needed, you can get the SVG element's dimensions to normalize the coordinates
121
        const svgWidth = Dimensions.get('window').width
122
        const svgHeight = height ? height : (!fullScreenMode ? MAP_VIEW_SIZE.height : Dimensions.get('window').height - 62.5)
123

    
124
        // Normalize the coordinates based on the SVG dimensions
125
        // @ts-ignore
126
        const locationX = (rawLocationX / svgWidth) * 100;
127
        const locationY = (rawLocationY / svgHeight) * 100;
128

    
129

    
130
        // Check if the touch event is within the bounds of a room
131
        let clickedRoom: Room | undefined = undefined
132

    
133
        // TODO set accordingaly
134
        const maxNumberDistance = 100
135

    
136
        let minDistance = Number.MAX_VALUE
137

    
138
        for (let i = 0; i < roomList.length; i++) {
139
            const room: Room = roomList[i]
140
            if (room.in_plan) {
141

    
142
                const currentDistance = calculateStraightLineDistance(room.number_x, room.number_y, locationX, locationY, true)
143

    
144
                if (currentDistance < minDistance) {
145
                    minDistance = currentDistance
146
                    clickedRoom = room
147
                }
148
            }
149
        };
150

    
151
        console.log('Room clicked with id:', clickedRoom.id);
152
        console.log(minDistance)
153
        if (clickedRoom && minDistance < maxNumberDistance) {
154
            // TODO        
155

    
156
            // Perform any actions you need with the clicked room
157

    
158
            // TODO fix -> point recognition
159
            setSelectedRoom && setSelectedRoom(clickedRoom)
160
        } else {
161
            console.log("no room found")
162
        }
163
    };
164

    
165
    return (
166
        // container
167
        <Box
168
            width={!fullScreenMode ? MAP_VIEW_SIZE.width : Dimensions.get('window').width - 5
169
            }
170
            height={height ? height : (!fullScreenMode ? MAP_VIEW_SIZE.height : Dimensions.get('window').height - 62.5)}
171
            // @ts-ignore
172
            style={
173
                fullScreenMode ? {
174
                    marginTop: 2.5,
175
                    marginLeft: 2.5,
176
                    marginRight: 2.5,
177
                }
178
                    :
179
                    { overflow: "hidden" }
180
            }
181
            borderColor={"light.300"}
182
            borderRadius={10}
183
            borderWidth={1}
184
        >
185

    
186
            <PinchGestureHandler
187
                ref={pinchRef}
188
                // @ts-ignore
189
                onGestureEvent={onGestureEvent}
190
                simultaneousHandlers={[svgRef, panRef]}>
191
                <Animated.View style={{ flex: 1 }}>
192
                    <PanGestureHandler
193
                        ref={panRef}
194
                        simultaneousHandlers={[svgRef, pinchRef]}
195
                        onGestureEvent={onPanEvent}
196
                        onHandlerStateChange={(nativeEvent: any) => {
197
                            if (nativeEvent.state === State.END) {
198
                                console.log(nativeEvent)
199
                            }
200
                        }}
201
                    >
202
                        <Animated.View style={[{
203
                            flex: 1,
204
                        }, animatedStyle]}>
205
                            <Svg
206
                                id="svgMap"
207
                                ref={(ref: any) => (svgRef.current = ref)}
208
                                onPress={handleSvgPress}
209
                            >
210
                                {mapImage && mapImage.viewBox &&
211
                                    // background image                    
212
                                    <SvgXml
213
                                        xml={mapImage.svg}
214
                                        width={"100%"}
215
                                        height={"100%"}
216
                                    />
217
                                }
218

    
219
                                {mapImage && roomList && roomList.length > 0 &&
220

    
221
                                    roomList.map((room, index) => {
222
                                        if (!room.in_plan) {
223
                                            return
224
                                        }
225
                                        return (
226
                                            <Path
227
                                                id={"roomList_" + index.toString()}
228
                                                key={'room_' + room.id}
229
                                                d={room.svg_path}  // The path data defining the shape of the room
230
                                                fill={selectedRoom && room.id == selectedRoom.id ? "#E6F7FF" : "white"}        // Fill the room shape with no color
231
                                                stroke="#66B2FF"       // Outline color
232
                                                strokeWidth={0.3}     // Outline width
233
                                                fillOpacity={selectedRoom && room.id == selectedRoom.id ? 1 : 0.2}
234
                                            />
235
                                        )
236
                                    })}
237

    
238
                                {mapImage && roomList && roomList.length > 0 &&
239

    
240
                                    roomList.map((room) => {
241
                                        if (!room.in_plan) {
242
                                            return
243
                                        }
244
                                        return (
245
                                            < Text
246
                                                x={room.number_x}     // Adjust the x-coordinate based on your room data
247
                                                y={room.number_y}     // Adjust the y-coordinate based on your room data
248
                                                fill="red"      // Text color
249
                                                fontSize={8}       // Font size
250
                                                textAnchor="middle"  // Center the text horizontally
251
                                                fontStyle='italic'
252
                                                vectorEffect='non-scaling-stroke' // Helps prevent stroke from scaling
253
                                            >
254
                                                {room.id}
255
                                            </Text>
256
                                        )
257
                                    })}
258
                            </Svg>
259
                        </Animated.View>
260
                    </PanGestureHandler>
261
                </Animated.View>
262
            </PinchGestureHandler >
263
        </Box >
264
    );
265
};
266

    
267
export default CastlePlanView;
268

    
    (1-1/1)