Leaflet.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. import React from "react";
  2. import {
  3. Map,
  4. TileLayer,
  5. Marker,
  6. Popup,
  7. ZoomControl,
  8. ScaleControl,
  9. Polyline,
  10. // Tooltip,
  11. FeatureGroup
  12. } from "react-leaflet";
  13. //import L from "leaflet";
  14. import {EditControl} from "react-leaflet-draw";
  15. import "react-leaflet-fullscreen/dist/styles.css";
  16. import FullscreenControl from "react-leaflet-fullscreen";
  17. import "./../css/maps.css";
  18. import {calcDistance} from "./../helpers/distance";
  19. import {longitude, latitude, mapWidth, mapHeight} from "./../config/variables";
  20. import {Button} from "reactstrap";
  21. import PathButtons from "./../PathButtons";
  22. import {CustomInput, Input, Label, Row, Col, Container} from "reactstrap";
  23. import mapboxToken from "./../config/mapboxToken.js";
  24. import EvaluationTable from "./../EvaluationTable";
  25. const mapStyles = {
  26. "bright": "bright-v9",
  27. "satellite": "satellite-streets-v9",
  28. "light": "light-v9",
  29. "dark": "dark-v9",
  30. "basic": "basic-v9",
  31. "outdoor": "outdoors-v10"
  32. }
  33. //const customIcon = new L.Icon({
  34. // iconUrl: require("../images/marker_icon.png"),
  35. // iconSize: [24, 40],
  36. // iconAnchor: [12, 40],
  37. //});
  38. export default class Leaflet extends React.Component{
  39. constructor(props){
  40. super(props);
  41. this.state = {
  42. latitude: latitude,
  43. longitude: longitude,
  44. zoom: 15,
  45. path: [],
  46. distance: 0,
  47. drawMode: false,
  48. mapStyle: "bright-v9",
  49. shapeOptions: {
  50. color: "#000",
  51. opacity: 1,
  52. fillColor: "#000",
  53. fillOpacity: 0.2,
  54. weight: 2,
  55. smoothFactor: 20
  56. }
  57. }
  58. }
  59. updateState = (key, value) => {
  60. this.setState({[key]: value})
  61. this.getDistance()
  62. }
  63. addMarker = event => {
  64. if(!this.state.drawMode){
  65. console.log("addmarker")
  66. const { lat, lng } = event.latlng
  67. let pathCopy = this.state.path.slice();
  68. pathCopy.push([lat, lng]);
  69. this.setState({path: pathCopy})
  70. this.getDistance()
  71. }
  72. }
  73. updateMarker = (idx, event) => {
  74. let {lat, lng} = event.target.getLatLng();
  75. let pathCopy = this.state.path.slice();
  76. pathCopy[idx] = [lat, lng]
  77. this.setState({path: pathCopy})
  78. this.getDistance()
  79. }
  80. getDistance = () => {
  81. let dst = calcDistance(this.state.path)
  82. this.setState({distance: dst})
  83. }
  84. clearPath = () => {
  85. this.setState({path: [], distance: 0})
  86. }
  87. _editableFG = null
  88. _onChange = () => {
  89. // this._editableFG contains the edited geometry, which can be manipulated through the leaflet API
  90. const { onChange } = this.props;
  91. if (!this._editableFG || !onChange) {
  92. return;
  93. }
  94. const geojsonData = this._editableFG.leafletElement.toGeoJSON();
  95. onChange(geojsonData);
  96. }
  97. switchDrawMode = () => {
  98. this.setState({drawMode: !this.state.drawMode})
  99. }
  100. updateShapeOptions = (event, option) => {
  101. let value = event.target.value
  102. this.setState(prevState => ({
  103. shapeOptions: {
  104. ...prevState.shapeOptions,
  105. [option]: value
  106. }
  107. }))
  108. }
  109. selectMapStyle = (event) => {
  110. this.setState({mapStyle: mapStyles[event.target.value]})
  111. }
  112. render() {
  113. const position = [this.state.latitude, this.state.longitude]
  114. let testMarkers = this.props.markers
  115. let markers = <></>
  116. if (testMarkers){
  117. markers = this.props.markers.map((pos, idx) =>
  118. <Marker position={pos} key={idx}></Marker>
  119. )
  120. }else{
  121. markers = this.state.path.map((pos, idx) =>
  122. <Marker
  123. position={pos}
  124. draggable
  125. key={idx}
  126. riseOnHover={true}
  127. onDragend={(e) => this.updateMarker(idx, e)}
  128. // icon={customIcon}
  129. >
  130. {/*<Tooltip permanent>{idx}</Tooltip>*/}
  131. <Popup>
  132. {idx}
  133. </Popup>
  134. </Marker>
  135. )
  136. }
  137. return (
  138. <div>
  139. <div className="map">
  140. <Map
  141. center={position}
  142. zoom={this.state.zoom}
  143. zoomControl={false}
  144. style={{width: mapWidth, height: mapHeight}}
  145. onClick={this.addMarker}
  146. >
  147. <TileLayer
  148. maxZoom={30}
  149. attribution='&amp;copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
  150. url={"https://api.mapbox.com/styles/v1/mapbox/" + this.state.mapStyle + "/tiles/{z}/{x}/{y}?access_token=" + mapboxToken}
  151. />
  152. <FeatureGroup>
  153. <EditControl
  154. position="topright"
  155. onEdited={this._onEdited}
  156. onCreated={this._onCreated}
  157. onDeleted={this._onDeleted}
  158. onDrawStart={() => {this.setState({drawMode: true})}}
  159. draw={{
  160. marker: false,
  161. circlemarker: false,
  162. polyline: {shapeOptions: this.state.shapeOptions},
  163. polygon: {shapeOptions: this.state.shapeOptions},
  164. circle: {shapeOptions: this.state.shapeOptions},
  165. rectangle: {shapeOptions: this.state.shapeOptions},
  166. }}
  167. />
  168. </FeatureGroup>
  169. {markers}
  170. <Polyline color="grey" positions={this.state.path} />
  171. <ScaleControl position="bottomright"/>
  172. <ZoomControl position="bottomright" />
  173. <FullscreenControl position="topright"/>
  174. </Map>
  175. </div>
  176. <div className="mapInfo">
  177. <Button onClick={this.clearPath}>Clear path</Button>
  178. <Button onClick={this.getDistance}>Calculate Distance</Button>
  179. <Input type="select" name="selectMapStyle" id="selectMapStyle" onChange={this.selectMapStyle}>
  180. {Object.keys(mapStyles).map((key, idx) => (
  181. <option value={key} key={idx}>{key}</option>
  182. ))}
  183. </Input>
  184. <p>
  185. Distanz: {Math.round(this.state.distance*100)/100} km
  186. </p>
  187. <PathButtons updateState={this.updateState} path={this.state.path}/>
  188. <br/>
  189. <div>
  190. <Container>
  191. <Row>
  192. <Col xs="2">
  193. <Label for="drawMode">Draw</Label>
  194. </Col>
  195. <Col xs="2">
  196. <CustomInput type="switch" onChange={this.switchDrawMode} id="drawMode" name="drawMode"/>
  197. </Col>
  198. <Col xs="2">
  199. <Label for="weight">Weight</Label>
  200. </Col>
  201. <Col xs="6">
  202. <Input type="range" onChange={(e) => this.updateShapeOptions(e, "weight")} name="weight" id="weight" placeholder="weight" min="1" max="20" value={this.state.shapeOptions.weight}/>
  203. </Col>
  204. </Row>
  205. <Row>
  206. <Col xs="2">
  207. <Label for="colorPicker">Line Color</Label>
  208. </Col>
  209. <Col xs="2">
  210. <Input type="color" onChange={(e) => this.updateShapeOptions(e, "color")} name="color" id="colorPicker" placeholder="colorPicker"/>
  211. </Col>
  212. <Col xs="2">
  213. <Label for="opacity">Opacity</Label>
  214. </Col>
  215. <Col xs="6">
  216. <Input type="range" onChange={(e) => this.updateShapeOptions(e, "opacity")} name="opacity" id="opacity" placeholder="opacity" min="0" max="1" step="0.1" value={this.state.shapeOptions.opacity}/>
  217. </Col>
  218. </Row>
  219. <Row>
  220. <Col xs="2">
  221. <Label for="fillColorPicker">Fill Color</Label>
  222. </Col>
  223. <Col xs="2">
  224. <Input type="color" onChange={(e) => this.updateShapeOptions(e, "fillColor")} name="fillColorPicker" id="fillColorPicker" placeholder="fillColorPicker"/>
  225. </Col>
  226. <Col xs="2">
  227. <Label for="fillOpacity">Fill Opacity</Label>
  228. </Col>
  229. <Col xs="6">
  230. <Input type="range" onChange={(e) => this.updateShapeOptions(e, "fillOpacity")} name="fillOpacity" id="fillOpacity" placeholder="fillOpacity" min="0" max="1" step="0.1" value={this.state.shapeOptions.fillOpacity}/>
  231. </Col>
  232. </Row>
  233. </Container>
  234. </div>
  235. </div>
  236. <EvaluationTable mapId="leaflet"/>
  237. </div>
  238. );
  239. }
  240. }