From 7f8d58ff52bad531e5825d272b5d218ec88b3f8a Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Wed, 2 Aug 2017 20:07:09 +0200 Subject: [PATCH 01/18] SPFAM-1032 Move ``circle.js => lib/main.js`` --- circle.js => lib/main.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename circle.js => lib/main.js (100%) diff --git a/circle.js b/lib/main.js similarity index 100% rename from circle.js rename to lib/main.js From b8a9bfb915b12e8c963d54b70f4efd1e8ef8c019 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Wed, 2 Aug 2017 20:07:39 +0200 Subject: [PATCH 02/18] SPFAM-1032 Move ``index.js => example/index.js`` --- index.js => example/index.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename index.js => example/index.js (100%) diff --git a/index.js b/example/index.js similarity index 100% rename from index.js rename to example/index.js From 4e31b212c21ee8fd0f56793e3934627a7e43e655 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Wed, 2 Aug 2017 20:07:55 +0200 Subject: [PATCH 03/18] SPFAM-1032 Move ``index.html => example/index.html`` --- index.html => example/index.html | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename index.html => example/index.html (100%) diff --git a/index.html b/example/index.html similarity index 100% rename from index.html rename to example/index.html From 0733f3f4a9cb5dafacd1e6cc71fd3e511d9268ff Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Thu, 3 Aug 2017 09:58:17 +0200 Subject: [PATCH 04/18] SPFAM-1032 Move helper functions from example/index.js into MapboxCircle, replace index.html with DOM updates from example/index.js --- example/index.html | 39 -------- example/index.js | 226 +++++---------------------------------------- lib/main.js | 210 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 215 insertions(+), 260 deletions(-) delete mode 100644 example/index.html diff --git a/example/index.html b/example/index.html deleted file mode 100644 index a97e458..0000000 --- a/example/index.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - Circles in GL JS - - - - - - - - - - - - - -
-
-
-
-

Mapbox GL Circles

-

Create and edit circle objects in GL JS.

-

Edit the circle radius or center by click+hold+drag on a control point.

-
-
-
-
-
-
-
-
-
-
- - - - \ No newline at end of file diff --git a/example/index.js b/example/index.js index 192b1ce..b131ada 100644 --- a/example/index.js +++ b/example/index.js @@ -1,216 +1,38 @@ 'use strict'; const mapboxgl = require('mapbox-gl'); -const Circle = require('./circle.js'); -// const turfInside = require('@turf/inside'); -const turfHelpers = require('@turf/helpers'); -const turfTruncate = require('@turf/truncate'); -const turfDistance = require('@turf/distance'); -const _ = require('lodash'); +const MapboxCircle = require('../lib/main.js'); + +let mapDiv = document.body.appendChild(document.createElement('div')); +mapDiv.style.position = 'absolute'; +mapDiv.style.top = '100px'; +mapDiv.style.right = 0; +mapDiv.style.left = 0; +mapDiv.style.bottom = 0; // noinspection SpellCheckingInspection mapboxgl.accessToken = 'pk.eyJ1IjoicnNiYXVtYW5uIiwiYSI6IjdiOWEzZGIyMGNkOGY3NWQ4ZTBhN2Y5ZGU2Mzg2NDY2In0.jycgv7qwF8MMIWt4cT0RaQ'; -let mapZoom = 12; - -const map = new mapboxgl.Map({ - container: 'map', +let center = [-75.343, 39.984]; +let map = new mapboxgl.Map({ + container: mapDiv, style: 'mapbox://styles/mapbox/streets-v9', - center: [-75.343, 39.984], - zoom: mapZoom + center: center, + zoom: 14 }); -// Circle Setup - -let center = [-75.343, 39.984]; -let radius = 3; -let units = 'kilometers'; -let properties = {foo: 'bar'}; - -let myCircle = new Circle(center, radius, { - units: units, - zoom: mapZoom, - properties: properties -}); +// MapboxCircle Setup // DOM elements -let boundsEl = document.getElementById('circleBounds'); -// let radiusEl = document.getElementById('selectRadius'); -// let dragEl = document.getElementById('selectRadius'); -let centerEl = document.getElementById('circleCenter'); -let radiusLabelEl = document.getElementById('circleRadiusLabel'); -boundsEl.innerHTML = 'Bounds: ' + myCircle.getBounds(); -centerEl.innerHTML = 'Center: ' + myCircle.getCenter(); -radiusLabelEl.innerHTML = 'Radius: ' + myCircle.getRadius() + ' ' + units; - -// Helper functions - -let animateCircle = function() { - // map.on('sourcedata', onSourceData) - map.getSource('circle-1').setData(myCircle.asGeojson()); - boundsEl.innerHTML = 'Bounds: ' + myCircle.getBounds(); - centerEl.innerHTML = 'Center: ' + myCircle.getCenter(); -}; - -let adjustCirclePrecision = function() { - let curZoom = map.getZoom(); - myCircle.updateZoom(curZoom); - animateCircle(); -}; - -let onMoveCircle = function(e) { - let mousePoint = turfTruncate(turfHelpers.point(map.unproject(e.point).toArray()), 6); - myCircle.updateCenter(mousePoint.geometry.coordinates); - animateCircle(); -}; - -let mouseUpCircle = function() { - map.setPaintProperty('circle-center-point', 'circle-color', '#fb6a4a'); - map.dragPan.enable(); - map.off('mousemove', onMoveCircle); -}; - -let mouseDownCircle = function() { - map.dragPan.disable(); - map.setPaintProperty('circle-center-point', 'circle-color', '#a50f15'); - map.on('mousemove', onMoveCircle); - map.once('mouseup', mouseUpCircle); -}; - -let onMovePoint = function(event) { - let clickPoint = map.unproject(event.point).toArray(); - myCircle.updateRadius(turfDistance(myCircle.getCenter(), clickPoint, units)); - radiusLabelEl.innerHTML = 'Radius: ' + Math.trunc(myCircle.getRadius()) + ' ' + units; - animateCircle(); -}; - -let mouseUpPoint = function() { - map.setPaintProperty('circle-control-points', 'circle-color', 'white'); - map.dragPan.enable(); - map.off('mousemove', onMovePoint); -}; - -let mouseDownPoint = function() { - map.dragPan.disable(); - map.setPaintProperty('circle-control-points', 'circle-color', '#a50f15'); - map.on('mousemove', onMovePoint); - map.once('mouseup', mouseUpPoint); -}; - -let onMousemove = function(e) { - map.off('mousedown', mouseDownCircle); - map.off('mousedown', mouseDownPoint); - - let pointFeatures = map.queryRenderedFeatures(e.point, { - layers: ['circle-control-points'] - }); - - let circleFeatures = map.queryRenderedFeatures(e.point, { - layers: ['circle-center-point'] - }); - - if ((!pointFeatures.length) && (!circleFeatures.length)) { - map.getCanvas().style.cursor = ''; - } - - if (pointFeatures.length) { - map.getCanvas().style.cursor = 'pointer'; - map.once('mousedown', mouseDownPoint); - } else if (circleFeatures.length) { - map.getCanvas().style.cursor = 'pointer'; - map.once('mousedown', mouseDownCircle); +let boundsEl = document.body.appendChild(document.createElement('div')); +let centerEl = document.body.appendChild(document.createElement('div')); +let radiusEl = document.body.appendChild(document.createElement('div')); + +window.myCircle = new MapboxCircle(map, center, 300, { + properties: {foo: 'bar'}, + feedbackEls: { + boundsEl: boundsEl, + centerEl: centerEl, + radiusEl: radiusEl } -}; - -map.on('load', () => { - map.addSource('circle-1', { - type: 'geojson', - data: myCircle.asGeojson(), - buffer: 1 - }); - - map.addLayer({ - id: 'circle-line', - type: 'line', - source: 'circle-1', - paint: { - 'line-color': '#fb6a4a', - 'line-width': { - stops: [ - [0, 0.1], - [16, 5] - ] - } - }, - filter: ['==', '$type', 'Polygon'] - }, 'waterway-label'); - - map.addLayer({ - id: 'circle-fill', - type: 'fill', - source: 'circle-1', - paint: { - 'fill-color': '#fb6a4a', - 'fill-opacity': 0.5 - }, - filter: ['==', '$type', 'Polygon'] - }, 'waterway-label'); - - map.addLayer({ - id: 'circle-control-points', - type: 'circle', - source: 'circle-1', - paint: { - 'circle-color': 'white', - 'circle-radius': { - stops: [ - [0, 6], - [4, 10], - [18, 12] - ] - }, - 'circle-stroke-color': 'black', - 'circle-stroke-width': { - stops: [ - [0, 0.1], - [8, 1], - [16, 4] - ] - } - }, - filter: ['all', ['==', '$type', 'Point'], - ['!=', 'type', 'center'] - ] - }); - - map.addLayer({ - id: 'circle-center-point', - type: 'circle', - source: 'circle-1', - paint: { - 'circle-color': '#fb6a4a', - 'circle-radius': { - stops: [ - [0, 6], - [4, 10], - [18, 12] - ] - }, - 'circle-stroke-color': 'black', - 'circle-stroke-width': { - stops: [ - [0, 0.1], - [8, 1], - [16, 4] - ] - } - }, - filter: ['all', ['==', '$type', 'Point'], - ['==', 'type', 'center'] - ] - }); - - // Add map event listeners - map.on('zoomend', adjustCirclePrecision); - map.on('mousemove', _.debounce(onMousemove, 16)); }); diff --git a/lib/main.js b/lib/main.js index 88bb167..d6210bf 100644 --- a/lib/main.js +++ b/lib/main.js @@ -1,33 +1,37 @@ 'use strict'; +const _ = require('lodash'); const turfCircle = require('@turf/circle'); // const turfLineDistance = require('@turf/line-distance'); const turfBbox = require('@turf/bbox'); const turfBboxPoly = require('@turf/bbox-polygon'); const turfTruncate = require('@turf/truncate'); const turfDestination = require('@turf/destination'); +const turfDistance = require('@turf/distance'); const turfHelpers = require('@turf/helpers'); -function Circle(center, radius, options) { +function MapboxCircle(map, center, radius, options) { + this.map = map; this.center = center; // Point geojson feature or array of [long,lat] this.radius = radius; // Radius of circle // miles, kilometers, degrees, or radians - this.units = options.units ? options.units : 'kilometers'; + this.units = 'meters'; // Current zoom level detail of circle - this.zoom = options.zoom ? options.zoom : 8; + this.zoom = this.map.getZoom(); + + if (options.feedbackEls) { // TODO: Remove me! + this.boundsEl = options.feedbackEls.boundsEl; + this.centerEl = options.feedbackEls.centerEl; + this.radiusEl = options.feedbackEls.radiusEl; + } + // JSON Object - property metadata for circle this.properties = options.properties ? options.properties : {}; this.steps = 100; // Default steps - this.circle_gj = turfCircle( - this.center, - this.radius, - this.steps, - this.units, - this.properties - ); + this.circle_gj = turfCircle(this.center, this.radius, this.steps, this.units, this.properties); this.controlPoints = [ turfDestination(this.center, this.radius, 0, this.units), @@ -39,13 +43,7 @@ function Circle(center, radius, options) { this._updateCircle = function() { this.steps = this._calcSteps(this.zoom); - this.circle_gj = turfCircle( - this.center, - this.radius, - this.steps, - this.units, - this.properties - ); + this.circle_gj = turfCircle(this.center, this.radius, this.steps, this.units, this.properties); this.controlPoints = [ turfDestination(this.center, this.radius, 0, this.units), @@ -64,8 +62,9 @@ function Circle(center, radius, options) { }; this._calcSteps(this.zoom); + console.log(this.steps); - this.asGeojson = function() { + this.asGeoJSON = function() { let feats = this.controlPoints; feats.push(this.circle_gj); feats.push(turfHelpers.point(this.center, {'type': 'center'})); @@ -122,6 +121,179 @@ function Circle(center, radius, options) { this.getControlPoints = function() { return turfHelpers.featureCollection(this.controlPoints); }; + + this.animate = function() { + // map.on('sourcedata', onSourceData) + this.map.getSource('circle-1').setData(this.asGeoJSON()); + this.boundsEl.innerHTML = 'Bounds: ' + this.getBounds(); + this.centerEl.innerHTML = 'Center: ' + this.getCenter(); + }; + + this.adjustPrecision = function() { + this.updateZoom(this.map.getZoom()); + this.animate(); + }.bind(this); + + this.onMove = function(event) { + let mousePoint = turfTruncate(turfHelpers.point(this.map.unproject(event.point).toArray()), 6); + this.updateCenter(mousePoint.geometry.coordinates); + this.animate(); + }.bind(this); + + this.onMouseUp = function() { + this.map.setPaintProperty('circle-center-point', 'circle-color', '#fb6a4a'); + this.map.dragPan.enable(); + this.map.off('mousemove', this.onMove); + }.bind(this); + + this.onMouseDown = function() { + this.map.dragPan.disable(); + this.map.setPaintProperty('circle-center-point', 'circle-color', '#a50f15'); + this.map.on('mousemove', this.onMove); + this.map.once('mouseup', this.onMouseUp); + }.bind(this); + + this.onHandleMove = function(event) { + let clickPoint = this.map.unproject(event.point).toArray(); + this.updateRadius(turfDistance(this.getCenter(), clickPoint, 'meters')); + this.radiusEl.innerHTML = 'Radius: ' + Math.trunc(this.getRadius()) + ' meters'; + this.animate(); + }.bind(this); + + this.onHandleMouseUp = function() { + this.map.setPaintProperty('circle-control-points', 'circle-color', 'white'); + this.map.dragPan.enable(); + this.map.off('mousemove', this.onHandleMove); + }.bind(this); + + this.onHandleMouseDown = function() { + this.map.dragPan.disable(); + this.map.setPaintProperty('circle-control-points', 'circle-color', '#a50f15'); + this.map.on('mousemove', this.onHandleMove); + this.map.once('mouseup', this.onHandleMouseUp); + }.bind(this); + + this.onMouseMove = function(event) { + this.map.off('mousedown', this.onMouseDown); + this.map.off('mousedown', this.onHandleMouseDown); + + let pointFeatures = this.map.queryRenderedFeatures(event.point, { + layers: ['circle-control-points'] + }); + + let circleFeatures = this.map.queryRenderedFeatures(event.point, { + layers: ['circle-center-point'] + }); + + if ((!pointFeatures.length) && (!circleFeatures.length)) { + this.map.getCanvas().style.cursor = ''; + } + + if (pointFeatures.length) { + this.map.getCanvas().style.cursor = 'pointer'; + this.map.once('mousedown', this.onHandleMouseDown); + } else if (circleFeatures.length) { + this.map.getCanvas().style.cursor = 'pointer'; + this.map.once('mousedown', this.onMouseDown); + } + }.bind(this); + + this.addToMap = function(targetMap) { + targetMap.on('load', () => { + targetMap.addSource('circle-1', { + type: 'geojson', + data: this.asGeoJSON(), + buffer: 1 + }); + + targetMap.addLayer({ + id: 'circle-line', + type: 'line', + source: 'circle-1', + paint: { + 'line-color': '#fb6a4a', + 'line-width': { + stops: [ + [0, 0.1], + [16, 5] + ] + } + }, + filter: ['==', '$type', 'Polygon'] + }, 'waterway-label'); + + targetMap.addLayer({ + id: 'circle-fill', + type: 'fill', + source: 'circle-1', + paint: { + 'fill-color': '#fb6a4a', + 'fill-opacity': 0.5 + }, + filter: ['==', '$type', 'Polygon'] + }, 'waterway-label'); + + targetMap.addLayer({ + id: 'circle-control-points', + type: 'circle', + source: 'circle-1', + paint: { + 'circle-color': 'white', + 'circle-radius': { + stops: [ + [0, 6], + [4, 10], + [18, 12] + ] + }, + 'circle-stroke-color': 'black', + 'circle-stroke-width': { + stops: [ + [0, 0.1], + [8, 1], + [16, 4] + ] + } + }, + filter: ['all', ['==', '$type', 'Point'], + ['!=', 'type', 'center'] + ] + }); + + targetMap.addLayer({ + id: 'circle-center-point', + type: 'circle', + source: 'circle-1', + paint: { + 'circle-color': '#fb6a4a', + 'circle-radius': { + stops: [ + [0, 6], + [4, 10], + [18, 12] + ] + }, + 'circle-stroke-color': 'black', + 'circle-stroke-width': { + stops: [ + [0, 0.1], + [8, 1], + [16, 4] + ] + } + }, + filter: ['all', ['==', '$type', 'Point'], + ['==', 'type', 'center'] + ] + }); + + // Add map event listeners + targetMap.on('zoomend', this.adjustPrecision); + targetMap.on('mousemove', _.debounce(this.onMouseMove, 16)); + }); + }; + + this.addToMap(map); } -module.exports = exports = Circle; +module.exports = exports = MapboxCircle; From 1ce2ba8ff87e8f9ee7bd22bdb00c83d288059a36 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Thu, 3 Aug 2017 13:55:18 +0200 Subject: [PATCH 05/18] SPFAM-1032 Remove dead code and unused methods --- example/index.js | 10 ++------ lib/main.js | 67 ++++++++++++++---------------------------------- 2 files changed, 21 insertions(+), 56 deletions(-) diff --git a/example/index.js b/example/index.js index b131ada..d111faf 100644 --- a/example/index.js +++ b/example/index.js @@ -24,15 +24,9 @@ let map = new mapboxgl.Map({ // MapboxCircle Setup // DOM elements -let boundsEl = document.body.appendChild(document.createElement('div')); -let centerEl = document.body.appendChild(document.createElement('div')); -let radiusEl = document.body.appendChild(document.createElement('div')); +let statusEl = document.body.appendChild(document.createElement('div')); window.myCircle = new MapboxCircle(map, center, 300, { properties: {foo: 'bar'}, - feedbackEls: { - boundsEl: boundsEl, - centerEl: centerEl, - radiusEl: radiusEl - } + statusEl: statusEl }); diff --git a/lib/main.js b/lib/main.js index d6210bf..a0efaf8 100644 --- a/lib/main.js +++ b/lib/main.js @@ -14,56 +14,40 @@ function MapboxCircle(map, center, radius, options) { this.map = map; this.center = center; // Point geojson feature or array of [long,lat] this.radius = radius; // Radius of circle + this.statusEl = options.statusEl; + this.properties = options.properties ? options.properties : {}; // JSON Object - property metadata for circle // miles, kilometers, degrees, or radians this.units = 'meters'; // Current zoom level detail of circle this.zoom = this.map.getZoom(); - if (options.feedbackEls) { // TODO: Remove me! - this.boundsEl = options.feedbackEls.boundsEl; - this.centerEl = options.feedbackEls.centerEl; - this.radiusEl = options.feedbackEls.radiusEl; - } + this.steps = null; // No default steps + this.circle_gj = null; + this.controlPoints = null; - // JSON Object - property metadata for circle - this.properties = options.properties ? options.properties : {}; - - this.steps = 100; // Default steps - - this.circle_gj = turfCircle(this.center, this.radius, this.steps, this.units, this.properties); - - this.controlPoints = [ - turfDestination(this.center, this.radius, 0, this.units), - turfDestination(this.center, this.radius, 90, this.units), - turfDestination(this.center, this.radius, 180, this.units), - turfDestination(this.center, this.radius, -90, this.units) - ]; + this._updateSteps = function(zoom) { + if (zoom <= 0.1) zoom = 0.1; + console.log(zoom); + let radiusKm = turfHelpers.convertDistance(this.radius, this.units, 'kilometers'); + this.steps = (Math.sqrt(radiusKm * 250) * zoom ^ 2); + }; this._updateCircle = function() { - this.steps = this._calcSteps(this.zoom); - + this._updateSteps(this.zoom); this.circle_gj = turfCircle(this.center, this.radius, this.steps, this.units, this.properties); - this.controlPoints = [ turfDestination(this.center, this.radius, 0, this.units), turfDestination(this.center, this.radius, 90, this.units), turfDestination(this.center, this.radius, 180, this.units), turfDestination(this.center, this.radius, -90, this.units) ]; - }; - - this._calcSteps = function(zoom) { - if (zoom <= 0.1) { - zoom = 0.1; + if (this.statusEl) { + this.statusEl.innerHTML = ('Center: ' + this.getCenter() + ' / Radius: ' + Math.trunc(this.getRadius()) + + ' meters / Bounds: ' + this.getBounds()); } - let radiusKm = turfHelpers.convertDistance(this.radius, this.units, 'kilometers'); - this.steps = (Math.sqrt(radiusKm * 250) * zoom ^ 2); }; - this._calcSteps(this.zoom); - console.log(this.steps); - this.asGeoJSON = function() { let feats = this.controlPoints; feats.push(this.circle_gj); @@ -82,17 +66,7 @@ function MapboxCircle(map, center, radius, options) { }; this.updateZoom = function(newZoom) { - this.zoom = this._calcSteps(newZoom); - this._updateCircle(); - }; - - this.updateSteps = function(newSteps) { - this.steps = newSteps; - this._updateCircle(); - }; - - this.updateUnits = function(newUnits) { - this.units = newUnits; + this.zoom = newZoom; this._updateCircle(); }; @@ -125,8 +99,6 @@ function MapboxCircle(map, center, radius, options) { this.animate = function() { // map.on('sourcedata', onSourceData) this.map.getSource('circle-1').setData(this.asGeoJSON()); - this.boundsEl.innerHTML = 'Bounds: ' + this.getBounds(); - this.centerEl.innerHTML = 'Center: ' + this.getCenter(); }; this.adjustPrecision = function() { @@ -156,7 +128,6 @@ function MapboxCircle(map, center, radius, options) { this.onHandleMove = function(event) { let clickPoint = this.map.unproject(event.point).toArray(); this.updateRadius(turfDistance(this.getCenter(), clickPoint, 'meters')); - this.radiusEl.innerHTML = 'Radius: ' + Math.trunc(this.getRadius()) + ' meters'; this.animate(); }.bind(this); @@ -198,7 +169,7 @@ function MapboxCircle(map, center, radius, options) { } }.bind(this); - this.addToMap = function(targetMap) { + this.addTo = function(targetMap) { targetMap.on('load', () => { targetMap.addSource('circle-1', { type: 'geojson', @@ -292,8 +263,8 @@ function MapboxCircle(map, center, radius, options) { targetMap.on('mousemove', _.debounce(this.onMouseMove, 16)); }); }; - - this.addToMap(map); + this._updateCircle(); + this.addTo(map); } module.exports = exports = MapboxCircle; From ba98d1855565936cfa5c50ac47cf1289a5b3df94 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Thu, 3 Aug 2017 14:48:32 +0200 Subject: [PATCH 06/18] SPFAM-1032 Refactor into new-style class --- lib/main.js | 187 +++++++++++++++++++++++++++------------------------- 1 file changed, 96 insertions(+), 91 deletions(-) diff --git a/lib/main.js b/lib/main.js index a0efaf8..fa8bbb2 100644 --- a/lib/main.js +++ b/lib/main.js @@ -2,7 +2,6 @@ const _ = require('lodash'); const turfCircle = require('@turf/circle'); -// const turfLineDistance = require('@turf/line-distance'); const turfBbox = require('@turf/bbox'); const turfBboxPoly = require('@turf/bbox-polygon'); const turfTruncate = require('@turf/truncate'); @@ -10,67 +9,82 @@ const turfDestination = require('@turf/destination'); const turfDistance = require('@turf/distance'); const turfHelpers = require('@turf/helpers'); -function MapboxCircle(map, center, radius, options) { - this.map = map; - this.center = center; // Point geojson feature or array of [long,lat] - this.radius = radius; // Radius of circle - this.statusEl = options.statusEl; - this.properties = options.properties ? options.properties : {}; // JSON Object - property metadata for circle - - // miles, kilometers, degrees, or radians - this.units = 'meters'; - // Current zoom level detail of circle - this.zoom = this.map.getZoom(); - - this.steps = null; // No default steps - this.circle_gj = null; - this.controlPoints = null; - - this._updateSteps = function(zoom) { - if (zoom <= 0.1) zoom = 0.1; - console.log(zoom); - let radiusKm = turfHelpers.convertDistance(this.radius, this.units, 'kilometers'); - this.steps = (Math.sqrt(radiusKm * 250) * zoom ^ 2); - }; - - this._updateCircle = function() { - this._updateSteps(this.zoom); - this.circle_gj = turfCircle(this.center, this.radius, this.steps, this.units, this.properties); +class MapboxCircle { + set center(value) { + this._center = value; + this._updateCircle(); + } + get center() { + return this._center; + } + set radius(value) { + this._radius = value; + this._updateCircle(); + } + get radius() { + return this._radius; + } + set zoom(value) { + this._zoom = value; + this._updateCircle(); + } + constructor(map, center, radius, options) { + this.map = map; + this._center = center; // Point geojson feature or array of [long,lat]. + this._radius = radius; // Radius of circle. + this.statusEl = options.statusEl; + this.properties = options.properties ? options.properties : {}; // JSON Object - property metadata for circle. + + this.units = 'meters'; + this._zoom = this.map.getZoom(); + + this.steps = null; // No default steps + this.circle_gj = null; + this.controlPoints = null; + + // Bind event handlers. + this.onMouseMove = this.onMouseMove.bind(this); + this.onMouseDown = this.onMouseDown.bind(this); + this.onHandleMouseDown = this.onHandleMouseDown.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + this.onHandleMouseUp = this.onHandleMouseUp.bind(this); + this.onMove = this.onMove.bind(this); + this.onHandleMove = this.onHandleMove.bind(this); + this.onZoomEnd = this.onZoomEnd.bind(this); + + // Initialize circle object. + this._updateCircle(); + this.addTo(map); + } + + _updateSteps(zoom) { + if (!zoom || zoom <= 0.1) zoom = 0.1; + this.steps = (Math.sqrt(Math.trunc(this._radius * 0.25)) * zoom ^ 2); + } + + _updateCircle() { + this._updateSteps(this._zoom); + this.circle_gj = turfCircle(this._center, this._radius, this.steps, this.units, this.properties); this.controlPoints = [ - turfDestination(this.center, this.radius, 0, this.units), - turfDestination(this.center, this.radius, 90, this.units), - turfDestination(this.center, this.radius, 180, this.units), - turfDestination(this.center, this.radius, -90, this.units) + turfDestination(this._center, this._radius, 0, this.units), + turfDestination(this._center, this._radius, 90, this.units), + turfDestination(this._center, this._radius, 180, this.units), + turfDestination(this._center, this._radius, -90, this.units) ]; if (this.statusEl) { - this.statusEl.innerHTML = ('Center: ' + this.getCenter() + ' / Radius: ' + Math.trunc(this.getRadius()) + + this.statusEl.innerHTML = ('Center: ' + this._center + ' / Radius: ' + Math.trunc(this._radius) + ' meters / Bounds: ' + this.getBounds()); } - }; + } - this.asGeoJSON = function() { + asGeoJSON() { let feats = this.controlPoints; feats.push(this.circle_gj); - feats.push(turfHelpers.point(this.center, {'type': 'center'})); + feats.push(turfHelpers.point(this._center, {'type': 'center'})); return turfHelpers.featureCollection(feats); - }; - - this.updateCenter = function(newCenter) { - this.center = newCenter; - this._updateCircle(); - }; - - this.updateRadius = function(newRadius) { - this.radius = newRadius; - this._updateCircle(); - }; + } - this.updateZoom = function(newZoom) { - this.zoom = newZoom; - this._updateCircle(); - }; - - this.getBounds = function() { + getBounds() { let bboxPoly = turfTruncate(turfBboxPoly(turfBbox(this.circle_gj)), 6); return [ bboxPoly.geometry.coordinates[0][0][0], @@ -78,73 +92,66 @@ function MapboxCircle(map, center, radius, options) { bboxPoly.geometry.coordinates[0][2][0], bboxPoly.geometry.coordinates[0][2][1] ]; - }; + } - this.getBboxPoly = function() { + getBboxPoly() { return turfTruncate(turfBboxPoly(turfBbox(this.circle_gj)), 6); - }; - - this.getCenter = function() { - return this.center; - }; - - this.getRadius = function() { - return this.radius; - }; + } - this.getControlPoints = function() { + getControlPoints() { return turfHelpers.featureCollection(this.controlPoints); - }; + } - this.animate = function() { + animate() { // map.on('sourcedata', onSourceData) this.map.getSource('circle-1').setData(this.asGeoJSON()); - }; + } - this.adjustPrecision = function() { - this.updateZoom(this.map.getZoom()); + onZoomEnd() { + // Adjust circle precision. + this.zoom = this.map.getZoom(); this.animate(); - }.bind(this); + } - this.onMove = function(event) { + onMove(event) { let mousePoint = turfTruncate(turfHelpers.point(this.map.unproject(event.point).toArray()), 6); - this.updateCenter(mousePoint.geometry.coordinates); + this.center = mousePoint.geometry.coordinates; this.animate(); - }.bind(this); + } - this.onMouseUp = function() { + onMouseUp() { this.map.setPaintProperty('circle-center-point', 'circle-color', '#fb6a4a'); this.map.dragPan.enable(); this.map.off('mousemove', this.onMove); - }.bind(this); + } - this.onMouseDown = function() { + onMouseDown() { this.map.dragPan.disable(); this.map.setPaintProperty('circle-center-point', 'circle-color', '#a50f15'); this.map.on('mousemove', this.onMove); this.map.once('mouseup', this.onMouseUp); - }.bind(this); + } - this.onHandleMove = function(event) { + onHandleMove(event) { let clickPoint = this.map.unproject(event.point).toArray(); - this.updateRadius(turfDistance(this.getCenter(), clickPoint, 'meters')); + this.radius = turfDistance(this._center, clickPoint, 'meters'); this.animate(); - }.bind(this); + } - this.onHandleMouseUp = function() { + onHandleMouseUp() { this.map.setPaintProperty('circle-control-points', 'circle-color', 'white'); this.map.dragPan.enable(); this.map.off('mousemove', this.onHandleMove); - }.bind(this); + } - this.onHandleMouseDown = function() { + onHandleMouseDown() { this.map.dragPan.disable(); this.map.setPaintProperty('circle-control-points', 'circle-color', '#a50f15'); this.map.on('mousemove', this.onHandleMove); this.map.once('mouseup', this.onHandleMouseUp); - }.bind(this); + } - this.onMouseMove = function(event) { + onMouseMove(event) { this.map.off('mousedown', this.onMouseDown); this.map.off('mousedown', this.onHandleMouseDown); @@ -167,9 +174,9 @@ function MapboxCircle(map, center, radius, options) { this.map.getCanvas().style.cursor = 'pointer'; this.map.once('mousedown', this.onMouseDown); } - }.bind(this); + } - this.addTo = function(targetMap) { + addTo(targetMap) { targetMap.on('load', () => { targetMap.addSource('circle-1', { type: 'geojson', @@ -259,12 +266,10 @@ function MapboxCircle(map, center, radius, options) { }); // Add map event listeners - targetMap.on('zoomend', this.adjustPrecision); + targetMap.on('zoomend', this.onZoomEnd); targetMap.on('mousemove', _.debounce(this.onMouseMove, 16)); }); - }; - this._updateCircle(); - this.addTo(map); + } } module.exports = exports = MapboxCircle; From 1c89292dcf52020df9038241f262487b87a13c30 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Thu, 3 Aug 2017 14:54:10 +0200 Subject: [PATCH 07/18] SPFAM-1032 Make animate() private --- lib/main.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/main.js b/lib/main.js index fa8bbb2..b88d45b 100644 --- a/lib/main.js +++ b/lib/main.js @@ -13,6 +13,7 @@ class MapboxCircle { set center(value) { this._center = value; this._updateCircle(); + this._animate(); } get center() { return this._center; @@ -20,6 +21,7 @@ class MapboxCircle { set radius(value) { this._radius = value; this._updateCircle(); + this._animate(); } get radius() { return this._radius; @@ -27,6 +29,7 @@ class MapboxCircle { set zoom(value) { this._zoom = value; this._updateCircle(); + this._animate(); } constructor(map, center, radius, options) { this.map = map; @@ -77,6 +80,11 @@ class MapboxCircle { } } + _animate() { + // map.on('sourcedata', onSourceData) + this.map.getSource('circle-1').setData(this.asGeoJSON()); + } + asGeoJSON() { let feats = this.controlPoints; feats.push(this.circle_gj); @@ -102,21 +110,14 @@ class MapboxCircle { return turfHelpers.featureCollection(this.controlPoints); } - animate() { - // map.on('sourcedata', onSourceData) - this.map.getSource('circle-1').setData(this.asGeoJSON()); - } - onZoomEnd() { // Adjust circle precision. this.zoom = this.map.getZoom(); - this.animate(); } onMove(event) { let mousePoint = turfTruncate(turfHelpers.point(this.map.unproject(event.point).toArray()), 6); this.center = mousePoint.geometry.coordinates; - this.animate(); } onMouseUp() { @@ -134,8 +135,7 @@ class MapboxCircle { onHandleMove(event) { let clickPoint = this.map.unproject(event.point).toArray(); - this.radius = turfDistance(this._center, clickPoint, 'meters'); - this.animate(); + this.radius = turfDistance(this.center, clickPoint, 'meters'); } onHandleMouseUp() { From 729eb5bd81ac244c1801d1481276386b4f02312b Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Thu, 3 Aug 2017 17:05:41 +0200 Subject: [PATCH 08/18] SPFAM-1032 Make more properties private, add overridable default options for fillColor/fillOpacity --- lib/main.js | 109 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 47 deletions(-) diff --git a/lib/main.js b/lib/main.js index b88d45b..6c3dfe8 100644 --- a/lib/main.js +++ b/lib/main.js @@ -10,6 +10,16 @@ const turfDistance = require('@turf/distance'); const turfHelpers = require('@turf/helpers'); class MapboxCircle { + set map(value) { + if (this._map === null) { + this._map = value; + } else { + throw new TypeError('MapboxCircle.map immutable once set.'); + } + } + get map() { + return this._map; + } set center(value) { this._center = value; this._updateCircle(); @@ -31,19 +41,22 @@ class MapboxCircle { this._updateCircle(); this._animate(); } - constructor(map, center, radius, options) { - this.map = map; - this._center = center; // Point geojson feature or array of [long,lat]. + constructor(center, radius, options) { + this._center = center; // Point geojson feature or array of [lng,lat]. this._radius = radius; // Radius of circle. - this.statusEl = options.statusEl; - this.properties = options.properties ? options.properties : {}; // JSON Object - property metadata for circle. - this.units = 'meters'; - this._zoom = this.map.getZoom(); + this._options = _.extend({ + strokeColor: '#000000', + fillColor: '#FB6A4A', + fillOpacity: 0.5, + properties: {}, // JSON Object - property metadata for circle. + statusEl: null + }, options); - this.steps = null; // No default steps - this.circle_gj = null; - this.controlPoints = null; + this._map = null; + this._zoom = null; + this._circle = null; + this._controlPoints = null; // Bind event handlers. this.onMouseMove = this.onMouseMove.bind(this); @@ -55,45 +68,43 @@ class MapboxCircle { this.onHandleMove = this.onHandleMove.bind(this); this.onZoomEnd = this.onZoomEnd.bind(this); - // Initialize circle object. + // Initialize circle. this._updateCircle(); - this.addTo(map); - } - - _updateSteps(zoom) { - if (!zoom || zoom <= 0.1) zoom = 0.1; - this.steps = (Math.sqrt(Math.trunc(this._radius * 0.25)) * zoom ^ 2); } _updateCircle() { - this._updateSteps(this._zoom); - this.circle_gj = turfCircle(this._center, this._radius, this.steps, this.units, this.properties); - this.controlPoints = [ - turfDestination(this._center, this._radius, 0, this.units), - turfDestination(this._center, this._radius, 90, this.units), - turfDestination(this._center, this._radius, 180, this.units), - turfDestination(this._center, this._radius, -90, this.units) + let zoom = !this._zoom || this._zoom <= 0.1 ? 0.1 : this._zoom; + let steps = Math.max((Math.sqrt(Math.trunc(this._radius * 0.25)) * zoom ^ 2), 64); + let units = 'meters'; + + this._circle = turfCircle(this._center, this._radius, steps, units, this._options.properties); + this._controlPoints = [ + turfDestination(this._center, this._radius, 0, units), + turfDestination(this._center, this._radius, 90, units), + turfDestination(this._center, this._radius, 180, units), + turfDestination(this._center, this._radius, -90, units) ]; - if (this.statusEl) { - this.statusEl.innerHTML = ('Center: ' + this._center + ' / Radius: ' + Math.trunc(this._radius) + - ' meters / Bounds: ' + this.getBounds()); + + if (this._options.statusEl) { + this._options.statusEl.innerHTML = ('Center: ' + this._center + ' / Radius: ' + Math.trunc(this._radius) + + ' meters / Bounds: ' + this.getBounds() + ' / Steps: ' + steps); } } _animate() { // map.on('sourcedata', onSourceData) - this.map.getSource('circle-1').setData(this.asGeoJSON()); + this._map.getSource('circle-1').setData(this.asGeoJSON()); } asGeoJSON() { - let feats = this.controlPoints; - feats.push(this.circle_gj); + let feats = this._controlPoints; + feats.push(this._circle); feats.push(turfHelpers.point(this._center, {'type': 'center'})); return turfHelpers.featureCollection(feats); } getBounds() { - let bboxPoly = turfTruncate(turfBboxPoly(turfBbox(this.circle_gj)), 6); + let bboxPoly = turfTruncate(turfBboxPoly(turfBbox(this._circle)), 6); return [ bboxPoly.geometry.coordinates[0][0][0], bboxPoly.geometry.coordinates[0][0][1], @@ -102,13 +113,15 @@ class MapboxCircle { ]; } + /* getBboxPoly() { - return turfTruncate(turfBboxPoly(turfBbox(this.circle_gj)), 6); + return turfTruncate(turfBboxPoly(turfBbox(this._circle)), 6); } - getControlPoints() { - return turfHelpers.featureCollection(this.controlPoints); + get_controlPoints() { + return turfHelpers.featureCollection(this._controlPoints); } + */ onZoomEnd() { // Adjust circle precision. @@ -176,20 +189,22 @@ class MapboxCircle { } } - addTo(targetMap) { - targetMap.on('load', () => { - targetMap.addSource('circle-1', { + addTo(map) { + this.map = map; + + this.map.on('load', () => { + this.map.addSource('circle-1', { type: 'geojson', data: this.asGeoJSON(), buffer: 1 }); - targetMap.addLayer({ + this.map.addLayer({ id: 'circle-line', type: 'line', source: 'circle-1', paint: { - 'line-color': '#fb6a4a', + 'line-color': this._options.strokeColor, 'line-width': { stops: [ [0, 0.1], @@ -200,18 +215,18 @@ class MapboxCircle { filter: ['==', '$type', 'Polygon'] }, 'waterway-label'); - targetMap.addLayer({ + this.map.addLayer({ id: 'circle-fill', type: 'fill', source: 'circle-1', paint: { - 'fill-color': '#fb6a4a', - 'fill-opacity': 0.5 + 'fill-color': this._options.fillColor, + 'fill-opacity': this._options.fillOpacity }, filter: ['==', '$type', 'Polygon'] }, 'waterway-label'); - targetMap.addLayer({ + this.map.addLayer({ id: 'circle-control-points', type: 'circle', source: 'circle-1', @@ -238,7 +253,7 @@ class MapboxCircle { ] }); - targetMap.addLayer({ + this.map.addLayer({ id: 'circle-center-point', type: 'circle', source: 'circle-1', @@ -265,10 +280,10 @@ class MapboxCircle { ] }); - // Add map event listeners - targetMap.on('zoomend', this.onZoomEnd); - targetMap.on('mousemove', _.debounce(this.onMouseMove, 16)); + this.map.on('zoomend', this.onZoomEnd); + this.map.on('mousemove', _.debounce(this.onMouseMove, 16)); }); + return this; } } From 13e0d62f2e7102de7ae5535152e667402f4a1e06 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 21 Aug 2017 18:19:07 +0200 Subject: [PATCH 09/18] SPFAM-1032 Update ESLint config to respect browser/commonjs built-ins --- .eslintrc.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 8c60789..427f0f4 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,12 +1,15 @@ { - "extends": "google", + "extends": ["eslint:recommended", "google"], + "env": { + "browser": true, + "commonjs": true + }, "parserOptions": { "ecmaVersion": 6, "sourceType": "module" }, "rules": { "max-len": ["error", {"code": 120, "ignoreStrings": true}], - "require-jsdoc": "off", "comma-dangle": ["error", "never"] } } \ No newline at end of file From 09715ee443b3848d5b9f45f3063c2604c371fb43 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 21 Aug 2017 18:20:48 +0200 Subject: [PATCH 10/18] SPFAM-1032 Update *MapboxCircle* to align with ESLint JSDoc requirements --- lib/main.js | 216 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 146 insertions(+), 70 deletions(-) diff --git a/lib/main.js b/lib/main.js index 6c3dfe8..d8ff079 100644 --- a/lib/main.js +++ b/lib/main.js @@ -9,100 +9,144 @@ const turfDestination = require('@turf/destination'); const turfDistance = require('@turf/distance'); const turfHelpers = require('@turf/helpers'); +/** + * A `google.maps.Circle` replacement for Mapbox GL JS, rendering a "spherical cap" on top of the world. + * @class MapboxCircle + */ class MapboxCircle { - set map(value) { - if (this._map === null) { - this._map = value; + /** @param {mapboxgl.Map} map Target map. */ + set map(map) { + if (this._map === undefined) { + this._map = map; } else { - throw new TypeError('MapboxCircle.map immutable once set.'); + throw new TypeError('MapboxCircle.map immutable.'); } } + + /** @return {mapboxgl.Map} Mapbox map. */ get map() { return this._map; } - set center(value) { - this._center = value; + + /** @param {Array} newCenter Center `[lng, lat]` coordinates. */ + set center(newCenter) { + this._center = newCenter; this._updateCircle(); this._animate(); } + + /** @return {Array} Center `[lng, lat]` coordinates. */ get center() { return this._center; } - set radius(value) { - this._radius = value; + + /** @param {Number} newRadius Meter radius. */ + set radius(newRadius) { + this._radius = newRadius; this._updateCircle(); this._animate(); } + + /** @return {Number} Circle radius. */ get radius() { return this._radius; } - set zoom(value) { - this._zoom = value; + + /** @param {Number} newZoom New zoom level. */ + set zoom(newZoom) { + this._zoom = newZoom; this._updateCircle(); this._animate(); } - constructor(center, radius, options) { - this._center = center; // Point geojson feature or array of [lng,lat]. - this._radius = radius; // Radius of circle. - this._options = _.extend({ + /** + * @param {Array} center Center `[lng, lat]` coordinates. + * @param {Number} radius Meter radius. + * @param {?Object} options + * @param {?String} [options.strokeColor='#000000'] Stroke color. + * @param {?String} [options.fillColor='#FB6A4A'] Fill color. + * @param {?Number} [options.fillOpacity=0.5] Fill opacity. + * @param {?Object} [options.properties={}] Property metadata for Mapbox GL JS circle object. + * @param {?HTMLElement} [options.statusEl] HTML element for emitting debug info. + */ + constructor(center, radius, options) { + /** @type {Array} */ this._center = center; + /** @const {Number} */ this._radius = radius; + /** @const {Object} */ this.options = _.extend({ strokeColor: '#000000', fillColor: '#FB6A4A', fillOpacity: 0.5, - properties: {}, // JSON Object - property metadata for circle. + properties: {}, statusEl: null }, options); - this._map = null; - this._zoom = null; - this._circle = null; - this._controlPoints = null; + /** @const {mapboxgl.Map} */ this._map = undefined; + /** @const {Number} */ this._zoom = undefined; + /** @const {Polygon} */ this._circle = undefined; + /** @const {Array} */ this._handles = undefined; // Bind event handlers. this.onMouseMove = this.onMouseMove.bind(this); - this.onMouseDown = this.onMouseDown.bind(this); - this.onHandleMouseDown = this.onHandleMouseDown.bind(this); - this.onMouseUp = this.onMouseUp.bind(this); - this.onHandleMouseUp = this.onHandleMouseUp.bind(this); - this.onMove = this.onMove.bind(this); - this.onHandleMove = this.onHandleMove.bind(this); + this.onCenterHandleMouseDown = this.onCenterHandleMouseDown.bind(this); + this.onRadiusHandleMouseDown = this.onRadiusHandleMouseDown.bind(this); + this.onCenterHandleMouseUp = this.onCenterHandleMouseUp.bind(this); + this.onRadiusHandleMouseUp = this.onRadiusHandleMouseUp.bind(this); + this.onCenterHandleMouseMove = this.onCenterHandleMouseMove.bind(this); + this.onRadiusHandleMouseMove = this.onRadiusHandleMouseMove.bind(this); this.onZoomEnd = this.onZoomEnd.bind(this); // Initialize circle. this._updateCircle(); } + /** + * Re-calculate/update circle polygon and handles. + * @private + */ _updateCircle() { - let zoom = !this._zoom || this._zoom <= 0.1 ? 0.1 : this._zoom; - let steps = Math.max((Math.sqrt(Math.trunc(this._radius * 0.25)) * zoom ^ 2), 64); - let units = 'meters'; + const zoom = !this._zoom || this._zoom <= 0.1 ? 0.1 : this._zoom; + const steps = Math.max((Math.sqrt(Math.trunc(this._radius * 0.25)) * zoom ^ 2), 64); + const units = 'meters'; - this._circle = turfCircle(this._center, this._radius, steps, units, this._options.properties); - this._controlPoints = [ + this._circle = turfCircle(this._center, this._radius, steps, units, this.options.properties); + this._handles = [ turfDestination(this._center, this._radius, 0, units), turfDestination(this._center, this._radius, 90, units), turfDestination(this._center, this._radius, 180, units), turfDestination(this._center, this._radius, -90, units) ]; - if (this._options.statusEl) { - this._options.statusEl.innerHTML = ('Center: ' + this._center + ' / Radius: ' + Math.trunc(this._radius) + - ' meters / Bounds: ' + this.getBounds() + ' / Steps: ' + steps); + if (this.options.statusEl) { + this.options.statusEl.innerHTML = ('Center: ' + this._center + ' / Radius: ' + Math.trunc(this._radius) + + ' meters / Bounds: ' + this.getBounds() + ' / Steps: ' + steps); } } + /** + * Refresh map with the circle's GeoJSON. + * @private + */ _animate() { // map.on('sourcedata', onSourceData) - this._map.getSource('circle-1').setData(this.asGeoJSON()); + this._map.getSource('circle-1').setData(this._asGeoJSON()); } - asGeoJSON() { - let feats = this._controlPoints; + /** + * Return GeoJSON for circle and handles. + * @private + * @return {FeatureCollection} + */ + _asGeoJSON() { + let feats = this._handles; feats.push(this._circle); feats.push(turfHelpers.point(this._center, {'type': 'center'})); return turfHelpers.featureCollection(feats); } + /** + * Get geodesic bounds for the circle. + * @return {[Number,Number,Number,Number]} + */ getBounds() { let bboxPoly = turfTruncate(turfBboxPoly(turfBbox(this._circle)), 6); return [ @@ -118,62 +162,89 @@ class MapboxCircle { return turfTruncate(turfBboxPoly(turfBbox(this._circle)), 6); } - get_controlPoints() { - return turfHelpers.featureCollection(this._controlPoints); + get_handles() { + return turfHelpers.featureCollection(this._handles); } */ + /** + * Adjust circle precision (steps used to draw the polygon). + */ onZoomEnd() { - // Adjust circle precision. this.zoom = this.map.getZoom(); } - onMove(event) { - let mousePoint = turfTruncate(turfHelpers.point(this.map.unproject(event.point).toArray()), 6); + /** + * Mouse-move listener, emulating a drag listener in conjunction with onCenterHandleMouseDown/onCenterHandleMouseUp. + * @param {MapMouseEvent} event + */ + onCenterHandleMouseMove(event) { + const mousePoint = turfTruncate(turfHelpers.point(this.map.unproject(event.point).toArray()), 6); this.center = mousePoint.geometry.coordinates; } - onMouseUp() { - this.map.setPaintProperty('circle-center-point', 'circle-color', '#fb6a4a'); + /** + * Restore center handle color, re-enable panning and remove onCenterHandleMouseMove (drag) listener. + */ + onCenterHandleMouseUp() { + this.map.setPaintProperty('circle-center-handle', 'circle-color', '#fb6a4a'); this.map.dragPan.enable(); - this.map.off('mousemove', this.onMove); + this.map.off('mousemove', this.onCenterHandleMouseMove); } - onMouseDown() { + /** + * Disable panning, set color of center handle, add onCenterHandleMouseMove (drag) listener and wait for mouse-up. + */ + onCenterHandleMouseDown() { this.map.dragPan.disable(); - this.map.setPaintProperty('circle-center-point', 'circle-color', '#a50f15'); - this.map.on('mousemove', this.onMove); - this.map.once('mouseup', this.onMouseUp); + this.map.setPaintProperty('circle-center-handle', 'circle-color', '#a50f15'); + this.map.on('mousemove', this.onCenterHandleMouseMove); + this.map.once('mouseup', this.onCenterHandleMouseUp); } - onHandleMove(event) { - let clickPoint = this.map.unproject(event.point).toArray(); - this.radius = turfDistance(this.center, clickPoint, 'meters'); + /** + * Mouse-move listener for the radius handles, emulating a drag event with + * onRadiusHandleMouseDown/onRadiusHandleMouseUp. + * @param {MapMouseEvent} event + */ + onRadiusHandleMouseMove(event) { + const mousePoint = this.map.unproject(event.point).toArray(); + this.radius = turfDistance(this.center, mousePoint, 'meters'); } - onHandleMouseUp() { - this.map.setPaintProperty('circle-control-points', 'circle-color', 'white'); + /** + * Restore color of radius handles, re-enable panning and deactivate existing mouse-move listener. + */ + onRadiusHandleMouseUp() { + this.map.setPaintProperty('circle-radius-handles', 'circle-color', 'white'); this.map.dragPan.enable(); - this.map.off('mousemove', this.onHandleMove); + this.map.off('mousemove', this.onRadiusHandleMouseMove); } - onHandleMouseDown() { + /** + * Disable panning, set color of radius handles, add mouse-move listener and wait for mouse-up (emulating drag). + */ + onRadiusHandleMouseDown() { this.map.dragPan.disable(); - this.map.setPaintProperty('circle-control-points', 'circle-color', '#a50f15'); - this.map.on('mousemove', this.onHandleMove); - this.map.once('mouseup', this.onHandleMouseUp); + this.map.setPaintProperty('circle-radius-handles', 'circle-color', '#a50f15'); + this.map.on('mousemove', this.onRadiusHandleMouseMove); + this.map.once('mouseup', this.onRadiusHandleMouseUp); } + /** + * Deactivate existing mouse-down listeners, check position and add new ones for map or handle as appropriate. + * @param {MapMouseEvent} event + */ onMouseMove(event) { - this.map.off('mousedown', this.onMouseDown); - this.map.off('mousedown', this.onHandleMouseDown); + this.map.off('mousedown', this.onCenterHandleMouseDown); + this.map.off('mousedown', this.onRadiusHandleMouseDown); let pointFeatures = this.map.queryRenderedFeatures(event.point, { - layers: ['circle-control-points'] + layers: ['circle-radius-handles'] }); let circleFeatures = this.map.queryRenderedFeatures(event.point, { - layers: ['circle-center-point'] + layers: ['circle-center-handle'] }); if ((!pointFeatures.length) && (!circleFeatures.length)) { @@ -182,20 +253,25 @@ class MapboxCircle { if (pointFeatures.length) { this.map.getCanvas().style.cursor = 'pointer'; - this.map.once('mousedown', this.onHandleMouseDown); + this.map.once('mousedown', this.onRadiusHandleMouseDown); } else if (circleFeatures.length) { this.map.getCanvas().style.cursor = 'pointer'; - this.map.once('mousedown', this.onMouseDown); + this.map.once('mousedown', this.onCenterHandleMouseDown); } } + /** + * Set map and initialize it with Mapbox GL layers for circle artifacts. + * @param {mapboxgl.Map} map + * @return {MapboxCircle} + */ addTo(map) { this.map = map; this.map.on('load', () => { this.map.addSource('circle-1', { type: 'geojson', - data: this.asGeoJSON(), + data: this._asGeoJSON(), buffer: 1 }); @@ -204,7 +280,7 @@ class MapboxCircle { type: 'line', source: 'circle-1', paint: { - 'line-color': this._options.strokeColor, + 'line-color': this.options.strokeColor, 'line-width': { stops: [ [0, 0.1], @@ -220,14 +296,14 @@ class MapboxCircle { type: 'fill', source: 'circle-1', paint: { - 'fill-color': this._options.fillColor, - 'fill-opacity': this._options.fillOpacity + 'fill-color': this.options.fillColor, + 'fill-opacity': this.options.fillOpacity }, filter: ['==', '$type', 'Polygon'] }, 'waterway-label'); this.map.addLayer({ - id: 'circle-control-points', + id: 'circle-radius-handles', type: 'circle', source: 'circle-1', paint: { @@ -254,7 +330,7 @@ class MapboxCircle { }); this.map.addLayer({ - id: 'circle-center-point', + id: 'circle-center-handle', type: 'circle', source: 'circle-1', paint: { From b6895742f589877a1ebf54927ae3ac9dc5a52354 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 21 Aug 2017 18:21:57 +0200 Subject: [PATCH 11/18] SPFAM-1032 Update example/index.js to apply circle options --- example/index.js | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/example/index.js b/example/index.js index d111faf..f7fae14 100644 --- a/example/index.js +++ b/example/index.js @@ -5,7 +5,7 @@ const MapboxCircle = require('../lib/main.js'); let mapDiv = document.body.appendChild(document.createElement('div')); mapDiv.style.position = 'absolute'; -mapDiv.style.top = '100px'; +mapDiv.style.top = '32px'; mapDiv.style.right = 0; mapDiv.style.left = 0; mapDiv.style.bottom = 0; @@ -13,8 +13,8 @@ mapDiv.style.bottom = 0; // noinspection SpellCheckingInspection mapboxgl.accessToken = 'pk.eyJ1IjoicnNiYXVtYW5uIiwiYSI6IjdiOWEzZGIyMGNkOGY3NWQ4ZTBhN2Y5ZGU2Mzg2NDY2In0.jycgv7qwF8MMIWt4cT0RaQ'; -let center = [-75.343, 39.984]; -let map = new mapboxgl.Map({ +const center = [-75.343, 39.984]; +const map = new mapboxgl.Map({ container: mapDiv, style: 'mapbox://styles/mapbox/streets-v9', center: center, @@ -24,9 +24,30 @@ let map = new mapboxgl.Map({ // MapboxCircle Setup // DOM elements -let statusEl = document.body.appendChild(document.createElement('div')); +const statusEl = document.body.appendChild(document.createElement('div')); -window.myCircle = new MapboxCircle(map, center, 300, { - properties: {foo: 'bar'}, +const editable = { + strokeColor: '#29AB87', + strokeWeight: 1, + fillColor: '#29AB87', + fillOpacity: 0.2 +}; + +/* +const nonEditable = { + strokeColor: '#000000', + strokeWeight: 0, + fillColor: '#000000', + fillOpacity: 0.2 +}; +*/ + +window.editableCircle = new MapboxCircle([-75.341, 39.986], 300, { + editable: true, + strokeColor: editable.strokeColor, + strokeWeight: editable.strokeWeight, + fillColor: editable.fillColor, + fillOpacity: editable.fillOpacity, statusEl: statusEl -}); +}).addTo(map); + From e3a438e221e31c1ce6fd495a32f09b44f5d495e8 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 21 Aug 2017 18:23:12 +0200 Subject: [PATCH 12/18] SPFAM-1032 Place *MapboxCircle* event listeners in (expected) sequential order --- lib/main.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/main.js b/lib/main.js index d8ff079..72971ba 100644 --- a/lib/main.js +++ b/lib/main.js @@ -174,6 +174,16 @@ class MapboxCircle { this.zoom = this.map.getZoom(); } + /** + * Disable panning, set color of center handle, add onCenterHandleMouseMove (drag) listener and wait for mouse-up. + */ + onCenterHandleMouseDown() { + this.map.dragPan.disable(); + this.map.setPaintProperty('circle-center-handle', 'circle-color', '#a50f15'); + this.map.on('mousemove', this.onCenterHandleMouseMove); + this.map.once('mouseup', this.onCenterHandleMouseUp); + } + /** * Mouse-move listener, emulating a drag listener in conjunction with onCenterHandleMouseDown/onCenterHandleMouseUp. * @param {MapMouseEvent} event @@ -193,13 +203,13 @@ class MapboxCircle { } /** - * Disable panning, set color of center handle, add onCenterHandleMouseMove (drag) listener and wait for mouse-up. + * Disable panning, set color of radius handles, add mouse-move listener and wait for mouse-up (emulating drag). */ - onCenterHandleMouseDown() { + onRadiusHandleMouseDown() { this.map.dragPan.disable(); - this.map.setPaintProperty('circle-center-handle', 'circle-color', '#a50f15'); - this.map.on('mousemove', this.onCenterHandleMouseMove); - this.map.once('mouseup', this.onCenterHandleMouseUp); + this.map.setPaintProperty('circle-radius-handles', 'circle-color', '#a50f15'); + this.map.on('mousemove', this.onRadiusHandleMouseMove); + this.map.once('mouseup', this.onRadiusHandleMouseUp); } /** @@ -221,16 +231,6 @@ class MapboxCircle { this.map.off('mousemove', this.onRadiusHandleMouseMove); } - /** - * Disable panning, set color of radius handles, add mouse-move listener and wait for mouse-up (emulating drag). - */ - onRadiusHandleMouseDown() { - this.map.dragPan.disable(); - this.map.setPaintProperty('circle-radius-handles', 'circle-color', '#a50f15'); - this.map.on('mousemove', this.onRadiusHandleMouseMove); - this.map.once('mouseup', this.onRadiusHandleMouseUp); - } - /** * Deactivate existing mouse-down listeners, check position and add new ones for map or handle as appropriate. * @param {MapMouseEvent} event From 20073496c870cc609add0d0fc3fd3ed5fb355fa7 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 21 Aug 2017 18:39:55 +0200 Subject: [PATCH 13/18] SPFAM-1032 Update details in package.json --- package.json | 64 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index fba6811..af10d36 100644 --- a/package.json +++ b/package.json @@ -1,42 +1,64 @@ { - "name": "Draw-Circle", - "version": "1.1.0", - "description": "Demo of drawing geofence circles with Mapbox GL JS API", - "main": "index.js", + "name": "mapbox-gl-circle", + "version": "1.2.0", + "description": "A google.maps.Circle replacement for Mapbox GL JS API", + "main": "main.js", "scripts": { - "start": "budo index.js:bundle.js --live -- --debug --delay=0", - "build": "watchify index.js -o bundle.js --debug --delay=0 -v", - "dist": "time browserify -t [ babelify --presets [ es2015 ] ] index.js | uglifyjs -c -m > bundle.min.js", - "test": "eslint ." + "start": "budo example/index.js --live -- -t brfs ", + "build": "watchify lib/main.js -o dist/mapbox-gl-circle.js --debug --delay=0 -v", + "prepublish": "mkdir -p dist && browserify --standalone MapboxCircle lib/main.js | uglifyjs -c -m > dist/mapbox-gl-circle.min.js", + "docs": "documentation build lib/main.js --format=md > API.md", + "lint": "eslint lib" }, "browserify": { "transform": [ "babelify" ] }, - "dependencies": { - "@turf/bbox": "^4.5.2", - "@turf/bbox-polygon": "^4.5.2", - "@turf/circle": "^4.5.2", - "@turf/destination": "^4.5.2", - "@turf/distance": "^4.5.2", - "@turf/helpers": "^4.5.2", - "@turf/truncate": "^4.5.2", - "lodash": "^4.17.4", - "lodash.debounce": "^4.0.8", - "mapbox-gl": "^0.38.0" + "files": [ + "lib", + "dist" + ], + "repository": { + "type": "git", + "url": "git+ssh://git@github.com:mblomdahl/mapbox-gl-circle.git" + }, + "keywords": [ + "geocoder", + "osm", + "gl" + ], + "author": "Smith Micro Software, Inc.", + "license": "ISC", + "bugs": { + "url": "https://github.com/mblomdahl/mapbox-gl-circle/issues" + }, + "homepage": "https://github.com/mblomdahl/mapbox-gl-circle#readme", + "optionalDependencies": { + "fsevents": "^1.1.2" }, "devDependencies": { "babel-preset-es2015": "^6.24.1", "babelify": "^7.3.0", + "brfs": "^1.4.3", "browserify": "^14.4.0", "budo": "^10.0.3", + "documentation": "^5.1.0", "eslint": "^4.2.0", "eslint-config-google": "^0.9.1", "uglify-js": "^3.0.24", "watchify": "^3.9.0" }, - "optionalDependencies": { - "fsevents": "^1.1.2" + "dependencies": { + "@turf/bbox": "^4.5.2", + "@turf/bbox-polygon": "^4.5.2", + "@turf/circle": "^4.5.2", + "@turf/destination": "^4.5.2", + "@turf/distance": "^4.5.2", + "@turf/helpers": "^4.5.2", + "@turf/truncate": "^4.5.2", + "lodash": "^4.17.4", + "lodash.debounce": "^4.0.8", + "mapbox-gl": "^0.38.0" } } From d9d21074d285263a95d4f41c8d02bfc7b3ad3543 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 21 Aug 2017 18:40:14 +0200 Subject: [PATCH 14/18] SPFAM-1032 Add first-draft API documentation --- API.md | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 API.md diff --git a/API.md b/API.md new file mode 100644 index 0000000..c2e2029 --- /dev/null +++ b/API.md @@ -0,0 +1,176 @@ + + +### Table of Contents + +- [MapboxCircle](#mapboxcircle) + - [map](#map) + - [map](#map-1) + - [center](#center) + - [center](#center-1) + - [radius](#radius) + - [radius](#radius-1) + - [zoom](#zoom) + - [constructor](#constructor) + - [\_center](#_center) + - [\_radius](#_radius) + - [options](#options) + - [\_map](#_map) + - [\_zoom](#_zoom) + - [\_circle](#_circle) + - [\_handles](#_handles) + - [getBounds](#getbounds) + - [onZoomEnd](#onzoomend) + - [onCenterHandleMouseDown](#oncenterhandlemousedown) + - [onCenterHandleMouseMove](#oncenterhandlemousemove) + - [onCenterHandleMouseUp](#oncenterhandlemouseup) + - [onRadiusHandleMouseDown](#onradiushandlemousedown) + - [onRadiusHandleMouseMove](#onradiushandlemousemove) + - [onRadiusHandleMouseUp](#onradiushandlemouseup) + - [onMouseMove](#onmousemove) + - [addTo](#addto) + +## MapboxCircle + +A `google.maps.Circle` replacement for Mapbox GL JS, rendering a "spherical cap" on top of the world. + +**Parameters** + +- `center` +- `radius` +- `options` + +### map + +**Parameters** + +- `map` **mapboxgl.Map** Target map. + +### map + +Returns **mapboxgl.Map** Mapbox map. + +### center + +**Parameters** + +- `newCenter` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)>** Center `[lng, lat]` coordinates. + +### center + +Returns **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)>** Center `[lng, lat]` coordinates. + +### radius + +**Parameters** + +- `newRadius` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** Meter radius. + +### radius + +Returns **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** Circle radius. + +### zoom + +**Parameters** + +- `newZoom` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** New zoom level. + +### constructor + +**Parameters** + +- `center` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)>** Center `[lng, lat]` coordinates. +- `radius` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** Meter radius. +- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?** + - `options.strokeColor` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Stroke color. (optional, default `'#000000'`) + - `options.fillColor` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Fill color. (optional, default `'#FB6A4A'`) + - `options.fillOpacity` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Fill opacity. (optional, default `0.5`) + - `options.properties` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?** Property metadata for Mapbox GL JS circle object. (optional, default `{}`) + - `options.statusEl` **[HTMLElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Element)??** HTML element for emitting debug info. + +### \_center + +### \_radius + +Type: [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) + +### options + +Type: [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) + +### \_map + +Type: mapboxgl.Map + +### \_zoom + +Type: [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) + +### \_circle + +Type: Polygon + +### \_handles + +Type: [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<Point> + +### getBounds + +Get geodesic bounds for the circle. + +Returns **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number), [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number), [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number), [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** + +### onZoomEnd + +Adjust circle precision (steps used to draw the polygon). + +### onCenterHandleMouseDown + +Disable panning, set color of center handle, add onCenterHandleMouseMove (drag) listener and wait for mouse-up. + +### onCenterHandleMouseMove + +Mouse-move listener, emulating a drag listener in conjunction with onCenterHandleMouseDown/onCenterHandleMouseUp. + +**Parameters** + +- `event` **MapMouseEvent** + +### onCenterHandleMouseUp + +Restore center handle color, re-enable panning and remove onCenterHandleMouseMove (drag) listener. + +### onRadiusHandleMouseDown + +Disable panning, set color of radius handles, add mouse-move listener and wait for mouse-up (emulating drag). + +### onRadiusHandleMouseMove + +Mouse-move listener for the radius handles, emulating a drag event with +onRadiusHandleMouseDown/onRadiusHandleMouseUp. + +**Parameters** + +- `event` **MapMouseEvent** + +### onRadiusHandleMouseUp + +Restore color of radius handles, re-enable panning and deactivate existing mouse-move listener. + +### onMouseMove + +Deactivate existing mouse-down listeners, check position and add new ones for map or handle as appropriate. + +**Parameters** + +- `event` **MapMouseEvent** + +### addTo + +Set map and initialize it with Mapbox GL layers for circle artifacts. + +**Parameters** + +- `map` **mapboxgl.Map** + +Returns **[MapboxCircle](#mapboxcircle)** From a306088181660431739a3f5397945964ba71fb47 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 21 Aug 2017 18:53:33 +0200 Subject: [PATCH 15/18] SPFAM-1032 Update CHANGELOG and Dockerfile to reflect 1.2.x restructuring --- Dockerfile | 8 ++++---- README.md | 22 ++++++++++++++++------ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Dockerfile b/Dockerfile index 72053d6..f3ae87b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,12 @@ -# To build: docker build -t draw-circle . -# To run: docker run -d -p 9966:9966 draw-circle +# To build: docker build -t mapbox-gl-circle . +# To run: docker run -i -p 9966:9966 mapbox-gl-circle # To test: open http://localhost:9966 FROM node:8-alpine -WORKDIR /opt/draw-circle +WORKDIR /opt/mapbox-gl-circle -COPY package.json index.html index.js circle.js /opt/draw-circle/ +COPY package.json example/index.js lib/main.js /opt/mapbox-gl-circle/ RUN npm install diff --git a/README.md b/README.md index 8b1afff..fbf8c9f 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,7 @@ -# Create a Native Circle in GL JS +# Spherical-Cap "Native Circle" for Mapbox GL JS -This demo uses turf.js to create a geojson circle class that works with GL JS to edit -circle features. - -The bulk of the code is in `circle.js`, the geojson circle class. Interactivity with -the circle object and map code is in `index.js`. +This project uses Turf.js to create a `google.maps.Circle` replacement as a Mapbox GL JS compatible GeoJSON object, +allowing the user to edit circle features (center/radius). ## Development @@ -31,6 +28,19 @@ the circle object and map code is in `index.js`. ## Changelog +### v. 1.2.0 + +* Removed dead code and unused methods +* Restructured library, moving ``circle.js -> lib/main.js`` and ``index.js -> example/index.js`` +* Refactored helper functions from ``example/index.js`` into *MapboxCircle* class, obsoleted *index.html* with + DOM updates in *example/index.js* +* Refactor into *MapboxCircle* into new-style ES6 class +* Made *MapboxCircle.animate()* and a bunch of properties private, added overridable defaults for fillColor/fillOpacity +* Updated ESLint config to respect browser/commonjs built-ins and added docs to *MapboxCircle* in order to + align with ESLint JSDoc requirements +* Updated project details in package.json and committed first-draft API documentation + + ### v. 1.1.0 Updated circle from Mapbox [bl.ocks.org sample](https://bl.ocks.org/ryanbaumann/d286190943d6b4eb70e65a9f76eab5a5/d3cd7cea5feed0dfddbf3705b7936ff560f668d1). From a330ab6e9df85a3b07ed64bb352b65c9345b9862 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 21 Aug 2017 19:42:57 +0200 Subject: [PATCH 16/18] SPFAM-1032 Update package.json to transpile ES6 and add *Usage* instructions --- .gitignore | 4 ++-- README.md | 10 ++++++++-- package.json | 4 ++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index bcb5a4d..9f47cb2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ .idea -node_modules -bundle.* +node_modules/ +dist/ diff --git a/README.md b/README.md index fbf8c9f..9728f16 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,13 @@ # Spherical-Cap "Native Circle" for Mapbox GL JS -This project uses Turf.js to create a `google.maps.Circle` replacement as a Mapbox GL JS compatible GeoJSON object, -allowing the user to edit circle features (center/radius). +This project uses Turf.js to create a `google.maps.Circle` replacement, as a Mapbox GL JS compatible GeoJSON object. +Allowing the developer to define a circle using center coordinates and radius (in meters). And, optionally, enabling +interactive editing via draggable center/radius handles. Just like the Google original! + + +## Usage + +See [API.md](https://github.com/mblomdahl/mapbox-gl-circle/blob/master/API.md). ## Development diff --git a/package.json b/package.json index af10d36..cd44fcc 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "main": "main.js", "scripts": { "start": "budo example/index.js --live -- -t brfs ", - "build": "watchify lib/main.js -o dist/mapbox-gl-circle.js --debug --delay=0 -v", - "prepublish": "mkdir -p dist && browserify --standalone MapboxCircle lib/main.js | uglifyjs -c -m > dist/mapbox-gl-circle.min.js", + "build": "mkdir -p dist && watchify lib/main.js -o dist/mapbox-gl-circle.js --debug --delay=0 -v", + "prepublish": "mkdir -p dist && browserify --standalone MapboxCircle -t [ babelify --presets [ es2015 ] ] lib/main.js | uglifyjs -c -m > dist/mapbox-gl-circle.min.js", "docs": "documentation build lib/main.js --format=md > API.md", "lint": "eslint lib" }, From ad141e260fb31addccb197bb90fd65ebee78f642 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 21 Aug 2017 21:13:12 +0200 Subject: [PATCH 17/18] Try out Travis CI config --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..24a8ab9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,3 @@ +language: node_js +node_js: + - "5" From fb1ccb2c908871c6db63e59370937eb9ccc05ab8 Mon Sep 17 00:00:00 2001 From: Mats Blomdahl Date: Mon, 21 Aug 2017 21:28:13 +0200 Subject: [PATCH 18/18] Add `test` to scripts in package.json for Travis CI --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index cd44fcc..3398f03 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "build": "mkdir -p dist && watchify lib/main.js -o dist/mapbox-gl-circle.js --debug --delay=0 -v", "prepublish": "mkdir -p dist && browserify --standalone MapboxCircle -t [ babelify --presets [ es2015 ] ] lib/main.js | uglifyjs -c -m > dist/mapbox-gl-circle.min.js", "docs": "documentation build lib/main.js --format=md > API.md", + "test": "eslint lib", "lint": "eslint lib" }, "browserify": {