Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Touch Support for Drawing Tools #5

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
246 changes: 194 additions & 52 deletions dist/leaflet.draw-src.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/leaflet.draw.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/Circle.Draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ L.Circle.Draw = L.SimpleShape.Draw.extend({
}
},

_initialLabelText: 'Click and drag to draw circle.',
_initialLabelText: (L.Browser.touch ? 'Tap' : 'Click') + ' and drag to draw circle.',

_drawShape: function (latlng) {
if (!this._shape) {
Expand Down
52 changes: 42 additions & 10 deletions src/Marker.Draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@ L.Marker.Draw = L.Handler.Draw.extend({

addHooks: function () {
L.Handler.Draw.prototype.addHooks.call(this);

//this._marker = null;
if (this._map) {
this._updateLabelText({ text: 'Click map to place marker.' });
this._updateLabelText({
text: (L.Browser.touch ? 'Tap' : 'Click') + ' map to place marker.'
});
L.DomEvent.addListener(this._container, 'mousemove', this._onMouseMove, this);
if (L.Browser.touch) {
L.DomEvent.addListener(this._container, 'touchmove', this._onMouseMove, this);
L.DomEvent.addListener(this._container, 'touchend', this._onClick, this);
}
}
},

Expand All @@ -18,19 +24,34 @@ L.Marker.Draw = L.Handler.Draw.extend({
if (this._map) {
if (this._marker) {
L.DomEvent
.removeListener(this._marker, 'click', this._onClick)
.removeListener(this._map, 'click', this._onClick);
.removeListener(this._marker, 'click', this._onClick)
.removeListener(this._map, 'click', this._onClick);

if (L.Browser.touch) {
L.DomEvent
.removeListener(this._marker, 'touchend', this._onClick);
}
this._map.removeLayer(this._marker);
delete this._marker;
}

L.DomEvent.removeListener(this._container, 'mousemove', this._onMouseMove);
if (L.Browser.touch) {
L.DomEvent
.removeListener(this._container, 'touchmove', this._onMouseMove)
.removeListener(this._container, 'touchend', this._onClick);
}
}
},

_onMouseMove: function (e) {
var newPos = this._map.mouseEventToLayerPoint(e),
latlng = this._map.mouseEventToLatLng(e);
var newPos = this._map.mouseEventToLayerPoint(e.touches ? e.touches[0] : e),
latlng = this._map.mouseEventToLatLng(e.touches ? e.touches[0] : e);

if (e.touches) {
// This is necessary to stop the map from panning
L.DomEvent.stopPropagation(e);
}

this._updateLabelPosition(newPos);

Expand All @@ -39,19 +60,30 @@ L.Marker.Draw = L.Handler.Draw.extend({
this._map.addLayer(this._marker);
// Bind to both marker and map to make sure we get the click event.
L.DomEvent
.addListener(this._marker, 'click', this._onClick, this)
.addListener(this._map, 'click', this._onClick, this);
.addListener(this._marker, 'click', this._onClick, this)
.addListener(this._map, 'click', this._onClick, this);

if (L.Browser.touch) {
L.DomEvent
.addListener(this._marker, 'touchend', this._onClick, this);
}
}
else {
this._marker.setLatLng(latlng);
}
},

_onClick: function (e) {
if (e.touches) {
// This might be a bit greedy
L.DomEvent.stopPropagation(e);
}
this._map.fire(
'draw:marker-created',
{ marker: new L.Marker(this._marker.getLatLng(), this.options.icon) }
);
{
marker: new L.Marker(this._marker ? this._marker.getLatLng() : this._map.mouseEventToLatLng(e.changedTouches ? e.changedTouches[0] : e), this.options.icon)
}
);
this.disable();
}
});
29 changes: 25 additions & 4 deletions src/Polygon.Draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,51 @@ L.Polygon.Draw = L.Polyline.Draw.extend({
// The first marker shold have a click handler to close the polygon
if (this._markers.length === 1) {
this._markers[0].on('click', this._finishShape, this);
if (L.Browser.touch) {
this._markers[0].on('touchend', this._finishShape, this);
}
}
},

_clickedFinishMarker : function (latlng) {
if (this._markers.length > 1) {
var m = this._markers[0];
// This could be improved by considering width and height of the icon separately, instead of just using the bigger one
var pointA = this._map.latLngToContainerPoint(latlng);
var pointB = this._map.latLngToContainerPoint(m.getLatLng());
var length = Math.floor(Math.sqrt(Math.pow((pointB.x - pointA.x), 2) + Math.pow((pointB.y - pointA.y), 2)));
var size = m.options.icon.options.iconSize;
if (length < Math.max(size.x, size.y) * this.options.touchtarget) {
return true;
}
}
return false;
},

_getLabelText: function () {
var text;
if (this._markers.length === 0) {
text = 'Click to start drawing shape.';
text = (L.Browser.touch ? 'Tap' : 'Click') + ' to start drawing shape.';
} else if (this._markers.length < 3) {
text = 'Click to continue drawing shape.';
text = (L.Browser.touch ? 'Tap' : 'Click') + ' to continue drawing shape.';
} else {
text = 'Click first point to close this shape.';
text = (L.Browser.touch ? 'Tap' : 'Click') + ' first point to close this shape.';
}
return {
text: text
};
},

_vertexAdded: function (latlng) {
//calc area here
//calc area here
},

_cleanUpShape: function () {
if (this._markers.length > 0) {
this._markers[0].off('click', this._finishShape);
if (L.Browser.touch) {
this._markers[0].off('touchend', this._finishShape);
}
}
}
});
101 changes: 78 additions & 23 deletions src/Polyline.Draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ L.Polyline.Draw = L.Handler.Draw.extend({

options: {
icon: new L.DivIcon({
iconSize: new L.Point(8, 8),
iconSize: L.Browser.touch ? new L.Point(30, 30) : new L.Point(10, 10),
className: 'leaflet-div-icon leaflet-editing-icon'
}),
guidelineDistance: 20,
Expand All @@ -14,7 +14,8 @@ L.Polyline.Draw = L.Handler.Draw.extend({
opacity: 0.5,
fill: false,
clickable: true
}
},
touchtarget : 1.5 // iconSize multiplied by touchtarget = final target size
},

addHooks: function () {
Expand All @@ -33,8 +34,15 @@ L.Polyline.Draw = L.Handler.Draw.extend({
this._updateLabelText(this._getLabelText());

L.DomEvent
.addListener(this._container, 'mousemove', this._onMouseMove, this)
.addListener(this._container, 'click', this._onClick, this);
.addListener(this._container, 'mousemove', this._onMouseMove, this)
.addListener(this._container, 'click', this._onClick, this);

if (L.Browser.touch) {
L.DomEvent
.addListener(this._container, 'touchstart', this._onMouseMove, this)
.addListener(this._container, 'touchmove', this._onMouseMove, this)
.addListener(this._container, 'touchend', this._onClick, this);
}
}
},

Expand All @@ -56,22 +64,34 @@ L.Polyline.Draw = L.Handler.Draw.extend({
this._container.style.cursor = '';

L.DomEvent
.removeListener(this._container, 'mousemove', this._onMouseMove)
.removeListener(this._container, 'click', this._onClick);
.removeListener(this._container, 'mousemove', this._onMouseMove)
.removeListener(this._container, 'click', this._onClick);

if (L.Browser.touch) {
L.DomEvent
.removeListener(this._container, 'touchmove', this._onMouseMove)
.removeListener(this._container, 'touchend', this._onClick);
}
},

_finishShape: function () {
this._map.fire(
'draw:poly-created',
{ poly: new this.Poly(this._poly.getLatLngs(), this.options.shapeOptions) }
);
{
poly: new this.Poly(this._poly.getLatLngs(), this.options.shapeOptions)
}
);
this.disable();
},

_onMouseMove: function (e) {
var newPos = this._map.mouseEventToLayerPoint(e),
latlng = this._map.mouseEventToLatLng(e),
markerCount = this._markers.length;
var newPos = this._map.mouseEventToLayerPoint(e.touches ? e.touches[0] : e),
latlng = this._map.mouseEventToLatLng(e.touches ? e.touches[0] : e),
markerCount = this._markers.length;

if (e.touches) {
L.DomEvent.stopPropagation(e);
}

// update the label
this._updateLabelPosition(newPos);
Expand All @@ -83,14 +103,25 @@ L.Polyline.Draw = L.Handler.Draw.extend({
this._drawGuide(
this._map.latLngToLayerPoint(this._markers[markerCount - 1].getLatLng()),
newPos
);
);
}

L.DomEvent.preventDefault(e);
},

_onClick: function (e) {
var latlng = this._map.mouseEventToLatLng(e);
var latlng = this._map.mouseEventToLatLng(e.changedTouches ? e.changedTouches[0] : e);

if (e.touches) {
this._clearGuides();
// The touchend on the container seems to have preference over the touchend on the marker, so we manually check position of the last marker.
// This also gives us the opportunity to use a touch target a little bigger than the visual shape, which makes it easier to hit the marker with clumsy fingers
if (this._clickedFinishMarker(latlng)) {
this._finishShape();
return true;
}

}

this._markers.push(this._createMarker(latlng));

Expand All @@ -104,16 +135,37 @@ L.Polyline.Draw = L.Handler.Draw.extend({

this._vertexAdded(latlng);
},

_clickedFinishMarker : function (latlng) {
if (this._markers.length > 1) {
var m = this._markers[this._markers.length - 1];
// This could be improved by considering width and height of the icon separately, instead of just using the bigger one
var pointA = this._map.latLngToContainerPoint(latlng);
var pointB = this._map.latLngToContainerPoint(m.getLatLng());
var length = Math.floor(Math.sqrt(Math.pow((pointB.x - pointA.x), 2) + Math.pow((pointB.y - pointA.y), 2)));
var size = m.options.icon.options.iconSize;
if (length < Math.max(size.x, size.y) * this.options.touchtarget) {
return true;
}
}
return false;
},

_updateMarkerHandler: function () {
// The last marker shold have a click handler to close the polyline
if (this._markers.length > 1) {
this._markers[this._markers.length - 1].on('click', this._finishShape, this);
if (L.Browser.touch) {
this._markers[this._markers.length - 1].on('touchend', this._finishShape, this);
}
}

// Remove the old marker click handler (as only the last point should close the polyline)
if (this._markers.length > 2) {
this._markers[this._markers.length - 2].off('click', this._finishShape);
if (L.Browser.touch) {
this._markers[this._markers.length - 2].off('touchend', this._finishShape);
}
}
},

Expand All @@ -129,10 +181,10 @@ L.Polyline.Draw = L.Handler.Draw.extend({

_drawGuide: function (pointA, pointB) {
var length = Math.floor(Math.sqrt(Math.pow((pointB.x - pointA.x), 2) + Math.pow((pointB.y - pointA.y), 2))),
i,
fraction,
dashPoint,
dash;
i,
fraction,
dashPoint,
dash;

//create the guides container if we haven't yet (TODO: probaly shouldn't do this every time the user starts to draw?)
if (!this._guidesContainer) {
Expand Down Expand Up @@ -160,12 +212,12 @@ L.Polyline.Draw = L.Handler.Draw.extend({

_getLabelText: function (currentLatLng) {
var labelText,
distance,
distanceStr;
distance,
distanceStr;

if (this._markers.length === 0) {
labelText = {
text: 'Click to start drawing line.'
text: (L.Browser.touch ? 'Tap' : 'Click') + ' to start drawing line.'
};
} else {
// calculate the distance from the last fixed point to the mouse position
Expand All @@ -175,12 +227,12 @@ L.Polyline.Draw = L.Handler.Draw.extend({

if (this._markers.length === 1) {
labelText = {
text: 'Click to continue drawing line.',
text: (L.Browser.touch ? 'Tap' : 'Click') + ' to continue drawing line.',
subtext: distanceStr
};
} else {
labelText = {
text: 'Click last point to finish line.',
text: (L.Browser.touch ? 'Tap' : 'Click') + ' last point to finish line.',
subtext: distanceStr
};
}
Expand All @@ -194,13 +246,16 @@ L.Polyline.Draw = L.Handler.Draw.extend({
}
else {
this._measurementRunningTotal +=
latlng.distanceTo(this._markers[this._markers.length - 2].getLatLng());
latlng.distanceTo(this._markers[this._markers.length - 2].getLatLng());
}
},

_cleanUpShape: function () {
if (this._markers.length > 0) {
this._markers[this._markers.length - 1].off('click', this._finishShape);
if (L.Browser.touch) {
this._markers[this._markers.length - 1].off('touchend', this._finishShape);
}
}
},

Expand Down
2 changes: 1 addition & 1 deletion src/Rectangle.Draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ L.Rectangle.Draw = L.SimpleShape.Draw.extend({
}
},

_initialLabelText: 'Click and drag to draw rectangle.',
_initialLabelText: (L.Browser.touch ? 'Tap' : 'Click') + ' and drag to draw rectangle.',

_drawShape: function (latlng) {
if (!this._shape) {
Expand Down
Loading