Projekt

Obecné

Profil

Stáhnout (13.1 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 { mapImage, roomList, selectedRoom, height, setSelectedRoom } = props;
26

    
27

    
28
    const [fullScreenMode, setFullScreen] = useState(false);
29

    
30
    useEffect(() => {
31
        if (props.fullScreenMode) {
32
            setFullScreen(props.fullScreenMode)
33
        }
34
    }, [props.fullScreenMode])
35

    
36

    
37
    const panRef = useRef<React.ReactElement>();
38
    const pinchRef = useRef<React.ReactElement>();
39

    
40
    const svgRef = useRef<React.ReactElement>();
41

    
42
    const translateX = useSharedValue(0);
43
    const translateY = useSharedValue(0);
44
    const scale = useSharedValue(DEFAULT_SCALE);
45

    
46
    console.log(mapImage.svg.substring(0, 500))
47

    
48
    const onPanEvent = useAnimatedGestureHandler({
49
        // handle one finger -> drag / move
50
        onStart: (event, ctx: any) => {
51
            if (event.numberOfPointers === 1) {
52
                ctx.startX = translateX.value;
53
                ctx.startY = translateY.value;
54
            }
55
        },
56
        onActive: (event, ctx: any) => {
57
            if (event.numberOfPointers === 1) {
58
                translateX.value = ctx.startX + event.translationX;
59
                translateY.value = ctx.startY + event.translationY;
60
            }
61
        },
62
    });
63

    
64
    const onGestureEvent = useAnimatedGestureHandler({
65
        onStart: (_, ctx: any) => {
66
            ctx.startScale = scale.value;
67
        },
68
        onActive: (event: any, ctx: any) => {
69
            // handle two fingers -> zoom + -
70
            if (event.numberOfPointers === 2) {
71
                scale.value = ctx.startScale * event.scale;
72
            }
73
        },
74
        onEnd: (event) => {
75
            // handle two fingers -> zoom + -
76
            if (event.numberOfPointers === 2) {
77
                if (scale.value < MIN_SCALE) {
78
                    scale.value = MIN_SCALE;
79
                }
80
                // You may add additional logic for maximum scale if needed
81

    
82
                console.log("scale")
83
                console.log(scale.value)
84
            }
85
        },
86
    });
87

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

    
98

    
99
    function calculateStraightLineDistance(x1: number, y1: number, planX: number, planY: number) {
100
        // Apply scale and translations to both points
101

    
102
        const x2 = planX
103
        const y2 = planY
104

    
105
        const x_distance = Math.abs(x1 - x2);
106
        const y_distance = Math.abs(y1 - y2);
107

    
108
        return x_distance + y_distance;
109
    }
110

    
111
    const zoomOut = () => {
112
        translateX.value = 0;
113
        translateY.value = 0;
114
        scale.value = DEFAULT_SCALE;
115
    }
116

    
117
    const zoomToRoom = (room: Room) => {
118
        // Todo
119

    
120
        console.log(room)
121

    
122
        scale.value = 3;
123

    
124
        translateX.value = room.number_x + 100
125
        translateY.value = room.number_y + 100
126

    
127
    }
128

    
129
    const handleFullScreenPressed = () => {
130
        if (scale.value != DEFAULT_SCALE || translateX.value != 0 || translateY.value != 0) {
131
            console.log("todo zoom out")
132
            zoomOut()
133
        }
134
        else {
135
            console.log("Toggling fullscreen")
136
            setFullScreen && setFullScreen(!fullScreenMode)
137
        }
138
    }
139

    
140
    const handleSvgPress = (event: GestureResponderEvent) => {
141

    
142
        // TODO ????????????
143

    
144
        const locationX = event.nativeEvent.locationX
145
        const locationY = event.nativeEvent.locationY
146

    
147
        // console.log("x " + event.nativeEvent.locationX + " y " + event.nativeEvent.locationY)
148
        console.log("view size:")
149
        console.log("x " + viewSize.width + " y " + viewSize.height)        
150
        console.log("svg size:")
151
        console.log("x " + mapImage.viewBox.width + " y " + mapImage.viewBox.height)
152

    
153
        let mapX =  (locationX / viewSize.width) * mapImage.viewBox.width
154
        let mapY =  (locationY / viewSize.height) * mapImage.viewBox.height
155

    
156

    
157
        // if()
158
        
159

    
160

    
161

    
162
        // console.log("x " + mapX + " y " + mapY)
163
        // console.log("")
164

    
165
        // Check if the touch event is within the bounds of a room
166
        let clickedRoom: Room | undefined = undefined
167

    
168
        // TODO set accordingaly
169
        const maxNumberDistance = 100
170

    
171
        let minDistance = Number.MAX_VALUE
172

    
173
        for (let i = 0; i < roomList.length; i++) {
174
            const room: Room = roomList[i]
175
            if (room.in_plan) {
176
                // TODO
177
                // console.log()
178
                console.log("Room + " + room.id + " x: " + room.number_x + " y: " + room.number_y)
179

    
180
                const currentDistance = calculateStraightLineDistance(room.number_x, room.number_y, mapX, mapY)
181

    
182
                if (currentDistance < minDistance) {
183
                    minDistance = currentDistance
184
                    clickedRoom = room
185
                }
186
            }
187
        };
188

    
189
        console.log()
190
        console.log('Room clicked with id:', clickedRoom?.id);
191
        console.log("x " + clickedRoom?.number_x + " y " + clickedRoom?.number_y)
192
        console.log(minDistance)
193
        console.log("clicked: x " + locationX + " y " + locationY)
194
        console.log("translated clicked: x " + mapX + " y " + mapY)
195

    
196
        if (clickedRoom && minDistance < maxNumberDistance) {
197
            // TODO        
198

    
199
            // Perform any actions you need with the clicked room
200

    
201
            // TODO fix -> point recognition
202
            setSelectedRoom && setSelectedRoom(clickedRoom)
203
        } else {
204
            console.log("no room found")
205
        }
206
        console.log("")
207
    };
208

    
209
    const [viewSize, setViewSize] = useState({ height: 0, width: 0 });
210

    
211
    useEffect(() => {
212
        setViewSize({
213
            width: fullScreenMode ?
214
                Dimensions.get('window').width - 20 : // full screen
215
                Dimensions.get('window').width - 20, // not full screen
216
            height: fullScreenMode ?
217
                Dimensions.get('window').height - 122.5 : // full scren
218
                Dimensions.get('window').height -350, // not full screen
219
        })
220
    }, [fullScreenMode])
221

    
222

    
223
    return (
224
        // container
225
        <View
226
            height={viewSize.height}
227
            width={viewSize.width}
228
            // @ts-ignore
229
            style={
230
                fullScreenMode ? {
231
                    position: "absolute",
232
                    top: -230,
233
                    left: 0,
234
                    zIndex: 1000,
235
                    backgroundColor: "white",
236
                }
237
                    :
238
                    {
239
                        overflow: "hidden",
240
                    }
241
            }
242
            borderColor={"light.300"}
243
            borderRadius={10}
244
            borderWidth={fullScreenMode ? 0 : 1}
245
        >
246
            {/* control panel */}
247
            <Flex direction="row" alignItems="center" justify="flex-end" style={{ height: 50, width: 100, top: fullScreenMode? 10 : 0, right: fullScreenMode ? 20 : 15, position: "absolute", zIndex: 5 }}>
248
                <Pressable padding={1.5} backgroundColor={"#654B07"} borderRadius={5} marginRight={selectedRoom ? 1 : -2} onPress={handleFullScreenPressed}>
249
                    <FullscreenIcon color="white" />
250
                </Pressable>
251
                {
252
                    selectedRoom &&
253
                    <Pressable padding={1.5} backgroundColor={"#654B07"} borderRadius={5} marginRight={-2} onPress={() => { zoomToRoom(selectedRoom) }}>
254
                        <ExitfullscreenIcon color="white" />
255
                    </Pressable>
256
                }
257

    
258
            </Flex>
259

    
260
            <PinchGestureHandler
261
                ref={pinchRef}
262
                // @ts-ignore
263
                onGestureEvent={onGestureEvent}
264
                simultaneousHandlers={[svgRef, panRef]}>
265
                <Animated.View style={[{ flex: 1 }, animatedStyle]}>
266
                    <PanGestureHandler
267
                        ref={panRef}
268
                        simultaneousHandlers={[svgRef, pinchRef]}
269
                        onGestureEvent={onPanEvent}
270
                        onHandlerStateChange={(nativeEvent: any) => {
271
                            if (nativeEvent.state === State.END) {
272
                                console.log(nativeEvent)
273
                            }
274
                        }}
275
                    >
276
                        <Animated.View style={[{
277
                            flex: 1,
278
                        }]}>
279
                            <Svg
280
                                id="svgMap"
281
                                onPress={handleSvgPress}
282
                            >
283
                                {mapImage && mapImage.viewBox &&
284
                                    // background image                    
285
                                    <SvgXml
286
                                        xml={mapImage.svg}
287
                                        width={"100%"}
288
                                        height={"100%"}
289
                                        viewBox={`${0} ${0} ${mapImage.viewBox.width} ${mapImage.viewBox.height}`}
290
                                        // onLayout={(event) => {
291
                                        //     setSvgDimensions({
292
                                        //         width: event.nativeEvent.layout.width,
293
                                        //         height: event.nativeEvent.layout.height,
294
                                        //     });
295
                                        // }}
296
                                    >
297
                                    </SvgXml>
298
                                }
299

    
300
                                {mapImage && roomList && roomList.length > 0 &&
301

    
302
                                    roomList.map((room, index) => {
303
                                        if (!room.in_plan) {
304
                                            return
305
                                        }
306
                                        return (
307
                                            <Path
308
                                                id={"roomList_" + index.toString()}
309
                                                d={room.svg_path}  // The path data defining the shape of the room
310
                                                fill={selectedRoom && room.id == selectedRoom.id ? "#E6F7FF" : "white"}        // Fill the room shape with no color
311
                                                stroke="#66B2FF"       // Outline color
312
                                                strokeWidth={0.3}     // Outline width
313
                                                fillOpacity={selectedRoom && room.id == selectedRoom.id ? 1 : 0.2}
314
                                            />
315
                                        )
316
                                    })}
317

    
318

    
319

    
320
                                {mapImage && roomList && roomList.length > 0 &&
321

    
322
                                    roomList.map((room) => {
323
                                        if (!room.in_plan) {
324
                                            return
325
                                        }
326
                                        return (
327
                                            < SvgText
328
                                                x={room.number_x}     // Adjust the x-coordinate based on your room data
329
                                                y={room.number_y}     // Adjust the y-coordinate based on your room data
330
                                                fill="red"      // Text color
331
                                                fontSize={8}       // Font size
332
                                                textAnchor="middle"  // Center the text horizontally
333
                                                fontStyle='italic'
334
                                                vectorEffect='non-scaling-stroke' // Helps prevent stroke from scaling
335
                                            >
336
                                                {room.id}
337
                                            </SvgText>
338
                                        )
339
                                    })}
340

    
341
                            </Svg>
342
                        </Animated.View>
343
                    </PanGestureHandler>
344
                </Animated.View>
345
            </PinchGestureHandler >
346
        </View >
347
    );
348
};
349

    
350
export default CastlePlanView;
351

    
    (1-1/1)