Permalink
Browse files

Add iD.behavior.drag

`iD.behavior.drag` is like `d3.behavior.drag`, with the following differences:

* The `origin` function is expected to return an [x, y] tuple rather than an
  {x, y} object.
* The events are `start`, `move`, and `end`.
  (d3/d3#563)
* The `start` event is not dispatched until the first cursor movement occurs.
  (d3/d3#368)
* The `move` event has a `loc` and `dxdy` [x, y] tuple properties rather
  than `x`, `y`, `dx`, and `dy` properties.
* The `end` event is not dispatched if no movement occurs.
* An `off` function is available that unbinds the drag's internal event handlers.
* Delegation is supported via the `delegate` function.
  • Loading branch information...
1 parent 8b889a4 commit 2c40de62befea284c23a0d59af840d087bb7fba3 @jfirebaugh jfirebaugh committed Dec 21, 2012
Showing with 182 additions and 4 deletions.
  1. +2 −0 Makefile
  2. +3 −0 index.html
  3. +1 −0 js/id/behavior.js
  4. +151 −0 js/id/behavior/drag.js
  5. +1 −1 js/id/renderer/background.js
  6. +1 −1 js/id/renderer/map.js
  7. +20 −2 js/id/util.js
  8. +3 −0 test/index.html
View
@@ -30,6 +30,8 @@ all: \
js/id/util.js \
js/id/actions.js \
js/id/actions/*.js \
+ js/id/behavior.js \
+ js/id/behavior/*.js \
js/id/modes.js \
js/id/modes/*.js \
js/id/controller/*.js \
View
@@ -62,6 +62,9 @@
<script src='js/id/actions/reverse_way.js'></script>
<script src='js/id/actions/split_way.js'></script>
+ <script src='js/id/behavior.js'></script>
+ <script src='js/id/behavior/drag.js'></script>
+
<script src='js/id/modes.js'></script>
<script src='js/id/modes/drag_features.js'></script>
<script src='js/id/modes/add_area.js'></script>
View
@@ -0,0 +1 @@
+iD.behavior = {};
View
@@ -0,0 +1,151 @@
+/*
+ `iD.behavior.drag` is like `d3.behavior.drag`, with the following differences:
+
+ * The `origin` function is expected to return an [x, y] tuple rather than an
+ {x, y} object.
+ * The events are `start`, `move`, and `end`.
+ (https://github.com/mbostock/d3/issues/563)
+ * The `start` event is not dispatched until the first cursor movement occurs.
+ (https://github.com/mbostock/d3/pull/368)
+ * The `move` event has a `loc` and `dxdy` [x, y] tuple properties rather
+ than `x`, `y`, `dx`, and `dy` properties.
+ * The `end` event is not dispatched if no movement occurs.
+ * An `off` function is available that unbinds the drag's internal event handlers.
+ * Delegation is supported via the `delegate` function.
+
+ */
+iD.behavior.drag = function () {
+ function d3_eventCancel() {
+ d3.event.stopPropagation();
+ d3.event.preventDefault();
+ }
+
+ var event = d3.dispatch("start", "move", "end"),
+ origin = null,
+ selector = '';
+
+ event.of = function(thiz, argumentz) {
+ return function(e1) {
+ try {
+ var e0 = e1.sourceEvent = d3.event;
+ e1.target = drag;
+ d3.event = e1;
+ event[e1.type].apply(thiz, argumentz);
+ } finally {
+ d3.event = e0;
+ }
+ };
+ };
+
+ function mousedown() {
+ var target = this,
+ event_ = event.of(target, arguments),
+ eventTarget = d3.event.target,
+ touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null,
+ offset,
+ origin_ = point(),
+ moved = 0;
+
+ var w = d3.select(window)
+ .on(touchId != null ? "touchmove.drag-" + touchId : "mousemove.drag", dragmove)
+ .on(touchId != null ? "touchend.drag-" + touchId : "mouseup.drag", dragend, true);
+
+ if (origin) {
+ offset = origin.apply(target, arguments);
+ offset = [ offset[0] - origin_[0], offset[1] - origin_[1] ];
+ } else {
+ offset = [ 0, 0 ];
+ }
+
+ if (touchId == null) d3_eventCancel();
+
+ function point() {
+ var p = target.parentNode;
+ return touchId != null ? d3.touches(p).filter(function (p) {
+ return p.identifier === touchId;
+ })[0] : d3.mouse(p);
+ }
+
+ function dragmove() {
+ if (!target.parentNode) return dragend();
+
+ var p = point(),
+ dx = p[0] - origin_[0],
+ dy = p[1] - origin_[1];
+
+ if (!moved) {
+ event_({
+ type: "start"
+ });
+ }
+
+ moved |= dx | dy;
+ origin_ = p;
+ d3_eventCancel();
+
+ event_({
+ type: "move",
+ loc: [p[0] + offset[0], p[1] + offset[1]],
+ dxdy: [dx, dy]
+ });
+ }
+
+ function dragend() {
+ if (moved) {
+ event_({
+ type: "end"
+ });
+
+ d3_eventCancel();
+ if (d3.event.target === eventTarget) w.on("click.drag", click, true);
+ }
+
+ w.on(touchId != null ? "touchmove.drag-" + touchId : "mousemove.drag", null)
+ .on(touchId != null ? "touchend.drag-" + touchId : "mouseup.drag", null);
+ }
+
+ function click() {
+ d3_eventCancel();
+ w.on("click.drag", null);
+ }
+ }
+
+ function drag(selection) {
+ var matchesSelector = iD.util.prefixDOMProperty('matchesSelector'),
+ delegate = mousedown;
+
+ if (selector) {
+ delegate = function() {
+ var root = this,
+ target = d3.event.target;
+ for (; target && target !== root; target = target.parentNode) {
+ if (target[matchesSelector](selector)) {
+ return mousedown.call(target, target.__data__);
+ }
+ }
+ }
+ }
+
+ selection.on("mousedown.drag" + selector, delegate)
+ .on("touchstart.drag" + selector, delegate);
+ }
+
+ drag.off = function(selection) {
+ selection.on("mousedown.drag" + selector, null)
+ .on("touchstart.drag" + selector, null);
+ };
+
+ drag.delegate = function(_) {
+ if (!arguments.length) return selector;
+ selector = _;
+ return drag;
+ };
+
+ drag.origin = function (_) {
+ if (!arguments.length) return origin;
+ origin = _;
+ return drag;
+ };
+
+ return d3.rebind(drag, event, "on");
+};
@@ -2,7 +2,7 @@ iD.Background = function() {
var tile = d3.geo.tile(),
projection,
cache = {},
- transformProp = iD.util.prefixProperty('Transform'),
+ transformProp = iD.util.prefixCSSProperty('Transform'),
source = d3.functor('');
function atZoom(t, distance) {
@@ -20,7 +20,7 @@ iD.Map = function() {
class_fill = iD.Style.styleClasses('stroke'),
class_area = iD.Style.styleClasses('area'),
class_casing = iD.Style.styleClasses('casing'),
- transformProp = iD.util.prefixProperty('Transform'),
+ transformProp = iD.util.prefixCSSProperty('Transform'),
support3d = iD.util.support3d(),
supersurface, surface, defs, tilegroup, r, g, alength;
View
@@ -56,7 +56,25 @@ iD.util.qsString = function(obj) {
}).join('&');
};
-iD.util.prefixProperty = function(property) {
+iD.util.prefixDOMProperty = function(property) {
+ var prefixes = ['webkit', 'ms', 'moz', 'o'],
+ i = -1,
+ n = prefixes.length,
+ s = document.body;
+
+ if (property in s)
+ return property;
+
+ property = property.substr(0, 1).toUpperCase() + property.substr(1);
+
+ while (++i < n)
+ if (prefixes[i] + property in s)
+ return prefixes[i] + property;
+
+ return false;
+};
+
+iD.util.prefixCSSProperty = function(property) {
var prefixes = ['webkit', 'ms', 'Moz', 'O'],
i = -1,
n = prefixes.length,
@@ -74,7 +92,7 @@ iD.util.prefixProperty = function(property) {
iD.util.support3d = function() {
// test for translate3d support. Based on https://gist.github.com/3794226 by lorenzopolidori and webinista
- var transformProp = iD.util.prefixProperty('Transform');
+ var transformProp = iD.util.prefixCSSProperty('Transform');
var el = document.createElement('div'),
has3d = false;
document.body.insertBefore(el, null);
View
@@ -61,6 +61,9 @@
<script src='../js/id/actions/remove_way_node.js'></script>
<script src='../js/id/actions/reverse_way.js'></script>
+ <script src='../js/id/behavior.js'></script>
+ <script src='../js/id/behavior/drag.js'></script>
+
<script src='../js/id/modes.js'></script>
<script src='../js/id/modes/add_area.js'></script>
<script src='../js/id/modes/add_point.js'></script>

0 comments on commit 2c40de6

Please sign in to comment.