Skip to content

Commit 1b3a3b3

Browse files
committed
dispatch.on(name) returns the current listener.
Fixes d3#383. This includes a non-backwards-compatible change to d3.rebind, so as to make it easier to rebind multiple methods on subclasses.
1 parent 75ddc28 commit 1b3a3b3

17 files changed

Lines changed: 107 additions & 121 deletions

File tree

d3.js

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,22 @@ function d3_this() {
4646
d3.functor = function(v) {
4747
return typeof v === "function" ? v : function() { return v; };
4848
};
49-
// A getter-setter method that preserves the appropriate `this` context.
50-
d3.rebind = function(object, method) {
49+
// Copies a variable number of methods from source to target.
50+
d3.rebind = function(target, source) {
51+
var i = 1, n = arguments.length, method;
52+
while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]);
53+
return target;
54+
};
55+
56+
// Method is assumed to be a standard D3 getter-setter:
57+
// If passed with no arguments, gets the value.
58+
// If passed with arguments, sets the value and returns the target.
59+
function d3_rebind(target, source, method) {
5160
return function() {
52-
var x = method.apply(object, arguments);
53-
return arguments.length ? object : x;
61+
var value = method.apply(source, arguments);
62+
return arguments.length ? target : value;
5463
};
55-
};
64+
}
5665
d3.ascending = function(a, b) {
5766
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
5867
};
@@ -494,7 +503,9 @@ d3_dispatch.prototype.on = function(type, listener) {
494503
type = type.substring(0, i);
495504
}
496505

497-
this[type].on(name, listener);
506+
return arguments.length < 2
507+
? this[type].on(name)
508+
: (this[type].on(name, listener), this);
498509
};
499510

500511
function d3_dispatch_event() {
@@ -512,6 +523,9 @@ function d3_dispatch_event() {
512523
dispatch.on = function(name, listener) {
513524
var l, i;
514525

526+
// return the current listener, if any
527+
if (arguments.length < 2) return (l = listenerByName[name]) && l.on;
528+
515529
// remove the old listener, if any (with copy-on-write)
516530
if (l = listenerByName[name]) {
517531
l.on = null;
@@ -2409,11 +2423,7 @@ function d3_scale_linear(domain, range, interpolate, clamp) {
24092423
};
24102424

24112425
function d3_scale_linearRebind(scale, linear) {
2412-
scale.range = d3.rebind(scale, linear.range);
2413-
scale.rangeRound = d3.rebind(scale, linear.rangeRound);
2414-
scale.interpolate = d3.rebind(scale, linear.interpolate);
2415-
scale.clamp = d3.rebind(scale, linear.clamp);
2416-
return scale;
2426+
return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
24172427
}
24182428

24192429
function d3_scale_linearNice(dx) {
@@ -4107,18 +4117,13 @@ d3.svg.brush = function() {
41074117
|| (y && extent[0][1] === extent[1][1]);
41084118
};
41094119

4110-
brush.on = function(type, listener) {
4111-
event.on(type, listener);
4112-
return brush;
4113-
};
4114-
41154120
d3.select(window)
41164121
.on("mousemove.brush", d3_svg_brushMove)
41174122
.on("mouseup.brush", d3_svg_brushUp)
41184123
.on("keydown.brush", d3_svg_brushKeydown)
41194124
.on("keyup.brush", d3_svg_brushKeyup);
41204125

4121-
return brush;
4126+
return d3.rebind(brush, event, "on");
41224127
};
41234128

41244129
var d3_svg_brush,
@@ -4303,12 +4308,7 @@ d3.behavior.drag = function() {
43034308
d3_behavior_dragDispatch("dragstart");
43044309
}
43054310

4306-
drag.on = function(type, listener) {
4307-
event.on(type, listener);
4308-
return drag;
4309-
};
4310-
4311-
return drag;
4311+
return d3.rebind(drag, event, "on");
43124312
};
43134313

43144314
var d3_behavior_dragEvent,
@@ -4448,12 +4448,7 @@ d3.behavior.zoom = function() {
44484448
return zoom;
44494449
};
44504450

4451-
zoom.on = function(type, listener) {
4452-
event.on(type, listener);
4453-
return zoom;
4454-
};
4455-
4456-
return zoom;
4451+
return d3.rebind(zoom, event, "on");
44574452
};
44584453

44594454
var d3_behavior_zoomDiv,

d3.layout.js

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -324,11 +324,6 @@ d3.layout.force = function() {
324324
return (alpha *= .99) < .005;
325325
}
326326

327-
force.on = function(type, listener) {
328-
event.on(type, listener);
329-
return force;
330-
};
331-
332327
force.nodes = function(x) {
333328
if (!arguments.length) return nodes;
334329
nodes = x;
@@ -489,7 +484,7 @@ d3.layout.force = function() {
489484
d3_layout_forceDragForce = force;
490485
}
491486

492-
return force;
487+
return d3.rebind(force, event, "on");
493488
};
494489

495490
var d3_layout_forceDragForce,
@@ -1120,10 +1115,10 @@ d3.layout.hierarchy = function() {
11201115

11211116
// A method assignment helper for hierarchy subclasses.
11221117
function d3_layout_hierarchyRebind(object, hierarchy) {
1123-
object.sort = d3.rebind(object, hierarchy.sort);
1124-
object.children = d3.rebind(object, hierarchy.children);
1118+
d3.rebind(object, hierarchy, "sort", "children", "value");
1119+
1120+
// Add an alias for links, for convenience.
11251121
object.links = d3_layout_hierarchyLinks;
1126-
object.value = d3.rebind(object, hierarchy.value);
11271122

11281123
// If the new API is used, enabling inlining.
11291124
object.nodes = function(d) {

d3.layout.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

d3.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

d3.time.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -570,12 +570,7 @@ function d3_time_scale(linear, methods, format) {
570570
};
571571

572572
// TOOD expose d3_scale_linear_rebind?
573-
scale.range = d3.rebind(scale, linear.range);
574-
scale.rangeRound = d3.rebind(scale, linear.rangeRound);
575-
scale.interpolate = d3.rebind(scale, linear.interpolate);
576-
scale.clamp = d3.rebind(scale, linear.clamp);
577-
578-
return scale;
573+
return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
579574
}
580575

581576
// TODO expose d3_scaleExtent?

d3.time.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/behavior/drag.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,7 @@ d3.behavior.drag = function() {
2828
d3_behavior_dragDispatch("dragstart");
2929
}
3030

31-
drag.on = function(type, listener) {
32-
event.on(type, listener);
33-
return drag;
34-
};
35-
36-
return drag;
31+
return d3.rebind(drag, event, "on");
3732
};
3833

3934
var d3_behavior_dragEvent,

src/behavior/zoom.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,7 @@ d3.behavior.zoom = function() {
6969
return zoom;
7070
};
7171

72-
zoom.on = function(type, listener) {
73-
event.on(type, listener);
74-
return zoom;
75-
};
76-
77-
return zoom;
72+
return d3.rebind(zoom, event, "on");
7873
};
7974

8075
var d3_behavior_zoomDiv,

src/core/dispatch.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ d3_dispatch.prototype.on = function(type, listener) {
1818
type = type.substring(0, i);
1919
}
2020

21-
this[type].on(name, listener);
21+
return arguments.length < 2
22+
? this[type].on(name)
23+
: (this[type].on(name, listener), this);
2224
};
2325

2426
function d3_dispatch_event() {
@@ -36,6 +38,9 @@ function d3_dispatch_event() {
3638
dispatch.on = function(name, listener) {
3739
var l, i;
3840

41+
// return the current listener, if any
42+
if (arguments.length < 2) return (l = listenerByName[name]) && l.on;
43+
3944
// remove the old listener, if any (with copy-on-write)
4045
if (l = listenerByName[name]) {
4146
l.on = null;

src/core/rebind.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
1-
// A getter-setter method that preserves the appropriate `this` context.
2-
d3.rebind = function(object, method) {
1+
// Copies a variable number of methods from source to target.
2+
d3.rebind = function(target, source) {
3+
var i = 1, n = arguments.length, method;
4+
while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]);
5+
return target;
6+
};
7+
8+
// Method is assumed to be a standard D3 getter-setter:
9+
// If passed with no arguments, gets the value.
10+
// If passed with arguments, sets the value and returns the target.
11+
function d3_rebind(target, source, method) {
312
return function() {
4-
var x = method.apply(object, arguments);
5-
return arguments.length ? object : x;
13+
var value = method.apply(source, arguments);
14+
return arguments.length ? target : value;
615
};
7-
};
16+
}

0 commit comments

Comments
 (0)