diff --git a/package-lock.json b/package-lock.json index 6139953dcac7fb8c6e4e70fcce3acdb9a6119dc7..a5848437d7f6b2b08a9cbd23acc1605d3eaa8322 100644 --- a/package-lock.json +++ b/package-lock.json @@ -849,9 +849,9 @@ } }, "@babel/runtime": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.3.tgz", - "integrity": "sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA==", + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz", + "integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==", "requires": { "regenerator-runtime": "^0.13.2" } @@ -2232,6 +2232,14 @@ "semver": "^5.5.0" } }, + "@babel/runtime": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.3.tgz", + "integrity": "sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA==", + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", @@ -7671,6 +7679,11 @@ "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.5.1.tgz", "integrity": "sha512-ekM9KAeG99tYisNBg0IzEywAlp0hYI5XRipsqRXyRTeuU8jcuntilpp+eFf5gaE0xubc9RuSNIVtByEKwqFV0w==" }, + "leaflet-draw": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/leaflet-draw/-/leaflet-draw-1.0.4.tgz", + "integrity": "sha512-rsQ6saQO5ST5Aj6XRFylr5zvarWgzWnrg46zQ1MEOEIHsppdC/8hnN8qMoFvACsPvTioAuysya/TVtog15tyAQ==" + }, "left-pad": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", @@ -7786,6 +7799,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, + "lodash-es": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.11.tgz", + "integrity": "sha512-DHb1ub+rMjjrxqlB3H56/6MXtm1lSksDp2rA2cNWjG8mlDUYFhUj3Di2Zn5IwSU87xLv8tNIQ7sSwE/YOX/D/Q==" + }, "lodash._reinterpolate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", @@ -10149,16 +10167,14 @@ "fast-deep-equal": "^2.0.1", "hoist-non-react-statics": "^3.3.0", "warning": "^4.0.3" - }, - "dependencies": { - "@babel/runtime": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz", - "integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==", - "requires": { - "regenerator-runtime": "^0.13.2" - } - } + } + }, + "react-leaflet-draw": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/react-leaflet-draw/-/react-leaflet-draw-0.19.0.tgz", + "integrity": "sha512-aOB7Nqgl79l62L7vHxhdyKJD6ep+1Q+qTfnrYfmcgF+yK0A1lQA2fUv9N4C0HCbejcyiqx1XYchSCw9Q+Vtc3A==", + "requires": { + "lodash-es": "^4.17.10" } }, "react-scripts": { diff --git a/package.json b/package.json index fd4f1ef5ed723b41f0a52817ea2c0c87396333a4..af5b9cd24a2375a6c95fc5b8708d9bc55264571f 100644 --- a/package.json +++ b/package.json @@ -3,13 +3,17 @@ "version": "0.1.0", "private": true, "dependencies": { + "@babel/runtime": "7.4.5", "leaflet": "^1.5.1", + "leaflet-draw": "^1.0.4", "react": "^16.8.6", "react-cookie": "^4.0.0", "react-dom": "^16.8.6", "react-leaflet": "^2.3.0", - "react-scripts": "3.0.1", + "react-leaflet-draw": "0.19.0", "universal-cookie": "^4.0.0" + "react-scripts": "3.0.1" + }, "scripts": { "start": "react-scripts start", diff --git a/src/App.css b/src/App.css index 8541116232637336711ddb5064d809f9562b3c60..b0f08dddfc38b5c27752c025dbfe8113491b93d2 100644 --- a/src/App.css +++ b/src/App.css @@ -1,6 +1,7 @@ body { margin: 0; padding: 0; + overflow: hidden; } .hidden { @@ -48,7 +49,7 @@ div.header button:hover { /* Login&RegisterForm */ div.fade-main { - position: absolute; + position: fixed; top: 0; z-index: 1000; height: 100vh; @@ -70,7 +71,7 @@ div.sticky { .close { position: fixed; color: #f1f1f1; - height: 100px; + height: 85px; font-size: 100px; font-weight: bold; transition: transform 0.4s ease-in-out; @@ -82,7 +83,7 @@ div.sticky { color: #bbb; text-decoration: none; cursor: pointer; - transform: rotateZ(90deg); + transform: rotate(90deg); } div.login { diff --git a/src/App.js b/src/App.js index 4ee86192799077399a359cda79b0a7408303bbe6..b5ee0cf4c7ef5a434a32cde764f4c1b03cc231ee 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,8 @@ import React, { Component } from 'react'; +import '../node_modules/leaflet-draw/dist/leaflet.draw.css' +import './App.css'; + +import UserMap from './components/UserMap.js' import styles from './App.css'; import UserMap from './components/UserMap'; diff --git a/src/App_3.js b/src/App_3.js new file mode 100644 index 0000000000000000000000000000000000000000..b2a585516702a125c7e11dd28aa609985aa4a686 --- /dev/null +++ b/src/App_3.js @@ -0,0 +1,367 @@ +import React, { Component } from 'react'; +import { Map, TileLayer, Circle, FeatureGroup } from 'react-leaflet'; +import L from 'leaflet'; +import { EditControl } from 'react-leaflet-draw'; + +// work around broken icons when using webpack, see https://github.com/PaulLeCam/react-leaflet/issues/255 + +delete L.Icon.Default.prototype._getIconUrl; +L.Icon.Default.mergeOptions({ + iconRetinaUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0/images/marker-icon.png', + iconUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0/images/marker-icon.png', + shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0/images/marker-shadow.png', +}); + +// + +let polyline; + +export default class EditControlExample extends Component { + + // see http://leaflet.github.io/Leaflet.draw/docs/leaflet-draw-latest.html#l-draw-event for leaflet-draw events doc + + _onEdited = (e) => { + + let numEdited = 0; + e.layers.eachLayer( (layer) => { + numEdited += 1; + }); + console.log(`_onEdited: edited ${numEdited} layers`, e); + + this._onChange(); + } + + _onCreated = (e) => { + let type = e.layerType; + let layer = e.layer; + if (type === 'marker') { + // Do marker specific actions + console.log("_onCreated: marker created", e); + } + else { + console.log("_onCreated: something else created:", type, e); + } + // Do whatever else you need to. (save to db; etc) + + this._onChange(); + } + + _onDeleted = (e) => { + + let numDeleted = 0; + e.layers.eachLayer( (layer) => { + numDeleted += 1; + }); + console.log(`onDeleted: removed ${numDeleted} layers`, e); + + this._onChange(); + } + + _onMounted = (drawControl) => { + console.log('_onMounted', drawControl); + } + + _onEditStart = (e) => { + console.log('_onEditStart', e); + } + + _onEditStop = (e) => { + console.log('_onEditStop', e); + } + + _onDeleteStart = (e) => { + console.log('_onDeleteStart', e); + } + + _onDeleteStop = (e) => { + console.log('_onDeleteStop', e); + } + + render() { + return ( + <Map className='map' center={[37.8189, -122.4786]} zoom={13} zoomControl={false}> + <TileLayer + attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' + url="http://{s}.tile.osm.org/{z}/{x}/{y}.png" + /> + <FeatureGroup ref={ (reactFGref) => {this._onFeatureGroupReady(reactFGref);} }> + <EditControl + position='topright' + onEdited={this._onEdited} + onCreated={this._onCreated} + onDeleted={this._onDeleted} + onMounted={this._onMounted} + onEditStart={this._onEditStart} + onEditStop={this._onEditStop} + onDeleteStart={this._onDeleteStart} + onDeleteStop={this._onDeleteStop} + draw={{ + rectangle: false + }} + /> + </FeatureGroup> + </Map> + ); + } + + _editableFG = null + + _onFeatureGroupReady = (reactFGref) => { + + // populate the leaflet FeatureGroup with the geoJson layers + + let leafletGeoJSON = new L.GeoJSON(getGeoJson()); + let leafletFG = reactFGref.leafletElement; + + leafletGeoJSON.eachLayer( (layer) => { + leafletFG.addLayer(layer); + }); + + // store the ref for future access to content + + this._editableFG = reactFGref; + } + + _onChange = () => { + + // this._editableFG contains the edited geometry, which can be manipulated through the leaflet API + + const { onChange } = this.props; + + if (!this._editableFG || !onChange) { + return; + } + + const geojsonData = this._editableFG.leafletElement.toGeoJSON(); + onChange(geojsonData); + } +} + +// data taken from the example in https://github.com/PaulLeCam/react-leaflet/issues/176 + +function getGeoJson() { + return { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -122.47979164123535, + 37.830124319877235 + ], + [ + -122.47721672058105, + 37.809377088502615 + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [ + -122.46923446655273, + 37.80293476836673 + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [ + -122.48399734497069, + 37.83466623607849 + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [ + -122.47867584228514, + 37.81893781173967 + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -122.48069286346434, + 37.800637436707525 + ], + [ + -122.48069286346434, + 37.803104310307276 + ], + [ + -122.47950196266174, + 37.803104310307276 + ], + [ + -122.47950196266174, + 37.800637436707525 + ], + [ + -122.48069286346434, + 37.800637436707525 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -122.48103886842728, + 37.833075326166274 + ], + [ + -122.48065531253813, + 37.832558431940114 + ], + [ + -122.4799284338951, + 37.8322660885204 + ], + [ + -122.47963070869446, + 37.83231693093747 + ], + [ + -122.47948586940764, + 37.832467339549524 + ], + [ + -122.47945636510849, + 37.83273426112019 + ], + [ + -122.47959315776825, + 37.83289737938241 + ], + [ + -122.48004108667372, + 37.833109220743104 + ], + [ + -122.48058557510376, + 37.83328293020496 + ], + [ + -122.48080283403395, + 37.83332529830436 + ], + [ + -122.48091548681259, + 37.83322785163939 + ], + [ + -122.48103886842728, + 37.833075326166274 + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -122.48043537139893, + 37.82564992009924 + ], + [ + -122.48129367828368, + 37.82629397920697 + ], + [ + -122.48240947723389, + 37.82544653184479 + ], + [ + -122.48373985290527, + 37.82632787689904 + ], + [ + -122.48425483703613, + 37.82680244295304 + ], + [ + -122.48605728149415, + 37.82639567223645 + ], + [ + -122.4898338317871, + 37.82663295542695 + ], + [ + -122.4930953979492, + 37.82415839321614 + ], + [ + -122.49700069427489, + 37.821887146654376 + ], + [ + -122.4991464614868, + 37.82171764783966 + ], + [ + -122.49850273132326, + 37.81798857543524 + ], + [ + -122.50923156738281, + 37.82090404811055 + ], + [ + -122.51232147216798, + 37.823344820392535 + ], + [ + -122.50150680541992, + 37.8271414168374 + ], + [ + -122.48743057250977, + 37.83093781796035 + ], + [ + -122.48313903808594, + 37.82822612280363 + ], + [ + -122.48043537139893, + 37.82564992009924 + ] + ] + ] + } + } + ] + } +} \ No newline at end of file diff --git a/src/components/DrawTools.js b/src/components/DrawTools.js new file mode 100644 index 0000000000000000000000000000000000000000..791233b3996d525e4c1da055f69011f66546aa46 --- /dev/null +++ b/src/components/DrawTools.js @@ -0,0 +1,63 @@ +import React, {Component} from 'react'; +import {Â EditControl } from "react-leaflet-draw" +import { + FeatureGroup, +} from 'react-leaflet' + +class DrawTools extends Component { + _onCreated = (e) => { + let type = e.layerType; // from the example; isn't used right now, but may be relevant in the future + let layer = e.layer; + let geoJSON = layer.toGeoJSON(); + console.log(JSON.stringify(geoJSON, null, 4)); // makes the output readable in the console + } + + render() { + return ( + // "It's important to wrap EditControl component into FeatureGroup component from react-leaflet. The elements you draw will be added to this FeatureGroup layer, when you hit edit button only items in this layer will be edited." + <FeatureGroup> + <EditControl + position='topright' + onCreated={this._onCreated} + draw={{ + circle: { + repeatMode: true, // allows using the tool again after finishing the previous shape + shapeOptions: { + color: '#f9f10c', + opacity: 100 + } + }, + rectangle: { + repeatMode: true + }, + polygon: { + repeatMode: true, + allowIntersection: false, // Restricts shapes to simple polygons + drawError: { + color: '#e1e100', // Color the shape will turn when intersects + message: '<strong>Oh snap!<strong> you can\'t draw that!' // Message that will show when intersect + }, + shapeOptions: { + color: '#ed2572', + opacity: 100 + } + }, + polyline: { + repeatMode: true, + shapeOptions: { + color: '#ed2572', + opacity: 100 + } + }, + marker: { + repeatMode: true + }, + circlemarker: false + }} + /> + </FeatureGroup> + ) + } +} + +export default DrawTools; \ No newline at end of file diff --git a/src/components/UserMap.js b/src/components/UserMap.js index 2fd70bc708032c147136f144936581a043bae894..86a94d2ccebe335de07c3defcf41614006e00ab4 100644 --- a/src/components/UserMap.js +++ b/src/components/UserMap.js @@ -1,5 +1,11 @@ -import React, { Component } from 'react'; -import { Map, TileLayer, Marker, Popup } from 'react-leaflet'; +import React, {Component} from 'react'; +import { + Map, + TileLayer, + ZoomControl +} from 'react-leaflet' +import DrawTools from './DrawTools.js' + class UserMap extends Component { constructor(props){ @@ -70,6 +76,8 @@ class UserMap extends Component { attribution='Maanmittauslaitoksen kartta' url=' https://tiles.kartat.kapsi.fi/taustakartta/{z}/{x}/{y}.jpg' /> + <ZoomControl position='topright' /> + <DrawTools position={this.props.position} /> <Marker position={this.props.position}> <Popup> Se on perjantai, my dudes <br />