Projekt

Obecné

Profil

Stáhnout (13.9 KB) Statistiky
| Větev: | Tag: | Revize:
1 d26c4168 Fantič
import { Box, HStack, Pressable, View, Text, Flex, IconButton } from 'native-base';
2
import React, { useEffect, useRef, useState } from 'react';
3 36ede89c Fantič
import { StyleSheet, Dimensions, TouchableOpacity, GestureResponderEvent } from 'react-native';
4 7652bb26 Fantič
import { PanGestureHandler, PinchGestureHandler, State, TapGestureHandler, TouchableWithoutFeedback } from 'react-native-gesture-handler';
5
6
import { findNodeHandle, UIManager } from 'react-native';
7
8 8d384539 Fantič
import Animated, {
9
    useAnimatedGestureHandler,
10
    useAnimatedStyle,
11
    useSharedValue,
12
} from 'react-native-reanimated';
13 28ab969f Fantič
import { PlanImage, Room } from '../../types/plan';
14 7652bb26 Fantič
import Svg, { Path, SvgXml, Text as SvgText, G, Circle } from 'react-native-svg';
15 aac857cf Fantič
16 bdedfcb4 Fantič
// @ts-ignore
17 36ede89c Fantič
import pointInSvgPolygon from "point-in-svg-polygon"
18 d26c4168 Fantič
import { ExitfullscreenIcon, FullscreenIcon } from '../general/Icons';
19 bdedfcb4 Fantič
20 36ede89c Fantič
const CastlePlanView = (props: { mapImage: PlanImage, roomList: Room[], selectedRoom?: Room, fullScreenMode?: boolean, height?: number, setSelectedRoom?: (room: Room) => void }) => {
21 8d384539 Fantič
22 28ab969f Fantič
    const DEFAULT_SCALE = 1
23
    const MIN_SCALE = 0.95
24
25 d26c4168 Fantič
    const { mapImage, roomList, selectedRoom, height, setSelectedRoom } = props;
26
27 7652bb26 Fantič
28 d26c4168 Fantič
    const [fullScreenMode, setFullScreen] = useState(false);
29
30
    useEffect(() => {
31
        if (props.fullScreenMode) {
32
            setFullScreen(props.fullScreenMode)
33
        }
34 7652bb26 Fantič
    }, [props.fullScreenMode])
35 d26c4168 Fantič
36 28ab969f Fantič
37
    const panRef = useRef<React.ReactElement>();
38
    const pinchRef = useRef<React.ReactElement>();
39 bdedfcb4 Fantič
40 8d384539 Fantič
    const svgRef = useRef<React.ReactElement>();
41
42
    const translateX = useSharedValue(0);
43
    const translateY = useSharedValue(0);
44 28ab969f Fantič
    const scale = useSharedValue(DEFAULT_SCALE);
45 8d384539 Fantič
46 28ab969f Fantič
    const onPanEvent = useAnimatedGestureHandler({
47
        // handle one finger -> drag / move
48 36ede89c Fantič
        onStart: (event, ctx: any) => {
49
            if (event.numberOfPointers === 1) {
50
                ctx.startX = translateX.value;
51
                ctx.startY = translateY.value;
52
            }
53 28ab969f Fantič
        },
54
        onActive: (event, ctx: any) => {
55 36ede89c Fantič
            if (event.numberOfPointers === 1) {
56
                translateX.value = ctx.startX + event.translationX;
57
                translateY.value = ctx.startY + event.translationY;
58
            }
59 28ab969f Fantič
        },
60
    });
61 aac857cf Fantič
62 8d384539 Fantič
    const onGestureEvent = useAnimatedGestureHandler({
63 08be9ecd Fantič
        onStart: (_, ctx: any) => {
64
            ctx.startScale = scale.value;
65
        },
66
        onActive: (event: any, ctx: any) => {
67
            // handle two fingers -> zoom + -
68 28ab969f Fantič
            if (event.numberOfPointers === 2) {
69 08be9ecd Fantič
                scale.value = ctx.startScale * event.scale;
70
            }
71
        },
72
        onEnd: (event) => {
73
            // handle two fingers -> zoom + -
74
            if (event.numberOfPointers === 2) {
75
                if (scale.value < MIN_SCALE) {
76
                    scale.value = MIN_SCALE;
77 8d384539 Fantič
                }
78 08be9ecd Fantič
                // You may add additional logic for maximum scale if needed
79 d4c93958 Fantič
80
                console.log("scale")
81
                console.log(scale.value)
82 8d384539 Fantič
            }
83
        },
84
    });
85 f220395e Fantič
86 8d384539 Fantič
    const animatedStyle = useAnimatedStyle(() => {
87
        return {
88
            transform: [
89
                { translateX: translateX.value },
90
                { translateY: translateY.value },
91
                { scale: scale.value },
92
            ],
93
        };
94
    });
95 aac857cf Fantič
96 36ede89c Fantič
97 d4c93958 Fantič
    function calculateStraightLineDistance(x1: number, y1: number, planX: number, planY: number) {
98 36ede89c Fantič
        // Apply scale and translations to both points
99
100 d26c4168 Fantič
        const x2 = planX
101
        const y2 = planY
102 36ede89c Fantič
103
        const x_distance = Math.abs(x1 - x2);
104
        const y_distance = Math.abs(y1 - y2);
105
106
        return x_distance + y_distance;
107
    }
108
109 d26c4168 Fantič
    const zoomOut = () => {
110
        translateX.value = 0;
111
        translateY.value = 0;
112
        scale.value = DEFAULT_SCALE;
113
    }
114
115
    const zoomToRoom = (room: Room) => {
116
        // Todo
117 7652bb26 Fantič
118
        console.log(room)
119
120
        scale.value = 3;
121
122
        translateX.value = room.number_x + 100
123
        translateY.value = room.number_y + 100
124
125 d26c4168 Fantič
    }
126
127
    const handleFullScreenPressed = () => {
128 7652bb26 Fantič
        if (scale.value != DEFAULT_SCALE || translateX.value != 0 || translateY.value != 0) {
129 d26c4168 Fantič
            console.log("todo zoom out")
130
            zoomOut()
131
        }
132
        else {
133
            console.log("Toggling fullscreen")
134
            setFullScreen && setFullScreen(!fullScreenMode)
135
        }
136
    }
137 36ede89c Fantič
138
    const handleSvgPress = (event: GestureResponderEvent) => {
139 9222f70c Fantič
        let locationX = event.nativeEvent.locationX
140
        let locationY = event.nativeEvent.locationY
141 36ede89c Fantič
142 9222f70c Fantič
        // console.log("view size:")
143
        // console.log("x " + viewSize.width + " y " + viewSize.height) 
144 50044675 Fantič
145
        const viewRatio =  viewSize.width / viewSize.height
146 9222f70c Fantič
        // console.log("ratio: " + viewSize.width / viewSize.height)       
147
        // console.log("svg size:")
148
        // console.log("x " + mapImage.viewBox.width + " y " + mapImage.viewBox.height)
149 50044675 Fantič
        const svgRatio = mapImage.viewBox.width / mapImage.viewBox.height
150 9222f70c Fantič
        // console.log("ratio: " + mapImage.viewBox.width / mapImage.viewBox.height)    
151 d4c93958 Fantič
152 9222f70c Fantič
    
153 d4c93958 Fantič
        let mapX =  (locationX / viewSize.width) * mapImage.viewBox.width
154
        let mapY =  (locationY / viewSize.height) * mapImage.viewBox.height
155
156 9222f70c Fantič
        // console.log("clicked: x " + locationX + " y " + locationY)
157
158 50044675 Fantič
        if(svgRatio > viewRatio){
159
            // svg is spaced in the middle 
160
            // top down is filled
161 9222f70c Fantič
            let xRatio = viewSize.width / mapImage.viewBox.width
162
            let yFilled = xRatio * mapImage.viewBox.height
163
            let offsetY = (viewSize.height - yFilled) / 2
164 d4c93958 Fantič
165 9222f70c Fantič
            mapY = ((locationY - offsetY) / yFilled) * mapImage.viewBox.height
166 50044675 Fantič
        }
167
        else if(svgRatio < viewRatio){
168
            // svg is spaced in the center 
169
            // left right is filled
170 9222f70c Fantič
            let yRatio = viewSize.height / mapImage.viewBox.height
171
            let xFilled = yRatio * mapImage.viewBox.width
172
            let offsetX = (viewSize.width - xFilled) / 2
173 d4c93958 Fantič
174 9222f70c Fantič
            mapX = ((locationX - offsetX) / xFilled) * mapImage.viewBox.width
175 50044675 Fantič
        }
176 d4c93958 Fantič
177
        // Check if the touch event is within the bounds of a room
178
        let clickedRoom: Room | undefined = undefined
179 36ede89c Fantič
180 d4c93958 Fantič
        const maxNumberDistance = 100
181 bdedfcb4 Fantič
182 d4c93958 Fantič
        let minDistance = Number.MAX_VALUE
183 bdedfcb4 Fantič
184 d4c93958 Fantič
        for (let i = 0; i < roomList.length; i++) {
185
            const room: Room = roomList[i]
186
            if (room.in_plan) {
187
                // TODO
188
                // console.log()
189
                console.log("Room + " + room.id + " x: " + room.number_x + " y: " + room.number_y)
190 36ede89c Fantič
191 d4c93958 Fantič
                const currentDistance = calculateStraightLineDistance(room.number_x, room.number_y, mapX, mapY)
192 36ede89c Fantič
193 d4c93958 Fantič
                if (currentDistance < minDistance) {
194
                    minDistance = currentDistance
195
                    clickedRoom = room
196
                }
197
            }
198
        };
199 bdedfcb4 Fantič
200 d4c93958 Fantič
        console.log()
201
        console.log('Room clicked with id:', clickedRoom?.id);
202
        console.log("x " + clickedRoom?.number_x + " y " + clickedRoom?.number_y)
203
        console.log(minDistance)
204
        console.log("translated clicked: x " + mapX + " y " + mapY)
205 d26c4168 Fantič
206 d4c93958 Fantič
        if (clickedRoom && minDistance < maxNumberDistance) {
207
            // TODO        
208 5cee436e Fantič
209 d4c93958 Fantič
            // Perform any actions you need with the clicked room
210 36ede89c Fantič
211 d4c93958 Fantič
            // TODO fix -> point recognition
212
            setSelectedRoom && setSelectedRoom(clickedRoom)
213
        } else {
214
            console.log("no room found")
215
        }
216
        console.log("")
217 bdedfcb4 Fantič
    };
218 5cee436e Fantič
219 d4c93958 Fantič
    const [viewSize, setViewSize] = useState({ height: 0, width: 0 });
220
221
    useEffect(() => {
222
        setViewSize({
223
            width: fullScreenMode ?
224
                Dimensions.get('window').width - 20 : // full screen
225
                Dimensions.get('window').width - 20, // not full screen
226
            height: fullScreenMode ?
227
                Dimensions.get('window').height - 122.5 : // full scren
228
                Dimensions.get('window').height -350, // not full screen
229
        })
230
    }, [fullScreenMode])
231
232 d26c4168 Fantič
233 aac857cf Fantič
    return (
234 8d384539 Fantič
        // container
235 d26c4168 Fantič
        <View
236 d4c93958 Fantič
            height={viewSize.height}
237
            width={viewSize.width}
238 5cee436e Fantič
            // @ts-ignore
239
            style={
240
                fullScreenMode ? {
241 d26c4168 Fantič
                    position: "absolute",
242
                    top: -230,
243
                    left: 0,
244
                    zIndex: 1000,
245 7652bb26 Fantič
                    backgroundColor: "white",
246 5cee436e Fantič
                }
247
                    :
248 d26c4168 Fantič
                    {
249
                        overflow: "hidden",
250
                    }
251 7a3ad946 Fantič
            }
252
            borderColor={"light.300"}
253
            borderRadius={10}
254 d26c4168 Fantič
            borderWidth={fullScreenMode ? 0 : 1}
255 08be9ecd Fantič
        >
256 d26c4168 Fantič
            {/* control panel */}
257 d4c93958 Fantič
            <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 }}>
258 d26c4168 Fantič
                <Pressable padding={1.5} backgroundColor={"#654B07"} borderRadius={5} marginRight={selectedRoom ? 1 : -2} onPress={handleFullScreenPressed}>
259
                    <FullscreenIcon color="white" />
260
                </Pressable>
261
                {
262
                    selectedRoom &&
263 7652bb26 Fantič
                    <Pressable padding={1.5} backgroundColor={"#654B07"} borderRadius={5} marginRight={-2} onPress={() => { zoomToRoom(selectedRoom) }}>
264 d26c4168 Fantič
                        <ExitfullscreenIcon color="white" />
265
                    </Pressable>
266
                }
267
268
            </Flex>
269 08be9ecd Fantič
270 28ab969f Fantič
            <PinchGestureHandler
271
                ref={pinchRef}
272
                // @ts-ignore
273
                onGestureEvent={onGestureEvent}
274
                simultaneousHandlers={[svgRef, panRef]}>
275 d4c93958 Fantič
                <Animated.View style={[{ flex: 1 }, animatedStyle]}>
276 28ab969f Fantič
                    <PanGestureHandler
277
                        ref={panRef}
278
                        simultaneousHandlers={[svgRef, pinchRef]}
279
                        onGestureEvent={onPanEvent}
280 bdedfcb4 Fantič
                        onHandlerStateChange={(nativeEvent: any) => {
281
                            if (nativeEvent.state === State.END) {
282
                                console.log(nativeEvent)
283
                            }
284
                        }}
285 8d384539 Fantič
                    >
286 28ab969f Fantič
                        <Animated.View style={[{
287
                            flex: 1,
288 d4c93958 Fantič
                        }]}>
289 28ab969f Fantič
                            <Svg
290 bdedfcb4 Fantič
                                id="svgMap"
291 d4c93958 Fantič
                                onPress={handleSvgPress}
292 28ab969f Fantič
                            >
293
                                {mapImage && mapImage.viewBox &&
294
                                    // background image                    
295
                                    <SvgXml
296
                                        xml={mapImage.svg}
297
                                        width={"100%"}
298
                                        height={"100%"}
299 d4c93958 Fantič
                                        viewBox={`${0} ${0} ${mapImage.viewBox.width} ${mapImage.viewBox.height}`}
300
                                        // onLayout={(event) => {
301
                                        //     setSvgDimensions({
302
                                        //         width: event.nativeEvent.layout.width,
303
                                        //         height: event.nativeEvent.layout.height,
304
                                        //     });
305
                                        // }}
306 7652bb26 Fantič
                                    >
307
                                    </SvgXml>
308 08be9ecd Fantič
                                }
309
310 28ab969f Fantič
                                {mapImage && roomList && roomList.length > 0 &&
311 bdedfcb4 Fantič
312
                                    roomList.map((room, index) => {
313 08be9ecd Fantič
                                        if (!room.in_plan) {
314
                                            return
315
                                        }
316
                                        return (
317 bdedfcb4 Fantič
                                            <Path
318
                                                id={"roomList_" + index.toString()}
319
                                                d={room.svg_path}  // The path data defining the shape of the room
320
                                                fill={selectedRoom && room.id == selectedRoom.id ? "#E6F7FF" : "white"}        // Fill the room shape with no color
321
                                                stroke="#66B2FF"       // Outline color
322
                                                strokeWidth={0.3}     // Outline width
323
                                                fillOpacity={selectedRoom && room.id == selectedRoom.id ? 1 : 0.2}
324
                                            />
325 08be9ecd Fantič
                                        )
326 bdedfcb4 Fantič
                                    })}
327
328 7652bb26 Fantič
329
330 bdedfcb4 Fantič
                                {mapImage && roomList && roomList.length > 0 &&
331 8d384539 Fantič
332 bdedfcb4 Fantič
                                    roomList.map((room) => {
333
                                        if (!room.in_plan) {
334
                                            return
335
                                        }
336
                                        return (
337 d26c4168 Fantič
                                            < SvgText
338 bdedfcb4 Fantič
                                                x={room.number_x}     // Adjust the x-coordinate based on your room data
339
                                                y={room.number_y}     // Adjust the y-coordinate based on your room data
340
                                                fill="red"      // Text color
341
                                                fontSize={8}       // Font size
342
                                                textAnchor="middle"  // Center the text horizontally
343
                                                fontStyle='italic'
344
                                                vectorEffect='non-scaling-stroke' // Helps prevent stroke from scaling
345
                                            >
346
                                                {room.id}
347 d26c4168 Fantič
                                            </SvgText>
348 bdedfcb4 Fantič
                                        )
349
                                    })}
350 7652bb26 Fantič
351 28ab969f Fantič
                            </Svg>
352
                        </Animated.View>
353
                    </PanGestureHandler>
354 8d384539 Fantič
                </Animated.View>
355 bdedfcb4 Fantič
            </PinchGestureHandler >
356 d26c4168 Fantič
        </View >
357 aac857cf Fantič
    );
358 8d384539 Fantič
};
359
360
export default CastlePlanView;