Skip to content

Commit 8d9d2b7

Browse files
committed
Replace d3.geo.identity with d3.geo.clipExtent.
The only function of d3.geo.identity was to allow viewport clipping on the identity projection, so it seems clearer to replace d3.geo.identity with a geometry transform that is explicitly tailored to viewport clipping.
1 parent 1e0faba commit 8d9d2b7

9 files changed

Lines changed: 188 additions & 118 deletions

File tree

d3.js

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2986,8 +2986,25 @@ d3 = function() {
29862986
return d3_geo_pointInPolygon(point, polygon);
29872987
}
29882988
}
2989-
var d3_geo_clipViewMAX = 1e9;
2990-
function d3_geo_clipView(x0, y0, x1, y1) {
2989+
var d3_geo_clipExtentMAX = 1e9;
2990+
d3.geo.clipExtent = function() {
2991+
var x0, y0, x1, y1, stream, clip, clipExtent = {
2992+
stream: function(output) {
2993+
if (stream) stream.valid = false;
2994+
stream = clip(output);
2995+
stream.valid = true;
2996+
return stream;
2997+
},
2998+
extent: function(_) {
2999+
if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];
3000+
clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]);
3001+
if (stream) stream.valid = false, stream = null;
3002+
return clipExtent;
3003+
}
3004+
};
3005+
return clipExtent.extent([ [ 0, 0 ], [ 960, 500 ] ]);
3006+
};
3007+
function d3_geo_clipExtent(x0, y0, x1, y1) {
29913008
return function(listener) {
29923009
var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), segments, polygon, ring;
29933010
var clip = {
@@ -3069,8 +3086,8 @@ d3 = function() {
30693086
if (v_) listener.lineEnd();
30703087
}
30713088
function linePoint(x, y) {
3072-
x = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, x));
3073-
y = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, y));
3089+
x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x));
3090+
y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y));
30743091
var v = visible(x, y);
30753092
if (polygon) ring.push([ x, y ]);
30763093
if (first) {
@@ -3113,7 +3130,7 @@ d3 = function() {
31133130
function clipLine(a, b) {
31143131
var dx = b[0] - a[0], dy = b[1] - a[1], t = [ 0, 1 ];
31153132
if (Math.abs(dx) < ε && Math.abs(dy) < ε) return x0 <= a[0] && a[0] <= x1 && y0 <= a[1] && a[1] <= y1;
3116-
if (d3_geo_clipViewT(x0 - a[0], dx, t) && d3_geo_clipViewT(a[0] - x1, -dx, t) && d3_geo_clipViewT(y0 - a[1], dy, t) && d3_geo_clipViewT(a[1] - y1, -dy, t)) {
3133+
if (d3_geo_clipExtentT(x0 - a[0], dx, t) && d3_geo_clipExtentT(a[0] - x1, -dx, t) && d3_geo_clipExtentT(y0 - a[1], dy, t) && d3_geo_clipExtentT(a[1] - y1, -dy, t)) {
31173134
if (t[1] < 1) {
31183135
b[0] = a[0] + t[1] * dx;
31193136
b[1] = a[1] + t[1] * dy;
@@ -3127,7 +3144,7 @@ d3 = function() {
31273144
return false;
31283145
}
31293146
}
3130-
function d3_geo_clipViewT(num, denominator, t) {
3147+
function d3_geo_clipExtentT(num, denominator, t) {
31313148
if (Math.abs(denominator) < ε) return num <= 0;
31323149
var u = num / denominator;
31333150
if (denominator > 0) {
@@ -3631,7 +3648,7 @@ d3 = function() {
36313648
projection.clipExtent = function(_) {
36323649
if (!arguments.length) return clipExtent;
36333650
clipExtent = _;
3634-
postclip = _ ? d3_geo_clipView(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity;
3651+
postclip = _ ? d3_geo_clipExtent(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity;
36353652
return invalidate();
36363653
};
36373654
projection.scale = function(_) {
@@ -4018,27 +4035,6 @@ d3 = function() {
40184035
(d3.geo.gnomonic = function() {
40194036
return d3_geo_projection(d3_geo_gnomonic);
40204037
}).raw = d3_geo_gnomonic;
4021-
d3.geo.identity = function() {
4022-
var clipExtent = null, clip = d3_identity, stream;
4023-
function identity(x) {
4024-
return x;
4025-
}
4026-
identity.invert = d3_identity;
4027-
identity.stream = function(output) {
4028-
if (stream) stream.valid = false;
4029-
stream = clip(output);
4030-
stream.valid = true;
4031-
return stream;
4032-
};
4033-
identity.clipExtent = function(_) {
4034-
if (!arguments.length) return clipExtent;
4035-
clipExtent = _;
4036-
clip = _ ? d3_geo_clipView(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity;
4037-
if (stream) stream.valid = false, stream = null;
4038-
return identity;
4039-
};
4040-
return identity;
4041-
};
40424038
function d3_geo_mercator(λ, φ) {
40434039
return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ];
40444040
}

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.
Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,33 @@
11
import "../arrays/merge";
22
import "../math/trigonometry";
3+
import "geo";
34
import "clip";
45
import "clip-polygon";
56

6-
var d3_geo_clipViewMAX = 1e9;
7+
var d3_geo_clipExtentMAX = 1e9;
8+
9+
d3.geo.clipExtent = function() {
10+
var x0, y0, x1, y1,
11+
stream,
12+
clip,
13+
clipExtent = {
14+
stream: function(output) {
15+
if (stream) stream.valid = false;
16+
stream = clip(output);
17+
stream.valid = true; // allow caching by d3.geo.path
18+
return stream;
19+
},
20+
extent: function(_) {
21+
if (!arguments.length) return [[x0, y0], [x1, y1]];
22+
clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]);
23+
if (stream) stream.valid = false, stream = null;
24+
return clipExtent;
25+
}
26+
};
27+
return clipExtent.extent([[0, 0], [960, 500]]);
28+
};
729

8-
function d3_geo_clipView(x0, y0, x1, y1) {
30+
function d3_geo_clipExtent(x0, y0, x1, y1) {
931
return function(listener) {
1032
var listener_ = listener,
1133
bufferListener = d3_geo_clipBufferListener(),
@@ -113,8 +135,8 @@ function d3_geo_clipView(x0, y0, x1, y1) {
113135
}
114136

115137
function linePoint(x, y) {
116-
x = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, x));
117-
y = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, y));
138+
x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x));
139+
y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y));
118140
var v = visible(x, y);
119141
if (polygon) ring.push([x, y]);
120142
if (first) {
@@ -177,10 +199,10 @@ function d3_geo_clipView(x0, y0, x1, y1) {
177199

178200
if (Math.abs(dx) < ε && Math.abs(dy) < ε) return x0 <= a[0] && a[0] <= x1 && y0 <= a[1] && a[1] <= y1;
179201

180-
if (d3_geo_clipViewT(x0 - a[0], dx, t) &&
181-
d3_geo_clipViewT(a[0] - x1, -dx, t) &&
182-
d3_geo_clipViewT(y0 - a[1], dy, t) &&
183-
d3_geo_clipViewT(a[1] - y1, -dy, t)) {
202+
if (d3_geo_clipExtentT(x0 - a[0], dx, t) &&
203+
d3_geo_clipExtentT(a[0] - x1, -dx, t) &&
204+
d3_geo_clipExtentT(y0 - a[1], dy, t) &&
205+
d3_geo_clipExtentT(a[1] - y1, -dy, t)) {
184206
if (t[1] < 1) {
185207
b[0] = a[0] + t[1] * dx;
186208
b[1] = a[1] + t[1] * dy;
@@ -196,7 +218,7 @@ function d3_geo_clipView(x0, y0, x1, y1) {
196218
}
197219
}
198220

199-
function d3_geo_clipViewT(num, denominator, t) {
221+
function d3_geo_clipExtentT(num, denominator, t) {
200222
if (Math.abs(denominator) < ε) return num <= 0;
201223

202224
var u = num / denominator;

src/geo/identity.js

Lines changed: 0 additions & 28 deletions
This file was deleted.

src/geo/index.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import "conic-equal-area";
2727
import "conic-equidistant";
2828
import "equirectangular";
2929
import "gnomonic";
30-
import "identity";
3130
import "mercator";
3231
import "orthographic";
3332
import "stereographic";

src/geo/projection.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import "../core/rebind";
33
import "../math/trigonometry";
44
import "clip-antimeridian";
55
import "clip-circle";
6-
import "clip-view";
6+
import "clip-extent";
77
import "compose";
88
import "geo";
99
import "path";
@@ -61,7 +61,7 @@ function d3_geo_projectionMutator(projectAt) {
6161
projection.clipExtent = function(_) {
6262
if (!arguments.length) return clipExtent;
6363
clipExtent = _;
64-
postclip = _ ? d3_geo_clipView(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity;
64+
postclip = _ ? d3_geo_clipExtent(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity;
6565
return invalidate();
6666
};
6767

test/geo/clip-extent-test.js

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
var vows = require("vows"),
2+
load = require("../load"),
3+
assert = require("../assert");
4+
5+
var suite = vows.describe("d3.geo.clipExtent");
6+
7+
suite.addBatch({
8+
"clipExtent": {
9+
topic: load("geo/clip-extent"),
10+
11+
"extent": {
12+
"defaults to [[0, 0], [960, 500]]": function(d3) {
13+
var clip = d3.geo.clipExtent();
14+
assert.deepEqual(clip.extent(), [[0, 0], [960, 500]]);
15+
},
16+
"coerces input values to numbers": function(d3) {
17+
var clip = d3.geo.clipExtent().extent([["1", "2"], ["3", "4"]]),
18+
extent = clip.extent();
19+
assert.strictEqual(extent[0][0], 1);
20+
assert.strictEqual(extent[0][1], 2);
21+
assert.strictEqual(extent[1][0], 3);
22+
assert.strictEqual(extent[1][1], 4);
23+
},
24+
"with no arguments, returns the current extent": function(d3) {
25+
var clip = d3.geo.clipExtent();
26+
assert.deepEqual(clip.extent(), [[0, 0], [960, 500]]);
27+
clip.extent([[1, 2], [3, 4]]);
28+
assert.deepEqual(clip.extent(), [[1, 2], [3, 4]]);
29+
},
30+
"with an argument, sets the current extent and returns this": function(d3) {
31+
var clip = d3.geo.clipExtent();
32+
assert.strictEqual(clip.extent([[1, 2], [3, 4]]), clip);
33+
}
34+
},
35+
36+
"stream": {
37+
"returns a stream that clips to the current extent": function(d3) {
38+
var clip = d3.geo.clipExtent().extent([[100, 200], [300, 400]]),
39+
stream = clip.stream(testContext);
40+
stream.lineStart();
41+
stream.point(0, 0);
42+
stream.point(500, 500);
43+
stream.lineEnd();
44+
assert.deepEqual(testContext.buffer(), [
45+
{type: "lineStart"},
46+
{type: "point", x: 200, y: 200},
47+
{type: "point", x: 300, y: 300},
48+
{type: "lineEnd"}
49+
]);
50+
},
51+
"can clip points": function(d3) {
52+
var clip = d3.geo.clipExtent(),
53+
stream = clip.stream(testContext);
54+
stream.point(-100, -100);
55+
stream.point(0, 0);
56+
stream.point(480, 250);
57+
stream.point(960, 500);
58+
stream.point(1060, 6000);
59+
assert.deepEqual(testContext.buffer(), [
60+
{type: "point", x: 0, y: 0},
61+
{type: "point", x: 480, y: 250},
62+
{type: "point", x: 960, y: 500}
63+
]);
64+
},
65+
"can clip lines": function(d3) {
66+
var clip = d3.geo.clipExtent(),
67+
stream = clip.stream(testContext);
68+
stream.lineStart();
69+
stream.point(-100, -100);
70+
stream.point(1060, 600);
71+
stream.lineEnd();
72+
assert.deepEqual(testContext.buffer(), [
73+
{type: "lineStart"},
74+
{type: "point", x: 66, y: 0},
75+
{type: "point", x: 894, y: 500},
76+
{type: "lineEnd"}
77+
]);
78+
},
79+
"can clip polygons": function(d3) {
80+
var clip = d3.geo.clipExtent(),
81+
stream = clip.stream(testContext);
82+
stream.polygonStart();
83+
stream.lineStart();
84+
stream.point(-100, -100);
85+
stream.point(1060, -100);
86+
stream.point(1060, 600);
87+
stream.point(-100, 600);
88+
stream.lineEnd();
89+
stream.polygonEnd();
90+
assert.deepEqual(testContext.buffer(), [
91+
{type: "polygonStart"},
92+
{type: "lineStart"},
93+
{type: "point", x: 0, y: 0},
94+
{type: "point", x: 960, y: 0},
95+
{type: "point", x: 960, y: 500},
96+
{type: "point", x: 0, y: 500},
97+
{type: "lineEnd"},
98+
{type: "polygonEnd"}
99+
]);
100+
},
101+
"the returned stream is cacheable": function(d3) {
102+
var clip = d3.geo.clipExtent().extent([[100, 200], [300, 400]]),
103+
stream = clip.stream(testContext);
104+
assert.isTrue(stream.valid);
105+
},
106+
"the returned stream is invalidated when the extent changes": function(d3) {
107+
var clip = d3.geo.clipExtent().extent([[100, 200], [300, 400]]),
108+
stream = clip.stream(testContext);
109+
assert.isTrue(stream.valid);
110+
clip.extent([[0, 0], [960, 500]]);
111+
assert.isFalse(stream.valid);
112+
}
113+
}
114+
}
115+
});
116+
117+
suite.export(module);
118+
119+
var testBuffer = [];
120+
121+
var testContext = {
122+
point: function(x, y) { testBuffer.push({type: "point", x: Math.round(x), y: Math.round(y)}); },
123+
lineStart: function() { testBuffer.push({type: "lineStart"}); },
124+
lineEnd: function() { testBuffer.push({type: "lineEnd"}); },
125+
polygonStart: function() { testBuffer.push({type: "polygonStart"}); },
126+
polygonEnd: function() { testBuffer.push({type: "polygonEnd"}); },
127+
sphere: function() { testBuffer.push({type: "sphere"}); },
128+
buffer: function() { var result = testBuffer; testBuffer = []; return result; }
129+
};

test/geo/clip-view-mock.js

Lines changed: 0 additions & 4 deletions
This file was deleted.

test/geo/clip-view-test.js

Lines changed: 0 additions & 44 deletions
This file was deleted.

0 commit comments

Comments
 (0)