Merge pull request #931 from systemed/streams

Start using d3 3.1.0
This commit is contained in:
Tom MacWright
2013-03-07 15:27:04 -08:00
15 changed files with 2025 additions and 436 deletions
-1
View File
@@ -46,7 +46,6 @@ data/data.js: \
js/lib/bootstrap-tooltip.js \
js/lib/d3.v3.js \
js/lib/d3.checkselect.js \
js/lib/d3.clip.js \
js/lib/d3.combobox.js \
js/lib/d3.geo.tile.js \
js/lib/d3.keybinding.js \
-1
View File
@@ -26,7 +26,6 @@
<script src='js/lib/d3.size.js'></script>
<script src='js/lib/d3.trigger.js'></script>
<script src='js/lib/d3.keybinding.js'></script>
<script src='js/lib/d3.clip.js'></script>
<script src='js/lib/d3.one.js'></script>
<script src='js/lib/d3-compat.js'></script>
<script src='js/lib/bootstrap-tooltip.js'></script>
+1 -1
View File
@@ -157,7 +157,7 @@ iD.Way.areaKeys = {
historic: {},
landuse: {},
military: {},
natural: iD.util.trueObj(['coastline']),
natural: { coastline: true },
amenity: {},
shop: {},
man_made: {},
+2 -1
View File
@@ -16,7 +16,7 @@ iD.Map = function(context) {
transformProp = iD.util.prefixCSSProperty('Transform'),
points = iD.svg.Points(roundedProjection),
vertices = iD.svg.Vertices(roundedProjection),
lines = iD.svg.Lines(roundedProjection),
lines = iD.svg.Lines(projection),
areas = iD.svg.Areas(roundedProjection),
midpoints = iD.svg.Midpoints(roundedProjection),
labels = iD.svg.Labels(roundedProjection),
@@ -261,6 +261,7 @@ iD.Map = function(context) {
dimensions = _;
surface.size(dimensions);
background.size(dimensions);
projection.clipExtent([[0, 0], dimensions]);
setCenter(center);
return redraw();
};
+44 -40
View File
@@ -13,30 +13,6 @@ iD.svg = {
};
},
resample: function(points, dx) {
var o = [];
for (var i = 0; i < points.length - 1; i++) {
var a = points[i], b = points[i + 1],
span = iD.geo.dist(a, b);
o.push(a);
// if there is space to fit one or more oneway mark
// in this segment
if (span > dx) {
// the angle from a to b
var angle = Math.atan2(b[1] - a[1], b[0] - a[0]),
to = points[i].slice();
while (iD.geo.dist(a, to) < (span - dx)) {
// a dx-length line segment in that angle
to[0] += Math.cos(angle) * dx;
to[1] += Math.sin(angle) * dx;
o.push(to.slice());
}
}
o.push(b);
}
return o;
},
LineString: function(projection, graph, dimensions, dx) {
var cache = {},
resample = this.resample;
@@ -46,27 +22,55 @@ iD.svg = {
return cache[entity.id];
}
var clip = d3.clip.cohenSutherland()
.bounds([0, 0, dimensions[0], dimensions[1]]);
var segments = [],
last,
next,
segment = [],
started = false,
d = '';
var segments = clip(graph.childNodes(entity).map(function(n) {
return projection(n.loc);
}));
projection.stream(
d3.geo.stream({
type: 'LineString',
coordinates: graph.childNodes(entity).map(function(n) {
return n.loc;
})
}, projection.stream({
lineStart: function() { last = null; started = false; },
lineEnd: function() { },
point: function(x, y) {
if (!started) d += 'M';
next = [Math.floor(x), Math.floor(y)];
if (dx && last && iD.geo.dist(last, next) > dx) {
var span = iD.geo.dist(last, next),
angle = Math.atan2(next[1] - last[1], next[0] - last[0]),
to = last.slice();
to[0] += Math.cos(angle) * dx;
to[1] += Math.sin(angle) * dx;
while (iD.geo.dist(last, to) < (span)) {
// a dx-length line segment in that angle
if (started) d += 'L';
d += Math.floor(to[0]) + ',' + Math.floor(to[1]);
started = started || true;
to[0] += Math.cos(angle) * dx;
to[1] += Math.sin(angle) * dx;
}
}
if (started) d += 'L';
d += next[0] + ',' + next[1];
started = started || true;
last = next;
}
}))
);
if (segments.length === 0) {
if (d === '') {
cache[entity.id] = null;
return cache[entity.id];
} else {
cache[entity.id] = d;
return cache[entity.id];
}
cache[entity.id] =
segments.map(function(points) {
if (dx) points = resample(points, dx);
return 'M' + points.map(function(p) {
return p[0] + ',' + p[1];
}).join('L');
}).join('');
return cache[entity.id];
};
},
+2 -2
View File
@@ -212,7 +212,7 @@ iD.svg.Labels = function(projection) {
pad = 50,
rect = new RTree.Rectangle(mouse[0] - pad, mouse[1] - pad, 2*pad, 2*pad),
labels = _.pluck(rtree.search(rect, this), 'leaf'),
containsLabel = iD.util.trueObj(labels),
containsLabel = d3.set(labels),
selection = d3.select(this);
// ensures that simply resetting opacity
@@ -230,7 +230,7 @@ iD.svg.Labels = function(projection) {
if (!labels.length) return;
selection.selectAll('.layer-label text, .layer-halo path, .layer-halo rect')
.filter(function(d) {
return containsLabel[d.id];
return containsLabel.has(d.id);
})
.style('opacity', 0)
.property('_opacity', 0);
+2 -2
View File
@@ -1,5 +1,5 @@
iD.svg.TagClasses = function() {
var keys = iD.util.trueObj([
var keys = d3.set([
'highway', 'railway', 'waterway', 'power', 'motorway', 'amenity',
'natural', 'landuse', 'building', 'oneway', 'bridge', 'boundary',
'leisure', 'construction', 'place'
@@ -18,7 +18,7 @@ iD.svg.TagClasses = function() {
var t = tags(entity);
for (var k in t) {
if (!keys[k]) continue;
if (!keys.has(k)) continue;
classes += ' tag-' + k + ' ' + 'tag-' + k + '-' + t[k];
}
-6
View File
@@ -1,11 +1,5 @@
iD.util = {};
iD.util.trueObj = function(arr) {
var o = {};
for (var i = 0, l = arr.length; i < l; i++) o[arr[i]] = true;
return o;
};
iD.util.tagText = function(entity) {
return d3.entries(entity.tags).map(function(e) {
return e.key + '=' + e.value;
-137
View File
@@ -1,137 +0,0 @@
d3.clip = {};
d3.clip.cohenSutherland = function() {
var xmin = 0, xmax = 0, ymin = 0, ymax = 0;
var x = function(d) {
return d[0];
};
var y = function(d) {
return d[1];
};
var INSIDE = 0; // 0000
var LEFT = 1; // 0001
var RIGHT = 2; // 0010
var BOTTOM = 4; // 0100
var TOP = 8; // 1000
function outCode(x, y) {
var code = INSIDE;
if (x < xmin)
code |= LEFT;
else if (x > xmax)
code |= RIGHT;
if (y < ymin)
code |= BOTTOM;
else if (y > ymax)
code |= TOP;
return code;
}
function clip(data) {
var segments = [],
points = [],
i = 0,
n = data.length,
x0, y0, x1, y1, c0, c1, _x0, _y0, _x1, _y1, _c0, _c1,
fx = d3.functor(x),
fy = d3.functor(y);
function segment() {
segments.push(points);
points = [];
}
if (n) {
x0 = +fx.call(this, data[0], 0);
y0 = +fy.call(this, data[0], 0);
c0 = outCode(x0, y0);
if (!c0) points.push([x0, y0]);
}
while (++i < n) {
x1 = +fx.call(this, data[i], i);
y1 = +fy.call(this, data[i], i);
c1 = outCode(x1, y1);
_x0 = x0;
_y0 = y0;
_x1 = x1;
_y1 = y1;
_c0 = c0;
_c1 = c1;
while (true) {
if (!(_c0 | _c1)) {
if (c0) points.push([_x0, _y0]);
points.push([_x1, _y1]);
if (c1) segment();
break;
} else if (_c0 & _c1) {
break;
} else {
var _x, _y, outcodeOut = _c0 ? _c0 : _c1;
if (outcodeOut & TOP) {
_x = _x0 + (_x1 - _x0) * (ymax - _y0) / (_y1 - _y0);
_y = ymax;
} else if (outcodeOut & BOTTOM) {
_x = _x0 + (_x1 - _x0) * (ymin - _y0) / (_y1 - _y0);
_y = ymin;
} else if (outcodeOut & RIGHT) {
_y = _y0 + (_y1 - _y0) * (xmax - _x0) / (_x1 - _x0);
_x = xmax;
} else if (outcodeOut & LEFT) {
_y = _y0 + (_y1 - _y0) * (xmin - _x0) / (_x1 - _x0);
_x = xmin;
}
if (outcodeOut == _c0) {
_x0 = _x;
_y0 = _y;
_c0 = outCode(_x0, _y0);
} else {
_x1 = _x;
_y1 = _y;
_c1 = outCode(_x1, _y1);
}
}
}
x0 = x1;
y0 = y1;
c0 = c1;
}
if (points.length) segment();
return segments;
}
clip.x = function(_) {
if (!arguments.length) return x;
x = _;
return clip;
};
clip.y = function(_) {
if (!arguments.length) return y;
y = _;
return clip;
};
clip.bounds = function(_) {
if (!arguments.length) return [xmin, ymin, xmax, ymax];
xmin = _[0];
ymin = _[1];
xmax = _[2];
ymax = _[3];
return clip;
};
return clip;
};
+1964 -185
View File
File diff suppressed because it is too large Load Diff
-2
View File
@@ -29,7 +29,6 @@
<script src='../js/lib/d3.size.js'></script>
<script src='../js/lib/d3.trigger.js'></script>
<script src='../js/lib/d3.keybinding.js'></script>
<script src='../js/lib/d3.clip.js'></script>
<script src='../js/lib/d3.one.js'></script>
<script src='../js/lib/d3-compat.js'></script>
<script src='../js/lib/bootstrap-tooltip.js'></script>
@@ -185,7 +184,6 @@
<script src="spec/spec_helpers.js"></script>
<!-- include spec files here... -->
<script src="spec/lib/d3.clip.js"></script>
<script src="spec/lib/d3.keybinding.js"></script>
<script src="spec/lib/locale.js"></script>
-41
View File
@@ -1,41 +0,0 @@
describe('d3.clip.cohenSutherland', function() {
var clip;
beforeEach(function() {
clip = d3.clip.cohenSutherland()
.bounds([0, 0, 10, 10]);
});
it('clips an empty array', function() {
expect(clip([])).to.eql([]);
});
it('clips a point inside bounds', function() {
expect(clip([[0, 0]])).to.eql([[[0, 0]]]);
});
it('clips a point outside bounds', function() {
expect(clip([[-1, -1]])).to.eql([]);
});
it('clips a single segment inside bounds', function() {
expect(clip([[0, 0], [10, 10]])).to.eql([[[0, 0], [10, 10]]]);
});
it('clips a single segment leaving bounds', function() {
expect(clip([[5, 5], [15, 15]])).to.eql([[[5, 5], [10, 10]]]);
});
it('clips a single segment entering bounds', function() {
expect(clip([[15, 15], [5, 5]])).to.eql([[[10, 10], [5, 5]]]);
});
it('clips a single segment entering and leaving bounds', function() {
expect(clip([[0, 15], [15, 0]])).to.eql([[[5, 10], [10, 5]]]);
});
it('clips multiple segments', function() {
expect(clip([[15, 15], [5, 5], [15, 15], [5, 5]])).to.
eql([[[10, 10], [5, 5], [10, 10]], [[10, 10], [5, 5]]]);
});
});
+9 -11
View File
@@ -1,12 +1,13 @@
describe("iD.svg.LineString", function () {
var projection = d3.geo.mercator();
it("returns an SVG path description for the entity's nodes", function () {
var a = iD.Node({loc: [0, 0]}),
b = iD.Node({loc: [2, 3]}),
way = iD.Way({nodes: [a.id, b.id]}),
graph = iD.Graph([a, b, way]),
projection = Object;
graph = iD.Graph([a, b, way]);
expect(iD.svg.LineString(projection, graph, [10, 10])(way)).to.equal("M0,0L2,3");
expect(iD.svg.LineString(projection, graph, [10, 10])(way)).to.equal('M480,250L482,245');
});
describe('resampling', function() {
@@ -14,27 +15,24 @@ describe("iD.svg.LineString", function () {
var a = iD.Node({loc: [0, 0]}),
b = iD.Node({loc: [10, 0]}),
way = iD.Way({nodes: [a.id, b.id]}),
graph = iD.Graph([a, b, way]),
projection = Object;
graph = iD.Graph([a, b, way]);
expect(iD.svg.LineString(projection, graph, [10, 10], 2)(way)).to.equal('M0,0L2,0L4,0L6,0L8,0L10,0');
expect(iD.svg.LineString(projection, graph, [10, 10], 2)(way)).to.equal('M480,250L482,250L484,250L486,250L488,250L490,250L492,250L493,250');
});
it("does not resmample when no steps are possible", function () {
var a = iD.Node({loc: [0, 0]}),
b = iD.Node({loc: [10, 0]}),
way = iD.Way({nodes: [a.id, b.id]}),
graph = iD.Graph([a, b, way]),
projection = Object;
graph = iD.Graph([a, b, way]);
expect(iD.svg.LineString(projection, graph, [10, 10], 20)(way)).to.equal('M0,0L10,0');
expect(iD.svg.LineString(projection, graph, [10, 10], 20)(way)).to.equal('M480,250L493,250');
});
});
it("returns null for an entity with no nodes", function () {
var way = iD.Way(),
graph = iD.Graph([way]),
projection = Object;
graph = iD.Graph([way]);
expect(iD.svg.LineString(projection, graph, [10, 10])(way)).to.be.null;
});
+1 -1
View File
@@ -1,6 +1,6 @@
describe("iD.svg.Lines", function () {
var surface,
projection = Object,
projection = d3.geo.mercator(),
filter = d3.functor(true),
dimensions = [10, 10];
-5
View File
@@ -1,9 +1,4 @@
describe('iD.Util', function() {
it('#trueObj', function() {
expect(iD.util.trueObj(['a', 'b', 'c'])).to.eql({ a: true, b: true, c: true });
expect(iD.util.trueObj([])).to.eql({});
});
it('#tagText', function() {
expect(iD.util.tagText({})).to.eql('');
expect(iD.util.tagText({tags:{foo:'bar'}})).to.eql('foo=bar');