Projekt

Obecné

Profil

Stáhnout (12.6 KB) Statistiky
| Větev: | Tag: | Revize:
1
import { Box, HStack, Pressable, View, Text, Flex, IconButton } from 'native-base';
2
import React, { useEffect, useRef, useState } from 'react';
3
import { StyleSheet, Dimensions, TouchableOpacity, GestureResponderEvent } from 'react-native';
4
import { PanGestureHandler, PinchGestureHandler, State, TapGestureHandler, TouchableWithoutFeedback } from 'react-native-gesture-handler';
5

    
6
import { findNodeHandle, UIManager } from 'react-native';
7

    
8
import Animated, {
9
    useAnimatedGestureHandler,
10
    useAnimatedStyle,
11
    useSharedValue,
12
} from 'react-native-reanimated';
13
import { PlanImage, Room } from '../../types/plan';
14
import Svg, { Path, SvgXml, Text as SvgText, G, Circle } from 'react-native-svg';
15

    
16
// @ts-ignore
17
import pointInSvgPolygon from "point-in-svg-polygon"
18
import { ExitfullscreenIcon, FullscreenIcon } from '../general/Icons';
19

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

    
22
    const DEFAULT_SCALE = 1
23
    const MIN_SCALE = 0.95
24

    
25
    const MAP_VIEW_SIZE = {
26
        height: 500,
27
        width: "100%"
28
    }
29

    
30
    const { mapImage, roomList, selectedRoom, height, setSelectedRoom } = props;
31

    
32
    const [svgDimensions, setSvgDimensions] = useState({ width: 0, height: 0 });
33

    
34
    const [fullScreenMode, setFullScreen] = useState(false);
35

    
36
    useEffect(() => {
37
        if (props.fullScreenMode) {
38
            setFullScreen(props.fullScreenMode)
39
        }
40
    }, [props.fullScreenMode])
41

    
42

    
43
    const panRef = useRef<React.ReactElement>();
44
    const pinchRef = useRef<React.ReactElement>();
45

    
46
    const svgRef = useRef<React.ReactElement>();
47

    
48
    const translateX = useSharedValue(0);
49
    const translateY = useSharedValue(0);
50
    const scale = useSharedValue(DEFAULT_SCALE);
51

    
52
    console.log(mapImage.svg.substring(0, 500))
53

    
54
    const onPanEvent = useAnimatedGestureHandler({
55
        // handle one finger -> drag / move
56
        onStart: (event, ctx: any) => {
57
            if (event.numberOfPointers === 1) {
58
                ctx.startX = translateX.value;
59
                ctx.startY = translateY.value;
60
            }
61
        },
62
        onActive: (event, ctx: any) => {
63
            if (event.numberOfPointers === 1) {
64
                translateX.value = ctx.startX + event.translationX;
65
                translateY.value = ctx.startY + event.translationY;
66
            }
67
        },
68
    });
69

    
70
    const onGestureEvent = useAnimatedGestureHandler({
71
        onStart: (_, ctx: any) => {
72
            ctx.startScale = scale.value;
73
        },
74
        onActive: (event: any, ctx: any) => {
75
            // handle two fingers -> zoom + -
76
            if (event.numberOfPointers === 2) {
77
                scale.value = ctx.startScale * event.scale;
78
            }
79
        },
80
        onEnd: (event) => {
81
            // handle two fingers -> zoom + -
82
            if (event.numberOfPointers === 2) {
83
                if (scale.value < MIN_SCALE) {
84
                    scale.value = MIN_SCALE;
85
                }
86
                // You may add additional logic for maximum scale if needed
87
            }
88
        },
89
    });
90

    
91
    const animatedStyle = useAnimatedStyle(() => {
92
        return {
93
            transform: [
94
                { translateX: translateX.value },
95
                { translateY: translateY.value },
96
                { scale: scale.value },
97
            ],
98
        };
99
    });
100

    
101

    
102
    function calculateStraightLineDistance(x1: number, y1: number, planX: number, planY: number, log?: boolean) {
103
        // Apply scale and translations to both points
104

    
105
        const x2 = planX
106
        const y2 = planY
107

    
108

    
109
        const x_distance = Math.abs(x1 - x2);
110
        const y_distance = Math.abs(y1 - y2);
111

    
112
        if (log) {
113
            console.log("Original X: ", x1, "Original Y: ", y1);
114
            console.log("Clicked X: ", planX, "Clicked Y: ", planY);
115
            console.log("Transformed X: ", x2, "Transformed Y: ", y2);
116
            console.log("Scale: ", scale.value, "TranslateX: ", translateX.value, "TranslateY: ", translateY.value);
117
            console.log("X Distance: ", x_distance, "Y Distance: ", y_distance);
118
        }
119
        return x_distance + y_distance;
120
    }
121

    
122
    const zoomOut = () => {
123
        translateX.value = 0;
124
        translateY.value = 0;
125
        scale.value = DEFAULT_SCALE;
126
    }
127

    
128
    const zoomToRoom = (room: Room) => {
129
        // Todo
130

    
131
        console.log(room)
132

    
133
        scale.value = 3;
134

    
135
        translateX.value = room.number_x + 100
136
        translateY.value = room.number_y + 100
137

    
138
    }
139

    
140
    const handleFullScreenPressed = () => {
141
        console.log("neco")
142
        if (scale.value != DEFAULT_SCALE || translateX.value != 0 || translateY.value != 0) {
143
            console.log("todo zoom out")
144
            zoomOut()
145
        }
146
        else {
147
            console.log("Toggling fullscreen")
148
            setFullScreen && setFullScreen(!fullScreenMode)
149
        }
150
    }
151

    
152
    const handleSvgPress = (event: GestureResponderEvent) => {
153

    
154
        // TODO ????????????
155

    
156
        // // Check if the touch event is within the bounds of a room
157
        // let clickedRoom: Room | undefined = undefined
158

    
159
        // // TODO set accordingaly
160
        // const maxNumberDistance = 100
161

    
162
        // let minDistance = Number.MAX_VALUE
163

    
164
        // for (let i = 0; i < roomList.length; i++) {
165
        //     const room: Room = roomList[i]
166
        //     if (room.in_plan) {
167

    
168
        //         // TODO
169
        //         console.log()
170
        //         console.log("Room + " + room.id + " x: " + room.number_x + " y: " + room.number_y)
171

    
172
        //         const currentDistance = calculateStraightLineDistance(room.number_x, room.number_y, locationX, locationY, false)
173

    
174
        //         if (currentDistance < minDistance) {
175
        //             minDistance = currentDistance
176
        //             clickedRoom = room
177
        //         }
178
        //     }
179
        // };
180

    
181
        // console.log()
182
        // console.log('Room clicked with id:', clickedRoom?.id);
183
        // console.log(minDistance)
184
        // if (clickedRoom && minDistance < maxNumberDistance) {
185
        //     // TODO        
186

    
187
        //     // Perform any actions you need with the clicked room
188

    
189
        //     // TODO fix -> point recognition
190
        //     setSelectedRoom && setSelectedRoom(clickedRoom)
191
        // } else {
192
        //     console.log("no room found")
193
        // }
194

    
195
    };
196

    
197
    console.log(Dimensions.get('window').height)
198

    
199
    return (
200
        // container
201
        <View
202
            width={!fullScreenMode ? MAP_VIEW_SIZE.width : Dimensions.get('window').width - 5
203
            }
204
            height={height ? height : (!fullScreenMode ? MAP_VIEW_SIZE.height : Dimensions.get('window').height - 62.5)}
205
            // @ts-ignore
206
            style={
207
                fullScreenMode ? {
208

    
209
                    position: "absolute",
210
                    top: -230,
211
                    left: 0,
212
                    zIndex: 1000,
213
                    backgroundColor: "white",
214

    
215
                    height: Dimensions.get('window').height - 120,
216
                    width: Dimensions.get('window').width - 20,
217

    
218

    
219
                }
220
                    :
221
                    {
222
                        overflow: "hidden",
223
                    }
224
            }
225
            borderColor={"light.300"}
226
            borderRadius={10}
227
            borderWidth={fullScreenMode ? 0 : 1}
228
        >
229
            {/* control panel */}
230
            <Flex direction="row" alignItems="center" justify="flex-end" style={{ height: 50, width: 100, top: 5, right: 10, position: "absolute", zIndex: 5 }}>
231
                <Pressable padding={1.5} backgroundColor={"#654B07"} borderRadius={5} marginRight={selectedRoom ? 1 : -2} onPress={handleFullScreenPressed}>
232
                    <FullscreenIcon color="white" />
233
                </Pressable>
234
                {
235
                    selectedRoom &&
236
                    <Pressable padding={1.5} backgroundColor={"#654B07"} borderRadius={5} marginRight={-2} onPress={() => { zoomToRoom(selectedRoom) }}>
237
                        <ExitfullscreenIcon color="white" />
238
                    </Pressable>
239
                }
240

    
241
            </Flex>
242

    
243
            <PinchGestureHandler
244
                ref={pinchRef}
245
                // @ts-ignore
246
                onGestureEvent={onGestureEvent}
247
                simultaneousHandlers={[svgRef, panRef]}>
248
                <Animated.View style={{ flex: 1 }}>
249
                    <PanGestureHandler
250
                        ref={panRef}
251
                        simultaneousHandlers={[svgRef, pinchRef]}
252
                        onGestureEvent={onPanEvent}
253
                        onHandlerStateChange={(nativeEvent: any) => {
254
                            if (nativeEvent.state === State.END) {
255
                                console.log(nativeEvent)
256
                            }
257
                        }}
258
                    >
259
                        <Animated.View style={[{
260
                            flex: 1,
261
                        }, animatedStyle]}>
262
                            <Svg
263
                                id="svgMap"
264
                                ref={(ref: any) => (svgRef.current = ref)}
265
                            >
266
                                {mapImage && mapImage.viewBox &&
267
                                    // background image                    
268
                                    <SvgXml
269
                                        xml={mapImage.svg}
270
                                        width={"100%"}
271
                                        height={"100%"}
272
                                        onLayout={(event) => {
273
                                            setSvgDimensions({
274
                                                width: event.nativeEvent.layout.width,
275
                                                height: event.nativeEvent.layout.height,
276
                                            });
277
                                        }}
278
                                    >
279
                                    </SvgXml>
280
                                }
281

    
282
                                {mapImage && roomList && roomList.length > 0 &&
283

    
284
                                    roomList.map((room, index) => {
285
                                        if (!room.in_plan) {
286
                                            return
287
                                        }
288
                                        return (
289
                                            <Path
290
                                                id={"roomList_" + index.toString()}
291
                                                key={'room_' + room.id}
292
                                                d={room.svg_path}  // The path data defining the shape of the room
293
                                                fill={selectedRoom && room.id == selectedRoom.id ? "#E6F7FF" : "white"}        // Fill the room shape with no color
294
                                                stroke="#66B2FF"       // Outline color
295
                                                strokeWidth={0.3}     // Outline width
296
                                                fillOpacity={selectedRoom && room.id == selectedRoom.id ? 1 : 0.2}
297
                                            />
298
                                        )
299
                                    })}
300

    
301

    
302

    
303
                                {mapImage && roomList && roomList.length > 0 &&
304

    
305
                                    roomList.map((room) => {
306
                                        if (!room.in_plan) {
307
                                            return
308
                                        }
309
                                        return (
310
                                            < SvgText
311
                                                x={room.number_x}     // Adjust the x-coordinate based on your room data
312
                                                y={room.number_y}     // Adjust the y-coordinate based on your room data
313
                                                fill="red"      // Text color
314
                                                fontSize={8}       // Font size
315
                                                textAnchor="middle"  // Center the text horizontally
316
                                                fontStyle='italic'
317
                                                vectorEffect='non-scaling-stroke' // Helps prevent stroke from scaling
318
                                            >
319
                                                {room.id}
320
                                            </SvgText>
321
                                        )
322
                                    })}
323

    
324
                            </Svg>
325
                        </Animated.View>
326
                    </PanGestureHandler>
327
                </Animated.View>
328
            </PinchGestureHandler >
329
        </View >
330
    );
331
};
332

    
333
export default CastlePlanView;
334

    
    (1-1/1)