-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #38 from DHBW-FN-TIT20/KWYG-Sprint-1
Kwyg sprint 1
- Loading branch information
Showing
13 changed files
with
865 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,3 +40,6 @@ Thumbs.db | |
|
||
# Production build | ||
www/ | ||
|
||
# Pagekite for localhost tunneling (https://pagekite.net/) | ||
pagekite.py |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import React from "react"; | ||
import { Circle } from "react-leaflet"; | ||
|
||
class AccuracyCircle extends React.Component { | ||
render() { | ||
if ( | ||
this.props.visible === false || | ||
this.props.center === undefined || | ||
this.props.center === null || | ||
this.props.center.lat === undefined || | ||
this.props.center.lng === undefined || | ||
this.props.radius === undefined || | ||
this.props.radius === null | ||
) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<Circle | ||
center={this.props.center} | ||
radius={this.props.radius} | ||
pathOptions={{ fill: true, fillColor: "#0000ff", fillOpacity: 0.1, color: "#0000ff", opacity: 0.2 }} | ||
/> | ||
); | ||
} | ||
} | ||
|
||
// define the types of the properties that are passed to the component | ||
AccuracyCircle.prototype.props = /** @type { { | ||
visible: boolean, | ||
center: { lat: number, lng: number } | undefined, | ||
radius: number | undefined, | ||
} } */ ({}); | ||
|
||
export default AccuracyCircle; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import React from "react"; | ||
import { Marker } from "react-leaflet"; | ||
import L from "leaflet"; | ||
|
||
class LocationMarker extends React.Component { | ||
markerIcon = L.icon({ | ||
iconUrl: this.props.iconUrl, | ||
iconSize: [this.props.size.width, this.props.size.height], | ||
// Center of the icon: | ||
iconAnchor: [this.props.anchor?.x || this.props.size.width / 2, this.props.anchor?.y || this.props.size.height / 2], | ||
}); | ||
|
||
render() { | ||
if ( | ||
this.props.position === undefined || | ||
this.props.position === null || | ||
this.props.position.lat === undefined || | ||
this.props.position.lng === undefined || | ||
!this.props.visible | ||
) { | ||
return null; | ||
} | ||
|
||
return <Marker position={[this.props.position.lat, this.props.position.lng]} icon={this.markerIcon} />; | ||
} | ||
} | ||
|
||
export default LocationMarker; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import React from "react"; | ||
import { Polygon } from "react-leaflet"; | ||
|
||
class OutlinePolygon extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
polyLatLngs: [], | ||
}; | ||
} | ||
|
||
async componentDidUpdate(prevProps) { | ||
if (this.props.placeName === prevProps.placeName) return; | ||
this.setState({ polyLatLngs: [] }); | ||
|
||
// fetch the polygon outline from the OpenStreetMap API (Nominatim) | ||
// this is not done in the main component because loading the polygon outline | ||
// takes more time than the normal API call | ||
const response = await fetch( | ||
// eslint-disable-next-line max-len | ||
`https://nominatim.openstreetmap.org/search?q=${this.props.placeName}&format=json&limit=1&polygon_geojson=1&polygon_threshold=0.0005`, | ||
); | ||
// check if the response is suited for a polygon outline | ||
const data = await response.json(); | ||
if ( | ||
data[0]?.geojson?.coordinates === undefined || | ||
data[0]?.geojson?.type === undefined || | ||
data[0]?.boundingbox === undefined || | ||
(data[0]?.geojson?.type !== "Polygon" && data[0]?.geojson?.type !== "MultiPolygon") || | ||
(data[0]?.class !== "boundary" && data[0]?.class !== "place" && data[0]?.class !== "landuse") | ||
) { | ||
this.setState({ polyLatLngs: [] }); | ||
return; | ||
} | ||
|
||
const latLngs = this.convertGeoJsonCoordsToLeafletLatLng(data[0].geojson.coordinates); | ||
this.setState({ polyLatLngs: latLngs }); | ||
} | ||
|
||
/** | ||
* Converts the coordinates of a GeoJSON polygon to the format used by Leaflet | ||
* @param {number[]} coords The coordinates of the GeoJSON polygon | ||
* @returns {number[]} The coordinates for the Leaflet polygon | ||
*/ | ||
convertGeoJsonCoordsToLeafletLatLng = coords => { | ||
if (coords === undefined) return []; | ||
|
||
const transformCoords = coords => { | ||
if ( | ||
Array.isArray(coords) && | ||
coords.length === 2 && | ||
typeof coords[0] === "number" && | ||
typeof coords[1] === "number" | ||
) { | ||
return { lat: coords[1], lng: coords[0] }; | ||
} | ||
return coords.map(transformCoords); | ||
}; | ||
|
||
const latLngs = transformCoords(coords); | ||
|
||
return latLngs; | ||
}; | ||
|
||
render() { | ||
if (this.state.polyLatLngs.length === 0) return null; | ||
|
||
return ( | ||
<Polygon | ||
positions={this.state.polyLatLngs} | ||
color="blue" | ||
weight={1} | ||
opacity={0.2} | ||
fillOpacity={0.05} | ||
smoothFactor={1} | ||
/> | ||
); | ||
} | ||
} | ||
|
||
// define the types of the properties that are passed to the component | ||
OutlinePolygon.prototype.props = /** @type { { | ||
placeName: string, | ||
} } */ ({}); | ||
|
||
export default OutlinePolygon; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
import React from "react"; | ||
import { Sheet } from "framework7-react"; | ||
|
||
class SnappingSheet extends React.Component { | ||
dragStartPositionY = 0; | ||
sheetScrollAreaRef = React.createRef(); | ||
isMoving = false; | ||
|
||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
sheetOpened: true, | ||
sheetHeight: this.props.snapHeightStates[this.props.currentState || 0], | ||
sheetHeightTransitionStyle: "0.3s ease-in-out", | ||
}; | ||
} | ||
|
||
/** | ||
* Adds touch and mouse listeners to the sheet | ||
*/ | ||
componentDidMount() { | ||
// add touch listeners to the sheet | ||
this.sheetScrollAreaRef.current.addEventListener("touchstart", this.dragStart, { passive: false }); | ||
this.sheetScrollAreaRef.current.addEventListener("touchmove", this.dragMove, { passive: false }); | ||
this.sheetScrollAreaRef.current.addEventListener("touchend", this.dragEnd, { passive: false }); | ||
|
||
// add mouse listeners to the sheet | ||
this.sheetScrollAreaRef.current.addEventListener("mousedown", this.dragStart, { passive: false }); | ||
window.addEventListener("mousemove", this.dragMove, { passive: false }); | ||
window.addEventListener("mouseup", this.dragEnd, { passive: false }); | ||
|
||
// let the parent know that the sheet is snapped to the current state (to clear the state) | ||
if (this.props.currentState !== undefined) this.props.snappedToHeight(this.props.currentState); | ||
} | ||
|
||
/** | ||
* Removes touch and mouse listeners from the sheet | ||
*/ | ||
componentWillUnmount() { | ||
// remove touch listeners from the sheet | ||
this.sheetScrollAreaRef.current.removeEventListener("touchstart", this.dragStart); | ||
this.sheetScrollAreaRef.current.removeEventListener("touchmove", this.dragMove); | ||
this.sheetScrollAreaRef.current.removeEventListener("touchend", this.dragEnd); | ||
|
||
// remove mouse listeners from the sheet | ||
this.sheetScrollAreaRef.current.removeEventListener("mousedown", this.dragStart); | ||
window.removeEventListener("mousemove", this.dragMove); | ||
window.removeEventListener("mouseup", this.dragEnd); | ||
} | ||
|
||
/** | ||
* Snaps the sheet to a given state if the state is defined | ||
*/ | ||
componentDidUpdate() { | ||
if (this.props.currentState !== undefined) { | ||
this.setState({ | ||
sheetHeightTransitionStyle: "0.3s ease-in-out", | ||
sheetHeight: this.props.snapHeightStates[this.props.currentState], | ||
}); | ||
this.props.snappedToHeight(this.props.snapHeightStates[this.props.currentState]); | ||
} | ||
} | ||
|
||
/** | ||
* Starts the dragging process | ||
* @param {Event} event | ||
*/ | ||
dragStart = event => { | ||
this.dragStartPositionY = event.touches ? event.touches[0].clientY : event.clientY; | ||
this.isMoving = true; | ||
this.setState({ sheetHeightTransitionStyle: "0s" }); | ||
}; | ||
|
||
/** | ||
* Moves the sheet (param is a touch event or a mouse event) | ||
* @param { Event } event | ||
*/ | ||
dragMove = event => { | ||
event.preventDefault(); | ||
|
||
if (!this.isMoving) return; | ||
|
||
// check if it is a touch event or a mouse event and get the y position | ||
const dragStartPositionY = event.touches ? event.touches[0].clientY : event.clientY; | ||
|
||
// calculate the new sheet height | ||
const difference = this.dragStartPositionY - dragStartPositionY; | ||
const newSheetHeight = this.state.sheetHeight + difference; | ||
|
||
// check if the new sheet height is in the allowed range | ||
if (newSheetHeight < this.props.snapHeightStates[0]) { | ||
this.setState({ sheetHeight: this.props.snapHeightStates[0] }); | ||
return; | ||
} | ||
if (newSheetHeight > this.props.snapHeightStates[this.props.snapHeightStates.length - 1]) { | ||
this.setState({ sheetHeight: this.props.snapHeightStates[this.props.snapHeightStates.length - 1] }); | ||
return; | ||
} | ||
|
||
// set the new sheet height and update the touch start position | ||
this.setState({ sheetHeight: newSheetHeight }); | ||
this.dragStartPositionY = dragStartPositionY; | ||
}; | ||
|
||
/** | ||
* Ends the dragging process | ||
*/ | ||
dragEnd = () => { | ||
this.isMoving = false; | ||
|
||
// snap the sheet to the nearest height state | ||
const closestSheetHeightState = this.props.snapHeightStates.reduce((prev, curr) => { | ||
return Math.abs(curr - this.state.sheetHeight) < Math.abs(prev - this.state.sheetHeight) ? curr : prev; | ||
}); | ||
|
||
// transition to the new sheet height | ||
this.setState({ sheetHeightTransitionStyle: "0.3s ease-out", sheetHeight: closestSheetHeightState }); | ||
this.props.snappedToHeight(closestSheetHeightState); | ||
}; | ||
|
||
render() { | ||
if (this.props.children === undefined) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<div ref={this.sheetScrollAreaRef}> | ||
<Sheet | ||
style={{ | ||
height: this.state.sheetHeight, | ||
transition: this.state.sheetHeightTransitionStyle, | ||
overflow: "hidden", | ||
}} | ||
opened={true} | ||
> | ||
{this.props.children} | ||
</Sheet> | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
// define the types of the properties that are passed to the component | ||
SnappingSheet.prototype.props = /** @type { { | ||
children: React.ReactNode | ||
snapHeightStates: number[], | ||
currentState: number | undefined, | ||
snappedToHeight: (height: number) => void | ||
} } */ ({}); | ||
|
||
export default SnappingSheet; |
Oops, something went wrong.