Leaflet.js 7.8 KB

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