From a68b9988c2275c021e530f75b92c92defb9ac120 Mon Sep 17 00:00:00 2001 From: Andreas Schmitz Date: Tue, 20 Mar 2018 10:19:38 +0100 Subject: [PATCH 1/6] added geolocation button --- assets/geolocation-marker-heading.png | Bin 0 -> 1673 bytes assets/geolocation-marker.png | Bin 0 -> 829 bytes .../GeoLocationButton.example.jsx | 63 +++++ .../GeoLocationButton.example.md | 8 + .../GeoLocationButton/GeoLocationButton.jsx | 265 ++++++++++++++++++ .../GeoLocationButton/GeoLocationButton.less | 60 ++++ .../GeoLocationButton.spec.jsx | 28 ++ src/Util/MathUtil/MathUtil.js | 19 ++ src/Util/MathUtil/MathUtil.spec.js | 34 +++ src/index.js | 4 + webpack.examples.common.config.js | 1 + 11 files changed, 482 insertions(+) create mode 100644 assets/geolocation-marker-heading.png create mode 100644 assets/geolocation-marker.png create mode 100644 src/Button/GeoLocationButton/GeoLocationButton.example.jsx create mode 100644 src/Button/GeoLocationButton/GeoLocationButton.example.md create mode 100644 src/Button/GeoLocationButton/GeoLocationButton.jsx create mode 100644 src/Button/GeoLocationButton/GeoLocationButton.less create mode 100644 src/Button/GeoLocationButton/GeoLocationButton.spec.jsx create mode 100644 src/Util/MathUtil/MathUtil.js create mode 100644 src/Util/MathUtil/MathUtil.spec.js diff --git a/assets/geolocation-marker-heading.png b/assets/geolocation-marker-heading.png new file mode 100644 index 0000000000000000000000000000000000000000..5edfadccce934226dcbc7c30e4b774b07cc6991c GIT binary patch literal 1673 zcmV;426p+0P)(V6D@%)Fb#LzC9 zow}1F$+BffmSjzTp6)*AKIhq1X>#D8tNZT#-TTfv=iGA@Aq2HVQ53~!niN2o6!A3x zYfb7SQ2~qmRb^jAsxE(PN=>lbtpT+GcG*S(i>9%aTDw;Fc1WlqL3Y3a)W_rT-^b(e zcY%7@XDp_e%=Sox5W7@Dt$-6~0-g?qLg$5)P$+aBcv?Pl%CX8`j$(cblL@TA0YC!| zrZzUl3Rc&50qV-Rdrggv1HeNd1N;vt1G`MJ*A#ofuJQ5lGmUO{`?XsS)N8jMsEuxS z`}p|y8NemSSmm7E=GbEbiyZ6*d~I!QU72idbs?G4)wgGb`u40?NaplRHn-Z=*4731 z^-qE-Y{1iUf1qSm{do^UvPLE5;k)~;2PZHg*)TwBepZ~zayFY3Z zmyRFeaJ^mmVm*)3rYb*dZ+muodwb%}ojWO@#G`23=eLJ|V~Ip!QV1b#E^is`E7nt~ z<@Ho*+4yffOC%DLz%e;@$FB`L+o(pAcWi8I(3o7-_0r7D%xHgq|I5IOz>EF;{V&hV z%#4i`;oBf$5Ehlek2Zf-6LlN9xeDC!k+m)P9gTpS)Az6d-g=Qc`~ zRgte-C+&0a=FOWIdwP0)r6`K^t8|gyO~;vy)g3>zf}~)`saVG(f{5eQ!80w*%G<{T|g{bVlJLz zvB4sbCZ*k396Y+SAcH;n&0nlou8k7Pt!EtpXOHi<-~vY23$?~ zW8V>e5%7}9WWMU?==f&ixm<3=Zc%vN>wIGH^Ij)*i$X4!TbZ7o-U2Er)$l8A zY;61+py!D8#9(8NWRw71rRvbdNF*`^aP4FZPigkYhCZd)xpuMz0Lj=%LK@X@ZcHQ+ zBVMn!>mT>iycGTq(GaVu@VCKd`0;ldSY2J6Iehr=&wvdeYcBZIcszdh^y$-Q z{LRj~m!3Juos}%f?Q%`%_YOJu`&mET-_|IVN}0=-FAps&EF`FAxB^rYvy1A{a&%;5 zsuFO+CHS$ywd=Xj4DME-^^{|adOSsVpG{ zsU=LuzYs#~RGTKav4BMajkfu!pi3>A+7(O{XRR{Utj0pM?jXjMVdqX_E@S@>+${xS Tjt zp$~i@2|TZS^9?*-O+?T%O#_moRQdozB?ajGsTk-0ZIwvfcK`uIMC2f-D%@TMFD&*#Y)cI_kxO0u2RafKlL-<2cimN~Kt<)x1`#)eu#!R;y8~)x1ij zQgj?=8aSnTGRiQLuS=;_Wq>hY!gbvn&1UnH9H>^*kyg|>_(+<~<|o&6ZvYdjH>0c+ z>a#8N)(Ow^9>sASiHOwvJ-M^|Mb18bFUEs6Vmx>wXP>^8JIi0B=I@D!NF2wJ=XsA5 zKB}yAvf2T_a$WcQ+}zw_P1B6|weMVe{t>Slu=z707KjBle@48n|Ki!&7DosBm>wO} zbGh7wbUOWdb#?Wd+W%MsY`}6HC%eAB{@k|h@%gpy+45Kr^Ca_CIHIVhf{ztG&FP?;MLclYc#2(M;Qi?(gCedC}d6390}Vo?;7Eu;dhOY zupMKX=18GX$O4-F&#wP09gtF~)Cj|H%QSS(WX(e(XR;=yp%aGTR;g5K0HUJ?%J%m5 z2Y^e*tV6>|k22aoM^_iS)oS%E!2OG392rP;jUE|DasT2N0Ls_}+WT-mpI`8Of5Wl* zC|=HW4HqxxaI8Lj-`~jR^9u=_%w8=B0xZk=I5RVIZF+Q2Kc4C5Wi?=@Eq`6}b+@b(sDJzP{T|T4;%800000NkvXX Hu0mjfcPoHH literal 0 HcmV?d00001 diff --git a/src/Button/GeoLocationButton/GeoLocationButton.example.jsx b/src/Button/GeoLocationButton/GeoLocationButton.example.jsx new file mode 100644 index 0000000000..9a154081d5 --- /dev/null +++ b/src/Button/GeoLocationButton/GeoLocationButton.example.jsx @@ -0,0 +1,63 @@ +import React from 'react'; +import { render } from 'react-dom'; + +import OlMap from 'ol/map'; +import OlView from 'ol/view'; +import OlLayerTile from 'ol/layer/tile'; +import OlSourceOsm from 'ol/source/osm'; +import olProj from 'ol/proj'; + +import { + GeoLocationButton, + ToggleGroup +} from '../../index.js'; + +// +// ***************************** SETUP ***************************************** +// +const map = new OlMap({ + layers: [ + new OlLayerTile({ + name: 'OSM', + source: new OlSourceOsm() + }) + ], + view: new OlView({ + center: olProj.fromLonLat([37.40570, 8.81566]), + zoom: 4 + }) +}); + +// +// ***************************** SETUP END ************************************* +// +render( +
+
+ +
+ + undefined} + map={map} + showMarker={true} + follow={true} + > + Track location + + + +
+ +
, + + // Target + document.getElementById('exampleContainer'), + + // Callback + () => { + map.setTarget('map'); + } +); diff --git a/src/Button/GeoLocationButton/GeoLocationButton.example.md b/src/Button/GeoLocationButton/GeoLocationButton.example.md new file mode 100644 index 0000000000..0cdc834335 --- /dev/null +++ b/src/Button/GeoLocationButton/GeoLocationButton.example.md @@ -0,0 +1,8 @@ +--- +layout: basic.hbs +title: GeoLocationButton example +description: This is an example showing a geolocation toggle button. +collection: Examples +--- + +This demonstrates the use of the geolocation button. diff --git a/src/Button/GeoLocationButton/GeoLocationButton.jsx b/src/Button/GeoLocationButton/GeoLocationButton.jsx new file mode 100644 index 0000000000..5b60faf3ac --- /dev/null +++ b/src/Button/GeoLocationButton/GeoLocationButton.jsx @@ -0,0 +1,265 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import OlMap from 'ol/map'; +import OlGeolocation from 'ol/geolocation'; +import OlGeomLineString from 'ol/geom/linestring'; +import OlOverlay from 'ol/overlay'; + +import ToggleButton from '../ToggleButton/ToggleButton.jsx'; +import { MathUtil } from '../../index'; + +import './GeoLocationButton.less'; +import mapMarker from '../../../assets/geolocation-marker.png'; +import mapMarkerHeading from '../../../assets/geolocation-marker-heading.png'; + +/** + * The GeoLocationButton. + * + * @class The GeoLocationButton + * @extends React.Component + */ +class GeoLocationButton extends React.Component { + + /** + * The className added to this component. + * + * @type {String} + * @private + */ + className = 'react-geo-geolocationbutton'; + + /** + * The properties. + * @type {Object} + */ + static propTypes = { + /** + * The className which should be added. + * + * @type {String} + */ + className: PropTypes.string, + + /** + * Instance of OL map this component is bound to. + * + * @type {OlMap} + */ + map: PropTypes.instanceOf(OlMap).isRequired, + + /** + * Will be called if geolocation fails. + * + * @type {Function} + */ + onError: PropTypes.func, + + /** + * Will be called when position changes. Receives an object with the properties + * position, accuracy, heading and speed + * + * @type {Function} + */ + onGeolocationChange: PropTypes.func, + + /** + * Whether to show a map marker at the current position. + * + * @type {Boolean} + */ + showMarker: PropTypes.bool, + + /** + * Whether to follow the current position. + * + * @type {Boolean} + */ + follow: PropTypes.bool + }; + + /** + * The default properties. + * @type {Object} + */ + static defaultProps = { + onGeolocationChange: () => undefined, + onError: () => undefined, + showMarker: true, + follow: true + } + + /** + * Creates the MeasureButton. + * + * @constructs MeasureButton + */ + constructor(props) { + super(props); + + this.positions = new OlGeomLineString([], 'XYZM'); + + this.state = { + }; + } + + onGeolocationChange = () => { + const position = this.geolocationInteraction.getPosition(); + const accuracy = this.geolocationInteraction.getAccuracy(); + let heading = this.geolocationInteraction.getHeading() || 0; + const speed = this.geolocationInteraction.getSpeed() || 0; + + const x = position[0]; + const y = position[1]; + const fCoords = this.positions.getCoordinates(); + const previous = fCoords[fCoords.length - 1]; + const prevHeading = previous && previous[2]; + if (prevHeading) { + let headingDiff = heading - MathUtil.mod(prevHeading); + + // force the rotation change to be less than 180° + if (Math.abs(headingDiff) > Math.PI) { + var sign = (headingDiff >= 0) ? 1 : -1; + headingDiff = -sign * (2 * Math.PI - Math.abs(headingDiff)); + } + heading = prevHeading + headingDiff; + } + this.positions.appendCoordinate([x, y, heading, Date.now()]); + + // only keep the 20 last coordinates + this.positions.setCoordinates(this.positions.getCoordinates().slice(-20)); + + if (this.markerEl) { + if (heading && speed) { + this.markerEl.src = mapMarkerHeading; + } else { + this.markerEl.src = mapMarker; + } + } + + this.updateView(); + + this.props.onGeolocationChange({ + position, + accuracy, + heading, + speed + }); + } + + onGeolocationError = () => { + this.props.onError(); + } + + /** + * Called when the button is toggled, this method ensures that everything + * is cleaned up when unpressed, and that geolocating can start when pressed. + * + * @method + */ + onToggle = (pressed) => { + if (!pressed && this.geolocationInteraction) { + this.geolocationInteraction.un('change', this.onGeolocationChange); + this.geolocationInteraction = null; + if (this.marker) { + this.props.map.removeOverlay(this.marker); + this.markerEl.parentNode.removeChild(this.markerEl); + } + } + if (!pressed) { + return; + } + const map = this.props.map; + const view = map.getView(); + + // Geolocation Control + this.geolocationInteraction = new OlGeolocation({ + projection: view.getProjection(), + trackingOptions: { + maximumAge: 10000, + enableHighAccuracy: true, + timeout: 600000 + } + }); + this.geolocationInteraction.setTracking(true); + if (this.props.showMarker) { + this.markerEl = document.getElementById('react-geolocation-overlay').cloneNode(); + this.markerEl.id = null; + this.marker = new OlOverlay({ + positioning: 'center-center', + element: this.markerEl, + stopEvent: false + }); + this.props.map.addOverlay(this.marker); + } + + // add listeners + this.geolocationInteraction.on('change', this.onGeolocationChange); + this.geolocationInteraction.on('error', this.onGeolocationError); + } + + // recenters the view by putting the given coordinates at 3/4 from the top or + // the screen + getCenterWithHeading = (position, rotation, resolution) => { + var size = this.props.map.getSize(); + var height = size[1]; + + return [ + position[0] - Math.sin(rotation) * height * resolution * 1 / 4, + position[1] + Math.cos(rotation) * height * resolution * 1 / 4 + ]; + } + + updateView = () => { + const view = this.props.map.getView(); + const deltaMean = 500; // the geolocation sampling period mean in ms + let previousM = 0; + // use sampling period to get a smooth transition + let m = Date.now() - deltaMean * 1.5; + m = Math.max(m, previousM); + previousM = m; + // interpolate position along positions LineString + const c = this.positions.getCoordinateAtM(m, true); + if (c) { + if (this.props.follow) { + view.setCenter(this.getCenterWithHeading(c, -c[2], view.getResolution())); + view.setRotation(-c[2]); + } + if (this.props.showMarker) { + this.marker.setPosition(c); + } + } + } + + /** + * The render function. + */ + render() { + const { + className, + map, + showMarker, + follow, + onGeolocationChange, + onError, + ...passThroughProps + } = this.props; + + const finalClassName = className + ? `${className} ${this.className}` + : this.className; + + return ( +
+ + +
+ ); + } +} + +export default GeoLocationButton; diff --git a/src/Button/GeoLocationButton/GeoLocationButton.less b/src/Button/GeoLocationButton/GeoLocationButton.less new file mode 100644 index 0000000000..f417381b9e --- /dev/null +++ b/src/Button/GeoLocationButton/GeoLocationButton.less @@ -0,0 +1,60 @@ +@import '../../style/variables.less'; + +button.react-geo-measurebutton { + color: #fff; + background-color: @primary-color; + border-color: darken(@component-background, 10); + + &:focus{ + background-color: lighten(@primary-color, 10); + border-color: lighten(@component-background, 10); + } + + &:hover { + background-color: lighten(@primary-color, 10); + border-color: lighten(@component-background, 10); + } + + &:disabled { + background-color: @component-background; + border-color: darken(@component-background, 10); + } + + &.btn-pressed { + background-color: darken(@primary-color, 20); + border-color: darken(@component-background, 10); + } +} + +.react-geo-measure-tooltip { + position: relative; + background: @measure-dynamic-tooltip-background-color; + border-radius: 4px; + color: white; + padding: 4px 8px; + opacity: 0.7; + white-space: nowrap; +} +.react-geo-measure-tooltip-dynamic { + opacity: 1; + font-weight: bold; +} +.react-geo-measure-tooltip-static { + background-color: @measure-static-tooltip-background-color; + color: black; + border: 1px solid white; +} +.react-geo-measure-tooltip-dynamic:before, +.react-geo-measure-tooltip-static:before { + border-top: 6px solid @measure-dynamic-tooltip-background-color; + border-right: 6px solid transparent; + border-left: 6px solid transparent; + content: ""; + position: absolute; + bottom: -6px; + margin-left: -7px; + left: 50%; +} +.react-geo-measure-tooltip-static:before { + border-top-color: @measure-static-tooltip-background-color; +} diff --git a/src/Button/GeoLocationButton/GeoLocationButton.spec.jsx b/src/Button/GeoLocationButton/GeoLocationButton.spec.jsx new file mode 100644 index 0000000000..31f7d731b3 --- /dev/null +++ b/src/Button/GeoLocationButton/GeoLocationButton.spec.jsx @@ -0,0 +1,28 @@ +/*eslint-env jest*/ +import TestUtil from '../../Util/TestUtil'; + +import { GeoLocationButton } from '../../index'; + +describe('', () => { + + let map; + + beforeEach(() => { + map = TestUtil.createMap(); + }); + + describe('#Basics', () => { + + it('is defined', () => { + expect(GeoLocationButton).not.toBeUndefined(); + }); + + it('can be rendered', () => { + const wrapper = TestUtil.mountComponent(GeoLocationButton, { + map: map + }); + expect(wrapper).not.toBeUndefined(); + }); + + }); +}); diff --git a/src/Util/MathUtil/MathUtil.js b/src/Util/MathUtil/MathUtil.js new file mode 100644 index 0000000000..93756e50bc --- /dev/null +++ b/src/Util/MathUtil/MathUtil.js @@ -0,0 +1,19 @@ +/** + * Helper Class for various calculations. + * + * @class MathUtil + */ +class MathUtil { + + // convert radians to degrees + static radToDeg = (rad) => rad * 360 / (Math.PI * 2); + + // convert degrees to radians + static degToRad = (deg) => deg * Math.PI * 2 / 360; + + // modulo for negative values + static mod = (n) => ((n % (2 * Math.PI)) + (2 * Math.PI)) % (2 * Math.PI); + +} + +export default MathUtil; diff --git a/src/Util/MathUtil/MathUtil.spec.js b/src/Util/MathUtil/MathUtil.spec.js new file mode 100644 index 0000000000..67390040a4 --- /dev/null +++ b/src/Util/MathUtil/MathUtil.spec.js @@ -0,0 +1,34 @@ +/*eslint-env jest*/ + +import { + MathUtil, +} from '../../index'; + +describe('MathUtil', () => { + + describe('Basics', () => { + it('is defined', () => { + expect(MathUtil).toBeDefined(); + }); + }); + + describe('Static methods', () => { + describe('#mod', () => { + it('properly handles negative values', () => { + expect(MathUtil.mod(-1.4)).toBeCloseTo(4.883185307179); + }); + }); + + describe('#radToDeg', () => { + it('converts radians to degrees', () => { + expect(MathUtil.radToDeg(Math.PI)).toBeCloseTo(180); + }); + }); + + describe('#degToRad', () => { + it('converts degrees to radians', () => { + expect(MathUtil.degToRad(180)).toBeCloseTo(Math.PI); + }); + }); + }); +}); diff --git a/src/index.js b/src/index.js index c08c7692d0..12ebeaa1ed 100644 --- a/src/index.js +++ b/src/index.js @@ -4,6 +4,7 @@ import SimpleButton from './Button/SimpleButton/SimpleButton.jsx'; import ToggleButton from './Button/ToggleButton/ToggleButton.jsx'; import ToggleGroup from './Button/ToggleGroup/ToggleGroup.jsx'; import MeasureButton from './Button/MeasureButton/MeasureButton.jsx'; +import GeoLocationButton from './Button/GeoLocationButton/GeoLocationButton.jsx'; import DigitizeButton from './Button/DigitizeButton/DigitizeButton.jsx'; import CoordinateReferenceSystemCombo from './Field/CoordinateReferenceSystemCombo/CoordinateReferenceSystemCombo.jsx'; import NominatimSearch from './Field/NominatimSearch/NominatimSearch.jsx'; @@ -31,6 +32,7 @@ import AnimateUtil from './Util/AnimateUtil/AnimateUtil'; import FeatureUtil from './Util/FeatureUtil/FeatureUtil'; import GeometryUtil from './Util/GeometryUtil/GeometryUtil'; import MapUtil from './Util/MapUtil/MapUtil'; +import MathUtil from './Util/MathUtil/MathUtil'; import MeasureUtil from './Util/MeasureUtil/MeasureUtil'; import ObjectUtil from './Util/ObjectUtil/ObjectUtil'; import ProjectionUtil from './Util/ProjectionUtil/ProjectionUtil'; @@ -52,6 +54,7 @@ export { ToggleButton, ToggleGroup, MeasureButton, + GeoLocationButton, DigitizeButton, LayerTree, LayerTreeNode, @@ -74,6 +77,7 @@ export { GeometryUtil, Logger, MapUtil, + MathUtil, MeasureUtil, CoordinateReferenceSystemCombo, NominatimSearch, diff --git a/webpack.examples.common.config.js b/webpack.examples.common.config.js index 03f740e1ad..c0d9aa4e3a 100644 --- a/webpack.examples.common.config.js +++ b/webpack.examples.common.config.js @@ -9,6 +9,7 @@ const config = { 'Button/ToggleButton/ToggleButton': './src/Button/ToggleButton/ToggleButton.example.jsx', 'Button/ToggleGroup/ToggleGroup': './src/Button/ToggleGroup/ToggleGroup.example.jsx', 'Button/MeasureButton/MeasureButton': './src/Button/MeasureButton/MeasureButton.example.jsx', + 'Button/GeoLocationButton/GeoLocationButton': './src/Button/GeoLocationButton/GeoLocationButton.example.jsx', 'Button/DigitizeButton/DigitizeButton': './src/Button/DigitizeButton/DigitizeButton.example.jsx', 'Button/UploadButton/UploadButton': './src/Button/UploadButton/UploadButton.example.jsx', 'CircleMenu/CircleMenu': './src/CircleMenu/CircleMenu.example.jsx', From 1ea4e81711b382a3f9e8580186534a9d9ea98b94 Mon Sep 17 00:00:00 2001 From: Andreas Schmitz Date: Tue, 20 Mar 2018 14:30:28 +0100 Subject: [PATCH 2/6] made tracking options configurable --- .../GeoLocationButton/GeoLocationButton.jsx | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/Button/GeoLocationButton/GeoLocationButton.jsx b/src/Button/GeoLocationButton/GeoLocationButton.jsx index 5b60faf3ac..1adedf941f 100644 --- a/src/Button/GeoLocationButton/GeoLocationButton.jsx +++ b/src/Button/GeoLocationButton/GeoLocationButton.jsx @@ -6,8 +6,10 @@ import OlGeolocation from 'ol/geolocation'; import OlGeomLineString from 'ol/geom/linestring'; import OlOverlay from 'ol/overlay'; -import ToggleButton from '../ToggleButton/ToggleButton.jsx'; -import { MathUtil } from '../../index'; +import { + MathUtil, + ToggleButton +} from '../../index'; import './GeoLocationButton.less'; import mapMarker from '../../../assets/geolocation-marker.png'; @@ -75,7 +77,13 @@ class GeoLocationButton extends React.Component { * * @type {Boolean} */ - follow: PropTypes.bool + follow: PropTypes.bool, + + /** + * The openlayers tracking options. + * @type {Object} + */ + trackingOptions: PropTypes.object }; /** @@ -86,7 +94,12 @@ class GeoLocationButton extends React.Component { onGeolocationChange: () => undefined, onError: () => undefined, showMarker: true, - follow: true + follow: true, + trackingOptions: { + maximumAge: 10000, + enableHighAccuracy: true, + timeout: 600000 + } } /** @@ -175,11 +188,7 @@ class GeoLocationButton extends React.Component { // Geolocation Control this.geolocationInteraction = new OlGeolocation({ projection: view.getProjection(), - trackingOptions: { - maximumAge: 10000, - enableHighAccuracy: true, - timeout: 600000 - } + trackingOptions: this.props.trackingOptions }); this.geolocationInteraction.setTracking(true); if (this.props.showMarker) { From eca37da70d0b6bb8632826516be0f8f3b7ce57e9 Mon Sep 17 00:00:00 2001 From: Andreas Schmitz Date: Tue, 20 Mar 2018 14:33:10 +0100 Subject: [PATCH 3/6] fixed camel case prop name --- src/Button/GeoLocationButton/GeoLocationButton.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Button/GeoLocationButton/GeoLocationButton.jsx b/src/Button/GeoLocationButton/GeoLocationButton.jsx index 1adedf941f..a9ac5aeb3c 100644 --- a/src/Button/GeoLocationButton/GeoLocationButton.jsx +++ b/src/Button/GeoLocationButton/GeoLocationButton.jsx @@ -83,7 +83,7 @@ class GeoLocationButton extends React.Component { * The openlayers tracking options. * @type {Object} */ - trackingOptions: PropTypes.object + trackingoptions: PropTypes.object }; /** @@ -95,7 +95,7 @@ class GeoLocationButton extends React.Component { onError: () => undefined, showMarker: true, follow: true, - trackingOptions: { + trackingoptions: { maximumAge: 10000, enableHighAccuracy: true, timeout: 600000 @@ -188,7 +188,7 @@ class GeoLocationButton extends React.Component { // Geolocation Control this.geolocationInteraction = new OlGeolocation({ projection: view.getProjection(), - trackingOptions: this.props.trackingOptions + trackingOptions: this.props.trackingoptions }); this.geolocationInteraction.setTracking(true); if (this.props.showMarker) { From e318a976c29312beeba6cc8205dbf871789ebada Mon Sep 17 00:00:00 2001 From: Andreas Schmitz Date: Tue, 20 Mar 2018 14:59:10 +0100 Subject: [PATCH 4/6] moved buttons to geolocation folder, removed unused less file --- .../GeoLocationButton/GeoLocationButton.jsx | 5 +- .../GeoLocationButton/GeoLocationButton.less | 60 ------------------ .../geolocation-marker-heading.png | Bin .../GeoLocationButton}/geolocation-marker.png | Bin 4 files changed, 2 insertions(+), 63 deletions(-) delete mode 100644 src/Button/GeoLocationButton/GeoLocationButton.less rename {assets => src/Button/GeoLocationButton}/geolocation-marker-heading.png (100%) rename {assets => src/Button/GeoLocationButton}/geolocation-marker.png (100%) diff --git a/src/Button/GeoLocationButton/GeoLocationButton.jsx b/src/Button/GeoLocationButton/GeoLocationButton.jsx index a9ac5aeb3c..4a799dbd8f 100644 --- a/src/Button/GeoLocationButton/GeoLocationButton.jsx +++ b/src/Button/GeoLocationButton/GeoLocationButton.jsx @@ -11,9 +11,8 @@ import { ToggleButton } from '../../index'; -import './GeoLocationButton.less'; -import mapMarker from '../../../assets/geolocation-marker.png'; -import mapMarkerHeading from '../../../assets/geolocation-marker-heading.png'; +import mapMarker from './geolocation-marker.png'; +import mapMarkerHeading from './geolocation-marker-heading.png'; /** * The GeoLocationButton. diff --git a/src/Button/GeoLocationButton/GeoLocationButton.less b/src/Button/GeoLocationButton/GeoLocationButton.less deleted file mode 100644 index f417381b9e..0000000000 --- a/src/Button/GeoLocationButton/GeoLocationButton.less +++ /dev/null @@ -1,60 +0,0 @@ -@import '../../style/variables.less'; - -button.react-geo-measurebutton { - color: #fff; - background-color: @primary-color; - border-color: darken(@component-background, 10); - - &:focus{ - background-color: lighten(@primary-color, 10); - border-color: lighten(@component-background, 10); - } - - &:hover { - background-color: lighten(@primary-color, 10); - border-color: lighten(@component-background, 10); - } - - &:disabled { - background-color: @component-background; - border-color: darken(@component-background, 10); - } - - &.btn-pressed { - background-color: darken(@primary-color, 20); - border-color: darken(@component-background, 10); - } -} - -.react-geo-measure-tooltip { - position: relative; - background: @measure-dynamic-tooltip-background-color; - border-radius: 4px; - color: white; - padding: 4px 8px; - opacity: 0.7; - white-space: nowrap; -} -.react-geo-measure-tooltip-dynamic { - opacity: 1; - font-weight: bold; -} -.react-geo-measure-tooltip-static { - background-color: @measure-static-tooltip-background-color; - color: black; - border: 1px solid white; -} -.react-geo-measure-tooltip-dynamic:before, -.react-geo-measure-tooltip-static:before { - border-top: 6px solid @measure-dynamic-tooltip-background-color; - border-right: 6px solid transparent; - border-left: 6px solid transparent; - content: ""; - position: absolute; - bottom: -6px; - margin-left: -7px; - left: 50%; -} -.react-geo-measure-tooltip-static:before { - border-top-color: @measure-static-tooltip-background-color; -} diff --git a/assets/geolocation-marker-heading.png b/src/Button/GeoLocationButton/geolocation-marker-heading.png similarity index 100% rename from assets/geolocation-marker-heading.png rename to src/Button/GeoLocationButton/geolocation-marker-heading.png diff --git a/assets/geolocation-marker.png b/src/Button/GeoLocationButton/geolocation-marker.png similarity index 100% rename from assets/geolocation-marker.png rename to src/Button/GeoLocationButton/geolocation-marker.png From fc182197af92a1bacfbe46b96f50b5539d491a1d Mon Sep 17 00:00:00 2001 From: Andreas Schmitz Date: Tue, 20 Mar 2018 15:10:24 +0100 Subject: [PATCH 5/6] added a couple more tests --- .../GeoLocationButton.spec.jsx | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/Button/GeoLocationButton/GeoLocationButton.spec.jsx b/src/Button/GeoLocationButton/GeoLocationButton.spec.jsx index 31f7d731b3..0b316c93f9 100644 --- a/src/Button/GeoLocationButton/GeoLocationButton.spec.jsx +++ b/src/Button/GeoLocationButton/GeoLocationButton.spec.jsx @@ -24,5 +24,35 @@ describe('', () => { expect(wrapper).not.toBeUndefined(); }); + it('creates the geolocation interaction on the fly', function() { + const wrapper = TestUtil.mountComponent(GeoLocationButton, { + map: map, + showMarker: false + }); + const instance = wrapper.instance(); + expect(instance.geolocationInteraction).toBeUndefined(); + }); + + it('can be pressed', () => { + const wrapper = TestUtil.mountComponent(GeoLocationButton, { + map: map, + showMarker: false + }); + const instance = wrapper.instance(); + instance.onToggle(true); + expect(instance.geolocationInteraction).not.toBeUndefined(); + }); + + it('can be pressed twice', () => { + const wrapper = TestUtil.mountComponent(GeoLocationButton, { + map: map, + showMarker: false + }); + const instance = wrapper.instance(); + instance.onToggle(true); + instance.onToggle(false); + expect(instance.geolocationInteraction).toBeNull(); + }); + }); }); From 30a128180a5043578759486bfb0191b8842c54d8 Mon Sep 17 00:00:00 2001 From: Andreas Schmitz Date: Tue, 20 Mar 2018 15:26:13 +0100 Subject: [PATCH 6/6] added another test --- .../GeoLocationButton.spec.jsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Button/GeoLocationButton/GeoLocationButton.spec.jsx b/src/Button/GeoLocationButton/GeoLocationButton.spec.jsx index 0b316c93f9..190b28ac0a 100644 --- a/src/Button/GeoLocationButton/GeoLocationButton.spec.jsx +++ b/src/Button/GeoLocationButton/GeoLocationButton.spec.jsx @@ -54,5 +54,23 @@ describe('', () => { expect(instance.geolocationInteraction).toBeNull(); }); + it('can use the geolocation interaction', () => { + const onChange = jest.fn(); + const wrapper = TestUtil.mountComponent(GeoLocationButton, { + map: map, + showMarker: false, + onGeolocationChange: onChange + }); + const instance = wrapper.instance(); + instance.onToggle(true); + + const getPosition = jest.fn(); + getPosition.mockReturnValue([2, 3]); + instance.geolocationInteraction.getPosition = getPosition; + + instance.onGeolocationChange(); + expect(onChange).toHaveBeenCalledTimes(1); + }); + }); });