Start using d3 3.1.0

Update d3, use streams, d3.set, clip
Use clipping, fix side effects
This commit is contained in:
Tom MacWright
2013-03-07 17:15:51 -05:00
parent e2dc3f46b2
commit 0fafa340fe
10 changed files with 2014 additions and 380 deletions
-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();
};
+43 -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,54 @@ iD.svg = {
return cache[entity.id];
}
var clip = d3.clip.cohenSutherland()
.bounds([0, 0, dimensions[0], dimensions[1]]);
var segments = [],
last,
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
-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');