Projekt

Obecné

Profil

Stáhnout (13.7 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

    
151
        const viewRatio =  viewSize.width / viewSize.height
152
        console.log("ratio: " + viewSize.width / viewSize.height)       
153
        console.log("svg size:")
154
        console.log("x " + mapImage.viewBox.width + " y " + mapImage.viewBox.height)
155
        const svgRatio = mapImage.viewBox.width / mapImage.viewBox.height
156
        console.log("ratio: " + mapImage.viewBox.width / mapImage.viewBox.height)    
157

    
158
        let mapX =  (locationX / viewSize.width) * mapImage.viewBox.width
159
        let mapY =  (locationY / viewSize.height) * mapImage.viewBox.height
160

    
161
        if(svgRatio > viewRatio){
162
            // svg is spaced in the middle 
163
            // top down is filled
164

    
165

    
166
            // TODO recalculate mapY
167
        }
168
        else if(svgRatio < viewRatio){
169
            // svg is spaced in the center 
170
            // left right is filled
171

    
172
            // TODO recalculate mapX
173
        }
174

    
175
        // console.log("x " + mapX + " y " + mapY)
176
        // console.log("")
177

    
178
        // Check if the touch event is within the bounds of a room
179
        let clickedRoom: Room | undefined = undefined
180

    
181
        // TODO set accordingaly
182
        const maxNumberDistance = 100
183

    
184
        let minDistance = Number.MAX_VALUE
185

    
186
        for (let i = 0; i < roomList.length; i++) {
187
            const room: Room = roomList[i]
188
            if (room.in_plan) {
189
                // TODO
190
                // console.log()
191
                console.log("Room + " + room.id + " x: " + room.number_x + " y: " + room.number_y)
192

    
193
                const currentDistance = calculateStraightLineDistance(room.number_x, room.number_y, mapX, mapY)
194

    
195
                if (currentDistance < minDistance) {
196
                    minDistance = currentDistance
197
                    clickedRoom = room
198
                }
199
            }
200
        };
201

    
202
        console.log()
203
        console.log('Room clicked with id:', clickedRoom?.id);
204
        console.log("x " + clickedRoom?.number_x + " y " + clickedRoom?.number_y)
205
        console.log(minDistance)
206
        console.log("clicked: x " + locationX + " y " + locationY)
207
        console.log("translated clicked: x " + mapX + " y " + mapY)
208

    
209
        if (clickedRoom && minDistance < maxNumberDistance) {
210
            // TODO        
211

    
212
            // Perform any actions you need with the clicked room
213

    
214
            // TODO fix -> point recognition
215
            setSelectedRoom && setSelectedRoom(clickedRoom)
216
        } else {
217
            console.log("no room found")
218
        }
219
        console.log("")
220
    };
221

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

    
224
    useEffect(() => {
225
        setViewSize({
226
            width: fullScreenMode ?
227
                Dimensions.get('window').width - 20 : // full screen
228
                Dimensions.get('window').width - 20, // not full screen
229
            height: fullScreenMode ?
230
                Dimensions.get('window').height - 122.5 : // full scren
231
                Dimensions.get('window').height -350, // not full screen
232
        })
233
    }, [fullScreenMode])
234

    
235

    
236
    return (
237
        // container
238
        <View
239
            height={viewSize.height}
240
            width={viewSize.width}
241
            // @ts-ignore
242
            style={
243
                fullScreenMode ? {
244
                    position: "absolute",
245
                    top: -230,
246
                    left: 0,
247
                    zIndex: 1000,
248
                    backgroundColor: "white",
249
                }
250
                    :
251
                    {
252
                        overflow: "hidden",
253
                    }
254
            }
255
            borderColor={"light.300"}
256
            borderRadius={10}
257
            borderWidth={fullScreenMode ? 0 : 1}
258
        >
259
            {/* control panel */}
260
            <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 }}>
261
                <Pressable padding={1.5} backgroundColor={"#654B07"} borderRadius={5} marginRight={selectedRoom ? 1 : -2} onPress={handleFullScreenPressed}>
262
                    <FullscreenIcon color="white" />
263
                </Pressable>
264
                {
265
                    selectedRoom &&
266
                    <Pressable padding={1.5} backgroundColor={"#654B07"} borderRadius={5} marginRight={-2} onPress={() => { zoomToRoom(selectedRoom) }}>
267
                        <ExitfullscreenIcon color="white" />
268
                    </Pressable>
269
                }
270

    
271
            </Flex>
272

    
273
            <PinchGestureHandler
274
                ref={pinchRef}
275
                // @ts-ignore
276
                onGestureEvent={onGestureEvent}
277
                simultaneousHandlers={[svgRef, panRef]}>
278
                <Animated.View style={[{ flex: 1 }, animatedStyle]}>
279
                    <PanGestureHandler
280
                        ref={panRef}
281
                        simultaneousHandlers={[svgRef, pinchRef]}
282
                        onGestureEvent={onPanEvent}
283
                        onHandlerStateChange={(nativeEvent: any) => {
284
                            if (nativeEvent.state === State.END) {
285
                                console.log(nativeEvent)
286
                            }
287
                        }}
288
                    >
289
                        <Animated.View style={[{
290
                            flex: 1,
291
                        }]}>
292
                            <Svg
293
                                id="svgMap"
294
                                onPress={handleSvgPress}
295
                            >
296
                                {mapImage && mapImage.viewBox &&
297
                                    // background image                    
298
                                    <SvgXml
299
                                        xml={mapImage.svg}
300
                                        width={"100%"}
301
                                        height={"100%"}
302
                                        viewBox={`${0} ${0} ${mapImage.viewBox.width} ${mapImage.viewBox.height}`}
303
                                        // onLayout={(event) => {
304
                                        //     setSvgDimensions({
305
                                        //         width: event.nativeEvent.layout.width,
306
                                        //         height: event.nativeEvent.layout.height,
307
                                        //     });
308
                                        // }}
309
                                    >
310
                                    </SvgXml>
311
                                }
312

    
313
                                {mapImage && roomList && roomList.length > 0 &&
314

    
315
                                    roomList.map((room, index) => {
316
                                        if (!room.in_plan) {
317
                                            return
318
                                        }
319
                                        return (
320
                                            <Path
321
                                                id={"roomList_" + index.toString()}
322
                                                d={room.svg_path}  // The path data defining the shape of the room
323
                                                fill={selectedRoom && room.id == selectedRoom.id ? "#E6F7FF" : "white"}        // Fill the room shape with no color
324
                                                stroke="#66B2FF"       // Outline color
325
                                                strokeWidth={0.3}     // Outline width
326
                                                fillOpacity={selectedRoom && room.id == selectedRoom.id ? 1 : 0.2}
327
                                            />
328
                                        )
329
                                    })}
330

    
331

    
332

    
333
                                {mapImage && roomList && roomList.length > 0 &&
334

    
335
                                    roomList.map((room) => {
336
                                        if (!room.in_plan) {
337
                                            return
338
                                        }
339
                                        return (
340
                                            < SvgText
341
                                                x={room.number_x}     // Adjust the x-coordinate based on your room data
342
                                                y={room.number_y}     // Adjust the y-coordinate based on your room data
343
                                                fill="red"      // Text color
344
                                                fontSize={8}       // Font size
345
                                                textAnchor="middle"  // Center the text horizontally
346
                                                fontStyle='italic'
347
                                                vectorEffect='non-scaling-stroke' // Helps prevent stroke from scaling
348
                                            >
349
                                                {room.id}
350
                                            </SvgText>
351
                                        )
352
                                    })}
353

    
354
                            </Svg>
355
                        </Animated.View>
356
                    </PanGestureHandler>
357
                </Animated.View>
358
            </PinchGestureHandler >
359
        </View >
360
    );
361
};
362

    
363
export default CastlePlanView;
364

    
    (1-1/1)