Skip to content

Commit

Permalink
Merge pull request #100 from mapbox/permedit
Browse files Browse the repository at this point in the history
Make all features fully interactive
  • Loading branch information
kelvinabrokwa committed Nov 5, 2015
2 parents d1e0fcf + 6424824 commit e72f3f5
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 93 deletions.
43 changes: 26 additions & 17 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,30 @@
In order to use GL Draw you must instantiate the draw class like so:

```js
var Draw = mapboxgl.Draw();
var Draw = mapboxgl.Draw({ options });
map.addControl(Draw);
```

Draw only works after the map has loaded so it is wise to perform any interactions in the `load` event callback of mapbox-gl:

```js
map.on('load', function() {
Draw.set({ ... });
console.log(Draw.getAll());
...
});
```

### Options

option | values | function
--- | --- | ---
drawing | boolean | The ability to draw and delete features - default: `true`
interactive | boolean | Keep all features permanently in edit mode - default: `false`
keybindings | boolean | Keyboard shortcuts for drawing - default: true
controls | Object | drawable shapes - default `{ marker: true, line: true, shape: true, square: true }`


`mapboxgl.Draw()` returns an instance of the `Draw` class which has the following public API methods for getting and setting data:

###`.set(Object: geojsonFeature) -> String`
Expand Down Expand Up @@ -115,7 +135,7 @@ This method removes all geometries in Draw and deletes the history.

Draw fires off a number of events on draw and edit actions.

###`draw.start`
###`drawing.start`

Fired when a drawing is started. Passes an object with the the feature type to the callback (`{ featureType: <String> }`). Note that these are gl-draw feature type, one of `point`, `line`, `polygon`, `square`.

Expand All @@ -127,7 +147,7 @@ map.on('draw.start', function(e) {
});
```

###`draw.end`
###`drawing.end`

Fired when a drawing is finished. Passes an object with the feature type and the geojson geometry to the callback.

Expand All @@ -139,26 +159,15 @@ map.on('draw.end', function(e) {
});
```

###`draw.feature.update`

Fired while drawing when a new vertex is added. Passes the geometry being drawn to the callback.

Example:

```
map.on('draw.feature.update', function(e) {
alert('new draw edit!', JSON.stringify(e.geojson));
});
```

###`edit.new`

Fired while editting when a new edit is made. Passes the new geometry to the callback.
Fired while editting when a new edit is made. Passes an object with the new geometry and its drawId to the callback.

Example:

```
map.on('edit.new', function(e) {
alert('new edit!', JSON.stringify(e.geojson));
alert('new edit on', e.id, '->', JSON.stringify(e.geojson));
});
```
```
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ var Draw = mapboxgl.Draw();

map.addControl(Draw)
```
See [API.md](https://github.com/mapbox/gl-draw/blob/master/API.md) for advanced usage.

### See [API.md](https://github.com/mapbox/gl-draw/blob/master/API.md) for advanced usage.

### Developing

Expand Down
7 changes: 5 additions & 2 deletions debug/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<div id='map'></div>
<script src='https://mapbox.s3.amazonaws.com/mapbox-gl-js/master/mapbox-gl-dev.js'></script>
<script src='../dist/mapboxgl.draw.js'></script>
<script>
<script type='text/javascript'>
mapboxgl.accessToken = localStorage.accessToken;

var map = new mapboxgl.Map({
Expand All @@ -29,7 +29,10 @@
position: 'top-left'
}));

var Draw = mapboxgl.Draw();
var Draw = mapboxgl.Draw({
interactive: true,
drawing: false
});
map.addControl(Draw);
</script>
</body>
Expand Down
128 changes: 69 additions & 59 deletions src/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

import R from 'ramda';
import mapboxgl from 'mapbox-gl';
import EditStore from './edit_store';
import { DOM, createButton } from './util';

// GL Styles
import themeEdit from './theme/edit';
import themeStyle from './theme/style';
import themeDrawing from './theme/drawing';
import { DOM, createButton } from './util';

// Data store
// Data stores
import Store from './store';
import EditStore from './edit_store';

// Control handlers
import Line from './geometries/line';
Expand All @@ -23,9 +25,10 @@ export default class Draw extends mapboxgl.Control {
super();

this.options = {
drawing: true,
interactive: false,
position: 'top-left',
keybindings: true,
geoJSON: [],
controls: {
marker: true,
line: true,
Expand All @@ -34,7 +37,7 @@ export default class Draw extends mapboxgl.Control {
}
};

Object.assign(this, options);
Object.assign(this.options, options);

// event listeners
this.drag = this._drag.bind(this);
Expand All @@ -57,48 +60,50 @@ export default class Draw extends mapboxgl.Control {
this._store.setEditStore(this._editStore);
this._editStore.setDrawStore(this._store);

// Build out draw controls
if (controls.line) {
this.lineStringCtrl = createButton(this._container, {
className: controlClass + ' line',
title: `LineString tool ${this.options.keybindings && '(l)'}`,
fn: this._drawLine.bind(this),
id: 'lineDrawBtn'
}, this._controlClass);
}
if (this.options.drawing) {
// Build draw controls
if (controls.line) {
this.lineStringCtrl = createButton(this._container, {
className: controlClass + ' line',
title: `LineString tool ${this.options.keybindings && '(l)'}`,
fn: this._drawLine.bind(this),
id: 'lineDrawBtn'
}, this._controlClass);
}

if (controls.shape) {
this.polygonCtrl = createButton(this._container, {
className: `${controlClass} shape`,
title: `Polygon tool ${this.options.keybindings && '(p)'}`,
fn: this._drawPolygon.bind(this),
id: 'polygonDrawBtn'
}, this._constrolClass);
}
if (controls.shape) {
this.polygonCtrl = createButton(this._container, {
className: `${controlClass} shape`,
title: `Polygon tool ${this.options.keybindings && '(p)'}`,
fn: this._drawPolygon.bind(this),
id: 'polygonDrawBtn'
}, this._constrolClass);
}

if (controls.square) {
this.squareCtrl = createButton(this._container, {
className: `${controlClass} square`,
title: `Square tool ${this.options.keybindings && '(s)'}`,
fn: this._drawSquare.bind(this),
id: 'squareDrawBtn'
}, this._controlClass);
}
if (controls.square) {
this.squareCtrl = createButton(this._container, {
className: `${controlClass} square`,
title: `Square tool ${this.options.keybindings && '(s)'}`,
fn: this._drawSquare.bind(this),
id: 'squareDrawBtn'
}, this._controlClass);
}

if (controls.marker) {
this.markerCtrl = createButton(this._container, {
className: `${controlClass} marker`,
title: `Marker tool ${this.options.keybindings && '(m)'}`,
fn: this._drawPoint.bind(this),
id: 'pointDrawBtn'
}, this._controlClass);
}
if (controls.marker) {
this.markerCtrl = createButton(this._container, {
className: `${controlClass} marker`,
title: `Marker tool ${this.options.keybindings && '(m)'}`,
fn: this._drawPoint.bind(this),
id: 'pointDrawBtn'
}, this._controlClass);
}

if (this.options.keybindings) {
map.getContainer().addEventListener('keyup', this.onKeyUp);
}
if (this.options.keybindings) {
map.getContainer().addEventListener('keyup', this.onKeyUp);
}

map.getContainer().addEventListener('keydown', this.onKeyDown);
map.getContainer().addEventListener('keydown', this.onKeyDown);
}

this._map = map;

Expand Down Expand Up @@ -141,6 +146,7 @@ export default class Draw extends mapboxgl.Control {
}

_onKeyUp(e) {
if (!this.drawing) return;

// draw shortcuts
const LINESTRING_KEY = 76; // (l)
Expand Down Expand Up @@ -194,22 +200,25 @@ export default class Draw extends mapboxgl.Control {
this._map.featuresAt(e.point, {
radius: 10,
includeGeometry: true,
layer: [ 'gl-draw-polygon', 'gl-draw-line', 'gl-draw-point' ]
layer: [ 'gl-draw-polygon',
'gl-draw-line',
'gl-draw-point' ]
}, (err, features) => {
if (err) throw err;
if (features.length) { // clicked on a feature
if (this._drawing) return;
this._edit(features[0].properties.drawId);
} else { // clicked outside all features
this._finishEdit();
if (!this.options.interactive)
this._finishEdit();
}
});
}

_edit(drawId) {
this._map.getContainer().addEventListener('mousedown', this.initiateDrag, true);

if (!this._editStore.inProgress())
if (!this._editStore.inProgress() && this.options.drawing)
this.deleteBtn = createButton(this._container, {
className: 'mapboxgl-ctrl-draw-btn trash',
title: 'delete',
Expand Down Expand Up @@ -299,36 +308,38 @@ export default class Draw extends mapboxgl.Control {
}

_drawPolygon() {
this._finishEdit();
if (!this.options.interactive)
this._finishEdit();
var polygon = new Polygon(this._map);
polygon.startDraw();
this._drawing = true;
}

_drawLine() {
this._finishEdit();
if (!this.options.interactive)
this._finishEdit();
var line = new Line(this._map);
line.startDraw();
this._drawing = true;
}

_drawSquare() {
this._finishEdit();
if (!this.options.interactive)
this._finishEdit();
var square = new Square(this._map);
square.startDraw();
this._drawing = true;
}

_drawPoint() {
this._finishEdit();
if (!this.options.interactive)
this._finishEdit();
var point = new Point(this._map);
point.startDraw();
this._drawing = true;
}

_mapState() {
var controlClass = this._controlClass;

this._map.on('load', () => {

// in progress drawing style
Expand Down Expand Up @@ -358,22 +369,18 @@ export default class Draw extends mapboxgl.Control {
});
themeEdit.forEach(style => { this._map.addLayer(style); });

this._map.on('draw.end', e => {
this._store.set(e.geometry);
DOM.removeClass(document.querySelectorAll('.' + controlClass), 'active');
});

this._map.on('drawing.new.update', e => {
this._map.getSource('drawing').setData(e.geojson);
});

// clear the drawing layer after a drawing is done
this._map.on('drawing.end', () => {
this._map.on('drawing.end', e => {
this._map.getSource('drawing').setData({
type: 'FeatureCollection',
features: []
});
this._drawing = false;
this._edit(e.geometry.getDrawId());
[ this.lineStringCtrl,
this.polygonCtrl,
this.squareCtrl,
Expand All @@ -393,16 +400,18 @@ export default class Draw extends mapboxgl.Control {
this._map.on('mousemove', e => {
this._map.featuresAt(e.point, {
radius: 7,
layer: ['gl-edit-point', 'gl-edit-point-mid']
layer: [ 'gl-edit-point', 'gl-edit-point-mid' ],
includeGeometry: true
}, (err, features) => {
if (err) throw err;
if (!features.length)
return this._map.getContainer().classList.remove('mapboxgl-draw-move-activated');

var vertex = R.find(feat => feat.properties.meta === 'vertex')(features);
var midpoint = R.find(feat => feat.properties.meta === 'midpoint')(features);
var marker = R.find(feat => feat.geometry.type === 'Point')(features);

if (vertex || midpoint) {
if (vertex || midpoint || marker) {
this._map.getContainer().classList.add('mapboxgl-draw-move-activated');
this.hoveringOnVertex = true;
}
Expand Down Expand Up @@ -455,6 +464,7 @@ export default class Draw extends mapboxgl.Control {
return;
}
this._store.set(feature);
this._edit(feature.getDrawId());
}
return feature.drawId;
}
Expand Down
Loading

0 comments on commit e72f3f5

Please sign in to comment.