Sfoglia il codice sorgente

added serialization functions, simply serializing a rectangle for now.

Eric Li 2 anni fa
parent
commit
660d8f623d

+ 55 - 241
src/components/Map/MainMapComponent/IndoorMap.tsx

@@ -1,5 +1,5 @@
 import React, { useState, useEffect, Children } from 'react';
-import { View, Text, StatusBar, StyleSheet, Dimensions, Button, ActivityIndicator, Alert, Modal, PanResponderCallbacks, PanResponderGestureState, GestureResponderEvent, ImageSourcePropType, TouchableOpacity } from 'react-native';
+import { View, Text, StatusBar, StyleSheet, Dimensions, Button, ActivityIndicator, Alert, Modal, PanResponderCallbacks, PanResponderGestureState, GestureResponderEvent, ImageSourcePropType, TouchableOpacity, Platform } from 'react-native';
 import { Svg, Defs, Rect, Mask, Circle, Marker, Path, Polyline, Image } from 'react-native-svg';
 import { RadioButton } from 'react-native-paper';
 import { Picker } from '@react-native-picker/picker';
@@ -9,6 +9,7 @@ import { colors, lmTypes } from "../../../utils/GlobalUtils";
 import { MapStackNavigationProp } from "../../../navigation/MapNavigator"
 import CustomModal from './modal';
 import { FontAwesome } from "@expo/vector-icons";
+import ReactDOMServer from 'react-dom/server'; //npm i --save-dev @types/react-dom
 
 
 import BasementC from './images/BasementC.svg';
@@ -37,69 +38,20 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
   const [showME, setShowME] = useState(false);
   const [showDots, setShowDots] = useState(false);
   const [showAddedDot, setShowAddedDot] = useState(false)
-  const [showModal2, setShowModal] = useState(false)
-  const [checked, setChecked] = React.useState('information');
-  const [coords, setCoords] = useState([0, 0])
   const [SVGdim, setSVGdim] = useState([1, 1])
-  const [firstTime, setfirstTime] = useState(true)
 
   const [localLandmarks, setLocalLandmarks] = useState<Landmark[]>([])
 
   const imageDim = 0.05 * Dimensions.get("window").width;
 
-  // Main issue is that I need to first load the page to retrieve dimensions of SVG, THEN I can actually use the 
-  // real proper coordinate values. Before, I used raw numbers, which is why it could load immediately. However here,
-  // my state starts with ratio values (0.5 , 0.25, etc), retrieves SVG coordinates, then finally gets the real positioning.
-
-  // *** IN-MEMORY IMPLEMENTATION ***
-  // let indoorCircles: IndoorMarker[][] = [ //first to fifth floor, last element is basement
-  //   [{ key: 1, coordx: 0.5 * SVGdim[0], coordy: 0.5 * SVGdim[1], description: "nothing yet1", landmark: "stairs" },
-  //   { key: 2, coordx: 0.25 * SVGdim[0], coordy: 0.25 * SVGdim[1], description: "nothing yet2", landmark: "stairs" }],
-
-  //   [{ key: 3, coordx: 0.35 * SVGdim[0], coordy: 0.35 * SVGdim[1], description: "nothing yet1", landmark: "stairs" },
-  //   { key: 4, coordx: 0.15 * SVGdim[0], coordy: 0.15 * SVGdim[1], description: "nothing yet2", landmark: "power" }],
-
-  //   [{ key: 5, coordx: 0.5 * SVGdim[0], coordy: 0.5 * SVGdim[1], description: "nothing yet1", landmark: "stairs" },
-  //   { key: 6, coordx: 0.25 * SVGdim[0], coordy: 0.25 * SVGdim[1], description: "nothing yet2", landmark: "stairs" }],
-
-  //   [{ key: 7, coordx: 0.35 * SVGdim[0], coordy: 0.35 * SVGdim[1], description: "nothing yet1", landmark: "power" },
-  //   { key: 8, coordx: 0.15 * SVGdim[0], coordy: 0.15 * SVGdim[1], description: "nothing yet2", landmark: "power" }],
-
-  //   [{ key: 9, coordx: 0.5 * SVGdim[0], coordy: 0.5 * SVGdim[1], description: "nothing yet1", landmark: "stairs" },
-  //   { key: 10, coordx: 0.25 * SVGdim[0], coordy: 0.25 * SVGdim[1], description: "nothing yet2", landmark: "stairs" }],
-
-  //   [{ key: 11, coordx: 0.35 * SVGdim[0], coordy: 0.35 * SVGdim[1], description: "nothing yet1", landmark: "power" },
-  //   { key: 12, coordx: 0.15 * SVGdim[0], coordy: 0.15 * SVGdim[1], description: "nothing yet2", landmark: "stairs" }],
-  // ]
-
-  // const [indoorMarkers, setIndoorMarkers] = useState([ //first to fifth floor, last element is basement
-  //   [{ key: 1, coordx: 0.5 * SVGdim[0], coordy: 0.5 * SVGdim[1], description: "nothing yet1", landmark: "stairs" },
-  //   { key: 2, coordx: 0.25 * SVGdim[0], coordy: 0.25 * SVGdim[1], description: "nothing yet2", landmark: "power" }],
-
-  //   [{ key: 3, coordx: 0.35 * SVGdim[0], coordy: 0.35 * SVGdim[1], description: "nothing yet1", landmark: "stairs" },
-  //   { key: 4, coordx: 0.15 * SVGdim[0], coordy: 0.15 * SVGdim[1], description: "nothing yet2", landmark: "power" }],
-
-  //   [{ key: 5, coordx: 0.5 * SVGdim[0], coordy: 0.5 * SVGdim[1], description: "nothing yet1", landmark: "stairs" },
-  //   { key: 6, coordx: 0.25 * SVGdim[0], coordy: 0.25 * SVGdim[1], description: "nothing yet2", landmark: "stairs" }],
-
-  //   [{ key: 7, coordx: 0.35 * SVGdim[0], coordy: 0.35 * SVGdim[1], description: "nothing yet1", landmark: "power" },
-  //   { key: 8, coordx: 0.15 * SVGdim[0], coordy: 0.15 * SVGdim[1], description: "nothing yet2", landmark: "power" }],
-
-  //   [{ key: 9, coordx: 0.5 * SVGdim[0], coordy: 0.5 * SVGdim[1], description: "nothing yet1", landmark: "stairs" },
-  //   { key: 10, coordx: 0.25 * SVGdim[0], coordy: 0.25 * SVGdim[1], description: "nothing yet2", landmark: "stairs" }],
-
-  //   [{ key: 11, coordx: 0.35 * SVGdim[0], coordy: 0.35 * SVGdim[1], description: "nothing yet1", landmark: "power" },
-  //   { key: 12, coordx: 0.15 * SVGdim[0], coordy: 0.15 * SVGdim[1], description: "nothing yet2", landmark: "stairs" }],
-  // ])
-
   function arrowBut(num, fontAweIcon) {
     if (num != 0) {
       return (
         <View style={{ flex: 1.2, marginHorizontal: 7, backgroundColor: "#d4d4d4", height: 53.5, maxWidth: 60 }}>
           <TouchableOpacity style={styles.arrowButton} onPress={() => { setFloor(prevState => prevState + num) }}>
-            <View style={{ flex: 1, justifyContent: "center" , alignItems:"center"}}>
+            <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
               {/* <FontAwesomeIcon icon="fa-solid fa-left" /> */}
-              <FontAwesome style={{marginLeft: (num==1 ? 5 : -5)}} color={"white"} size={35} name={fontAweIcon} />
+              <FontAwesome style={{ marginLeft: (num == 1 ? 5 : -5) }} color={"white"} size={35} name={fontAweIcon} />
             </View>
           </TouchableOpacity>
         </View>
@@ -113,13 +65,8 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
     }
   }
 
-  let num = 0
 
   const loadCircles = applyFilter(landmarks)?.map((item) => {
-    if (num < 2) {
-      // console.log("*this is inside loadCircles* SVGdim values are " + SVGdim[0] + " and " + SVGdim[1])
-      num += 1;
-    }
     if (item.floor == floor && SVGdim[0] != 1 && SVGdim[1] != 1) {
       return (
         <Image
@@ -135,58 +82,6 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
   }
   )
 
-  // const loadCircles = landmarks.filter(lm => lm.floor == floor).map(item => {
-  //   if (SVGdim[0] != 1 && SVGdim[1] != 1) {
-  //     console.log("svg dimensions are " + SVGdim[0] + " wide and " + SVGdim[1] + " tall")
-  //     return (
-  //       <Image
-  //         // onPress={() => handleDelete(item.longitude, item.latitude , item.id)}
-  //         onPress={() => focusLandmark(item)}
-  //         // onPress={() => Alert.alert("long is " + item.longitude  + " and lat is " + item.latitude)}
-  //         key={item.id}
-  //         x={item.longitude * SVGdim[0]}
-  //         y={item.latitude * SVGdim[1]}
-  //         // x={item.longitude}
-  //         // y={item.latitude}
-  //         width={0.05 * Dimensions.get("window").width}
-  //         height={0.05 * Dimensions.get("window").width}
-  //         href={lmTypes[item.landmark_type]['image'] as ImageSourcePropType} />)
-
-  //     /// *** IN-MEMORY IMPLEMENTATION ***
-  //     // if (item.landmark_type == "stairs") {
-  //     //   return (
-  //     //     <Image onPress={() => handleDelete(item.coordx, item.coordy)} key={item.key} x={item.coordx} y={item.coordy} width={0.05 * Dimensions.get("window").width} height={0.05 * Dimensions.get("window").width} href={require('./landmark_images/stairs.png')} />
-  //     //     // <Circle onPress={() => handleDelete(item.coordx, item.coordy)} key={item.key} cx={item.coordx} cy={item.coordy} r="4" fill="black" />)
-  //     //   )
-  //     // }
-  //     // else if (item.landmark == "power") {
-  //     //   return (
-  //     //     <Image onPress={() => handleDelete(item.coordx, item.coordy)} key={item.key} x={item.coordx} y={item.coordy} width={0.05 * Dimensions.get("window").width} height={0.05 * Dimensions.get("window").width} href={require('./landmark_images/power.png')} />
-  //     //   )
-  //     // }
-  //     // else if (item.landmark == "information") {
-  //     //   return (
-  //     //     <Image onPress={() => handleDelete(item.coordx, item.coordy)} key={item.key} x={item.coordx} y={item.coordy} width={0.05 * Dimensions.get("window").width} height={0.05 * Dimensions.get("window").width} href={require('./landmark_images/information.png')} />
-  //     //   )
-  //     // }
-  //   }
-  // }
-  // )
-
-  // function addCircle(evt: GestureResponderEvent) {
-  //   Alert.alert("Are you sure you want to add a landmark here?", undefined,
-  //     [{ text: "Cancel", onPress: () => console.log("Cancelled") }
-  //       ,
-  //     {
-  //       text: "Confirm", onPress: () => {
-  //         setShowModal(true)
-  //         setCoords([evt.nativeEvent.locationX, evt.nativeEvent.locationY])
-  //       }
-  //     }])
-  //   }
-
-  //   setCoords([evt.nativeEvent.locationX, evt.nativeEvent.locationY])
-  // }
 
   function addLandmark(evt: GestureResponderEvent) {
     if (evt) {
@@ -201,43 +96,7 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
     }
   }
 
-  // *** IN-MEMORY IMPLEMENTATION ***
-  // function addCircleConfirmed() {
-  //   let newKey: number
-  //   if (indoorMarkers[floor].length == 0) {
-  //     newKey = floor * 100
-  //   }
-  //   else {
-  //     newKey = indoorMarkers[floor][indoorMarkers[floor].length - 1].key + 1
-  //   }
-  //   const newDot = { key: newKey, coordx: coords[0], coordy: coords[1], description: "filler", landmark: checked }
-  //   console.log(checked)
-  //   console.log(newDot)
-  //   indoorMarkers[floor].push(newDot)
-  //   setIndoorMarkers(indoorMarkers)
-  //   setShowAddedDot(true)
-  //   Alert.alert("Added Circle: coordinates are " + coords[0].toFixed(3) + " and " + coords[1].toFixed(3))
-  // }
-
-  function handleDelete(coordx: number, coordy: number, id: string) {
-    Alert.alert("Are you sure you want to delete this landmark?", undefined,
-      [{ text: "Cancel", onPress: () => console.log("Cancelled") }
-        ,
-      { text: "Confirm", onPress: () => console.log('delete') }])
-
-
-
-    //*** IN-MEMORY IMPLEMENTATION ***
-    // function handleDeleteConfirmed() {
-    //   const result = indoorMarkers[floor].filter(indoorMarker => indoorMarker['coordx'] != coordx && indoorMarker['coordy'] != coordy)
-    //   indoorMarkers[floor] = result
-    //   setIndoorMarkers(indoorMarkers);
-    //   setShowDots(true)
-    //   Alert.alert("Delete: Coordinates of deleted circle were " + coordx.toFixed(3) + " and " + coordy.toFixed(3))
-    //   console.log(result)
-    //   console.log(indoorMarkers[floor])
-    // }
-  }
+
 
   useEffect(() => {
     // Alert.alert("useEffect has been triggered")
@@ -246,14 +105,6 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
     setTimeout(() => setShowME(true), 100);
   })
 
-  // useEffect(() => {
-  //   if (firstTime) {
-  //     setfirstTime(false) 
-  //     setIndoorMarkers(indoorCircles)  
-  //     console.log("SVGDIM set to: " + SVGdim)
-  //   }
-
-  // }, [SVGdim])
 
 
   const compArray = [
@@ -265,14 +116,44 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
     <FifthFloorC viewBox='257 153 270 290' style={{ opacity: 0.7 }} height={"100%"} width={"100%"} />,
   ]
 
-  // for (let i = 0; i < landmarks.length; i++) {
-  //   if (landmarks[i].floor == 1) {
-  //     console.log("The index that is on floor 1 is " + i)
-  //     console.log("The longitude is " + landmarks[i].longitude)
-  //     console.log("The latitude is " + landmarks[i].latitude)
-  //     console.log("The landmark_type is " + landmarks[i].landmark_type)
-  //   }
-  // }
+
+  const childToWeb = (child: any) => {
+    const { type, props } = child;
+    const name = type && type.displayName;
+    const webName = name && name[0].toLowerCase() + name.slice(1);
+    const Tag = webName ? webName : type;
+    return <Tag {...props}>{toWeb(props.children)}</Tag>;
+  };
+
+  const toWeb = (children: any) => React.Children.map(children, childToWeb);
+
+  function renderSvg() {
+    return (
+      <Svg height="100%" width="100%" style={{ backgroundColor: '#33AAFF' }}>
+      <Rect
+        x="50"
+        y="50"
+        width="50"
+        height="50"
+        fill="#3399ff"
+        strokeWidth="3"
+        stroke="rgb(0,0,0)"
+      />
+    </Svg>
+    )
+  }
+
+  function serialize() {
+    const element = renderSvg();
+    const webJsx = Platform.OS === 'web' ? element : toWeb(element);
+    const svgString = ReactDOMServer.renderToStaticMarkup(webJsx);
+    console.log(svgString)
+    // setText(svgString)
+    return svgString
+  }
+
+
+
 
   // TODO: wire up promptaddlandmark, applyfilters, and focuslandmark methods passed from MapNavigator
   return (
@@ -285,12 +166,12 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
 
       <View style={{ borderColor: "blue", borderWidth: 0, maxHeight: 50, flex: 1, flexDirection: "row", justifyContent: "center", }}>
 
-      {/* arrow-circle-o-right */}
-      {floor == 0 ? arrowBut(0, "") : arrowBut(-1, "chevron-left")}
+        {/* arrow-circle-o-right */}
+        {floor == 0 ? arrowBut(0, "") : arrowBut(-1, "chevron-left")}
 
 
         <Picker
-          style={{ backgroundColor: colors.red, width: 200, height: 50, flex: 5, color:'white' }}
+          style={{ backgroundColor: colors.red, width: 200, height: 50, flex: 5, color: 'white' }}
           selectedValue={floor} // the text of what gets displayed on the dropdown header
           onValueChange={(itemValue, itemIndex: number) => {
             setFloor(itemIndex)
@@ -319,12 +200,10 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
             </View> :
 
             <ReactNativeZoomableView
-              
               panBoundaryPadding={100}
               // bindToBorders={false}
               bindToBorders={true}
-              
-              
+
 
               zoomStep={2.8}
               // initialZoom={2.2}
@@ -333,95 +212,31 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
               initialOffsetY={5}
               onLongPress={(event) => {
                 console.log(event.nativeEvent)
+                serialize()
                 addLandmark(event)
               }}>
-              {/** IN-MEMORY IMPLEMENTATION */}
-              {/* <Modal transparent={true} visible={showModal2}>
-                <View style={{ backgroundColor: "#000000aa", flex: 1 }}>
-                <View style={{ backgroundColor: "#ffffff", margin: 50, padding: 20, borderRadius: 10, }}>
-                <Text style={{ fontSize: 18, marginBottom: 10 }}>Type of Landmark to Add:</Text>
-                
-                <View style={{ flexDirection: "row", alignItems: "center" }}>
-                <RadioButton
-                value="information"
-                status={checked === 'information' ? 'checked' : 'unchecked'}
-                onPress={() => setChecked('information')}
-                />
-                <Text style={{ fontSize: 16 }}>Information</Text>
-                </View>
-                
-                <View style={{ flexDirection: "row", alignItems: "center" }}>
-                <RadioButton
-                value="power"
-                status={checked === 'power' ? 'checked' : 'unchecked'}
-                onPress={() => setChecked('power')}
-                />
-                <Text style={{ fontSize: 16 }}>Power</Text>
-                </View>
-                
-                <View style={{ flexDirection: "row", alignItems: "center", marginBottom: 11 }}>
-                <RadioButton
-                value="stairs"
-                status={checked === 'stairs' ? 'checked' : 'unchecked'}
-                onPress={() => setChecked('stairs')}
-                />
-                <Text style={{ fontSize: 16 }}>Stairs</Text>
-                </View>
-                
-                <Button color={"red"} title='OK' onPress={() => {
-                  //addCircleConfirmed()
-                      setShowModal(false)
-                    }}></Button>
-                    </View>
-                    </View>
-                  </Modal> */}
+
+
+
               <Svg onLayout={event => {
                 // console.log("OFFICIAL: " + event.nativeEvent.layout.width + " , " + event.nativeEvent.layout.height)
                 setSVGdim([event.nativeEvent.layout.width, event.nativeEvent.layout.height])
 
-                // *** IN-MEMORY IMPLEMENTATION *** 
-                // TODO: change this mapping to apply to Landmark type
-                // DONE!!!
                 const transformedLandmarks = localLandmarks.map(item => {
                   return { ...item, coordx: item.longitude * event.nativeEvent.layout.width, coordy: item.latitude * event.nativeEvent.layout.height }
                 })
                 console.log("*this is within onLayout* SVGdim values are " + SVGdim[0] + " AND " + SVGdim[1])
                 setLocalLandmarks(transformedLandmarks)
               }}
-              style={{borderColor:"red" , borderWidth:0}}
               >
-
                 {/* {firstTime == true ? undefined : loadCircles} */}
                 {loadCircles}
+                {compArray[floor]}
+              </Svg>
 
 
 
-                {/* {console.log("Landmark[0]'s landmark type is now " + landmarks[0].landmark_type)}
-{console.log("Landmark[0]'s longitude (x) is now " + landmarks[0].longitude)}
-{console.log("Landmark[0]'s latitude (y) is now " + landmarks[0].latitude)}
-{console.log("Landmark[0]'s floor is now " + landmarks[0].floor)}
-{console.log(lmTypes[2]['image'] as ImageSourcePropType)} */}
-
-
-                {/* {console.log(landmarks.filter(lm => lm.floor == floor))} */}
-
-
-                {/* <Image
-                  // onPress={() => handleDelete(item.longitude, item.landmark_type)}
-                  onPress={() => { Alert.alert("A landmark has been tapped") }}
-                  key={landmarks[344].id}
-                  x={landmarks[344].longitude}
-                  y={landmarks[344].latitude}
-                  // y={item.latitude * SVGdim[1]}
-                  width={0.06 * Dimensions.get("window").width}
-                  height={0.06 * Dimensions.get("window").width}
-                  href={landmarks[344].landmark_type as ImageSourcePropType}
-                // href={require('./landmark_images/stairs.png')}
-                /> */}
-
 
-                {compArray[floor]}
-              </Svg>
 
             </ReactNativeZoomableView>
 
@@ -434,11 +249,10 @@ const IndoorMap: React.FC<IndoorMapProps> = ({ navigation, landmarks, promptAddL
         setLocalLandmarks(landmarks)
       }} /> */}
 
-      <Button title="Go back to map" color={colors.red} onPress={() => navigation.goBack()} />
+      <Button title='Press me to svgString' color={colors.red} onPress={serialize}></Button>
+      {/* <Button title="Go back to map" color={colors.red} onPress={() => navigation.goBack()} /> */}
       {/* <TouchableOpacity style={styles.arrowButton} onPress={() => setFloor(prevState => prevState+1)} ><Text>Increase floor by 1</Text></TouchableOpacity> */}
 
-
-
     </View>
   );
 }

BIN
src/components/Map/MainMapComponent/landmark_images/information.png


BIN
src/components/Map/MainMapComponent/landmark_images/power.png


BIN
src/components/Map/MainMapComponent/landmark_images/stairs.png