diff --git a/src/App.css b/src/App.css index dd6464757b7cba9f96157c84695c6e0fca4db7dc..a0c99fee8d065ca947e7f47aaf956d4d918bf6c2 100644 --- a/src/App.css +++ b/src/App.css @@ -60,22 +60,22 @@ div.fade-main { } div.sticky { - position: fixed; - top: 0px; - right: 0px; - height: 100px; - width: 100px; - margin-right: 150px; + position: fixed; + top: 0px; + right: 0px; + height: 100px; + width: 100px; + margin-right: 150px; } .close { - position: fixed; - color: #f1f1f1; - height: 85px; - font-size: 100px; - font-weight: bold; - transition: transform 0.4s ease-in-out; - line-height: 70%; + position: fixed; + color: #f1f1f1; + height: 85px; + font-size: 100px; + font-weight: bold; + transition: transform 0.4s ease-in-out; + line-height: 70%; } .close:hover, @@ -155,3 +155,44 @@ div.login button:hover { margin-right: 20%; } +/* Editing text button in the toolbar */ +.leaflet-draw-toolbar .leaflet-draw-draw-textbox { + background-image: url("icons/button-textbox.png"); + background-size: 30px 30px; +} + +/* Editing tooltips */ +.leaflet-tooltip { + font-size: 18px; + /* Overriding tooltip layout by making it invisible */ + background-color: transparent; + box-shadow: none; + border: none; + padding: 0; +} + +/* remove the small triangle on tooltip */ +.leaflet-tooltip-bottom:before { + border: 0; +} + +/* Editing editable tooltips */ +.editable { + cursor: text; /* the cursor icon doesn't change by default when hovering on top of the text; overriding */ + min-width: 154px; + min-height: 18px; + color: #fff; + font-weight: bold; + /* text borders */ + text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, + 1px 1px 0 #000; +} + +/* placeholder text for tooltip */ +[contenteditable="true"]:empty:before { + content: attr(placeholder); + display: block; /* For Firefox */ + color: #777; + text-shadow: none; + font-weight: normal; +} diff --git a/src/components/DrawTools.js b/src/components/DrawTools.js index 791233b3996d525e4c1da055f69011f66546aa46..00ee52aa71938a5e4159edaaf65464381c1b525b 100644 --- a/src/components/DrawTools.js +++ b/src/components/DrawTools.js @@ -1,63 +1,178 @@ -import React, {Component} from 'react'; -import {Â EditControl } from "react-leaflet-draw" -import { - FeatureGroup, -} from 'react-leaflet' +import React, { Component } from "react"; +import { EditControl } from "react-leaflet-draw"; +import L from "leaflet"; +import "leaflet-draw"; +import { FeatureGroup } from "react-leaflet"; + +// class for text field +L.Draw.MarkerTextBox = L.Draw.Marker.extend({ + options: { + icon: L.divIcon({ + className: "", // empty class to override default styling + iconSize: [20, 20], + iconAnchor: [10, 20] + }), + repeatMode: false, + interactive: true + }, + initialize: function(map, options) { + this.type = "textbox"; // important to have a unique type, so that it won't get mixed up with other elements + this.featureTypeCode = "textbox"; + L.Draw.Feature.prototype.initialize.call(this, map, options); + } +}); + +// Overriding default toolbar +// Just adding one new button though lol +L.DrawToolbar.include({ + getModeHandlers: function(map) { + return [ + { + enabled: this.options.polyline, + handler: new L.Draw.Polyline(map, this.options.polyline), + title: L.drawLocal.draw.toolbar.buttons.polyline + }, + { + enabled: this.options.polygon, + handler: new L.Draw.Polygon(map, this.options.polygon), + title: L.drawLocal.draw.toolbar.buttons.polygon + }, + { + enabled: this.options.rectangle, + handler: new L.Draw.Rectangle(map, this.options.rectangle), + title: L.drawLocal.draw.toolbar.buttons.rectangle + }, + { + enabled: this.options.circle, + handler: new L.Draw.Circle(map, this.options.circle), + title: L.drawLocal.draw.toolbar.buttons.circle + }, + { + enabled: this.options.marker, + handler: new L.Draw.Marker(map, this.options.marker), + title: L.drawLocal.draw.toolbar.buttons.marker + }, + { + enabled: this.options.marker, + handler: new L.Draw.MarkerTextBox(map, this.options.marker), + title: "Write text" + } + ]; + } +}); 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> - ) - } + constructor(props) { + super(props); + this.state = { + geoJSONAll: [] // property for all GeoJSON data in the map + }; + } + + _onCreated = e => { + // check if a drawn polyline has just one point in it + if (e.layerType === "polyline" && e.layer.getLatLngs().length === 1) { + e.layer.remove(); + return; + } + + if (e.layerType === "textbox") { + // have to create tooltip as a DOM element to allow text selecting. maybe + let tooltip = L.DomUtil.create("div", "editable"); + tooltip.innerHTML = + '<div contenteditable="true" placeholder="Click here and type"></div>'; + + e.layer.bindTooltip(tooltip, { + permanent: true, + direction: "bottom", + interactive: true + }); + + // disable dragging when cursor is over marker (tooltip) + // clicking on tooltip fires the marker's click handler, hence e.layer.on + e.layer.on("mouseover", function() { + e.layer._map.dragging.disable(); + }); + + // enable dragging again when cursor is out of marker (tooltip) + e.layer.on("mouseout", function() { + e.layer._map.dragging.enable(); + }); + + // show placeholder text again upon emptying textbox + e.layer.on("keyup", function() { + // when the text area is emptied, a <br> appears + // manually removing it so that the placeholder text can show + if ( + tooltip.innerHTML === + '<div placeholder="Click here and type" contenteditable="true"><br></div>' || + tooltip.innerHTML === + '<div placeholder="Click here and type" contenteditable="true"><div><br></div></div>' + ) { + tooltip.innerHTML = + '<div placeholder="Click here and type" contenteditable="true"></div>'; + } + }); + } // end if (e.layerType === "textbox") + + // turning layer data to GeoJSON + this.makeGeoJSON(e.layer); + }; // end _onCreated + + makeGeoJSON = e => { + let geoJSON = e.toGeoJSON(); + let newGeoJSONAll = this.state.geoJSONAll; + newGeoJSONAll.push(geoJSON); // can't do +=, need to use push function + console.log(JSON.stringify(newGeoJSONAll, null, 4)); + this.setState({ geoJSONAll: newGeoJSONAll }); + }; + + 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: 1 // affects the outline only. for some reason it wasn't at full opacity, so this is needed for more clarity + } + }, + 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: 1 + } + }, + polyline: { + repeatMode: true, + shapeOptions: { + color: "#ed2572", + opacity: 1 + } + }, + marker: { + repeatMode: false + }, + circlemarker: false + }} + /> + </FeatureGroup> + ); + } } -export default DrawTools; \ No newline at end of file +export default DrawTools; diff --git a/src/components/UserMap.js b/src/components/UserMap.js index 1ec4c484d990b5b29ff443a7840a86e2517bda78..4b3e690ea038c66268066abdda38bedb7a22cdfa 100644 --- a/src/components/UserMap.js +++ b/src/components/UserMap.js @@ -1,54 +1,52 @@ -import React, {Component} from 'react'; -import { - Map, - TileLayer, - ZoomControl, - Marker, - Popup -} from 'react-leaflet' -import DrawTools from './DrawTools.js' +import React, { Component } from "react"; +import { Map, TileLayer, ZoomControl, Marker, Popup } from "react-leaflet"; +import L from "leaflet"; +import DrawTools from "./DrawTools.js"; class UserMap extends Component { - constructor(props){ + constructor(props) { super(props); this.state = { ownLat: null, ownLng: null, - mapUrl: 'https://tiles.kartat.kapsi.fi/taustakartta/{z}/{x}/{y}.jpg' - } + mapUrl: "https://tiles.kartat.kapsi.fi/taustakartta/{z}/{x}/{y}.jpg" + }; this.watchPositionId = null; } - componentDidMount(){ - this.getCurrentPosition((position) => { + componentDidMount() { + this.getCurrentPosition(position => { this.setCurrentPosition(position); }); } - componentWillUnmount(){ - if(this.watchPositionId != null){ + componentWillUnmount() { + if (this.watchPositionId != null) { navigator.geolocation.clearWatch(this.watchPositionId); } } - setCurrentPosition(position){ + setCurrentPosition(position) { this.setState({ ownLat: position.coords.latitude, - ownLng: position.coords.longitude, + ownLng: position.coords.longitude }); } - getCurrentPosition(callback){ - if(!navigator.geolocation){ + getCurrentPosition(callback) { + if (!navigator.geolocation) { console.log("Can't get geolocation :/"); - } - else{ + } else { // Position tracking options const options = { enableHighAccuracy: true, timeout: 30000, maximumAge: 0 + }; + + if (this.watchPositionId != null) { + navigator.geolocation.clearWatch(this.watchPositionId); } if(this.watchPositionId != null){navigator.geolocation.clearWatch(this.watchPositionId);} @@ -60,11 +58,15 @@ class UserMap extends Component { } }, (error) =>{ console.log(error); + // disable tracking + if(this.watchPositionId != null){ + navigator.geolocation.clearWatch(this.watchPositionId); + } }, options); } } - positionToGeoJSON(position){ + positionToGeoJSON(position) { let geoJSON = { type: "Feature", properties: {}, @@ -72,33 +74,47 @@ class UserMap extends Component { type: "Point", coordinates: [position.coords.longitude, position.coords.latitude] } - } + }; return JSON.stringify(geoJSON); } + testers = asd => { + console.log(asd.target.getZoom()); + }; + render() { return ( - <Map className='map' center={this.props.position} zoom={this.props.zoom}> + <Map + className='map' + center={this.props.position} + zoom={this.props.zoom} + minZoom='7' + maxZoom='17' + zoomControl={false}> <TileLayer attribution='© <a href="https://www.maanmittauslaitos.fi/">Maanmittauslaitos</a>' url={this.props.mapUrl} /> - <ZoomControl position='topright' /> - <DrawTools position={this.props.position} /> + + <ZoomControl position="topright" /> + <DrawTools position={this.props.position} /> <Marker position={this.props.position}> <Popup> Se on perjantai, my dudes <br /> </Popup> </Marker> - {this.state.ownLat !== null && <Marker position={[this.state.ownLat, this.state.ownLng]}> - <Popup> - User's real position.<br /> - </Popup> - </Marker>} + {this.state.ownLat !== null && ( + <Marker position={[this.state.ownLat, this.state.ownLng]}> + <Popup> + User's real position. + <br /> + </Popup> + </Marker> + )} </Map> ); } } -export default UserMap; \ No newline at end of file +export default UserMap; diff --git a/src/icons/button-textbox.png b/src/icons/button-textbox.png new file mode 100644 index 0000000000000000000000000000000000000000..e36a2872bdf8f68df996d35159335a77211ead7a Binary files /dev/null and b/src/icons/button-textbox.png differ diff --git a/src/icons/nil.png b/src/icons/nil.png new file mode 100644 index 0000000000000000000000000000000000000000..ae058ee7bffad41634a20cd463fc94219f0de69b Binary files /dev/null and b/src/icons/nil.png differ