Skip to content

Instantly share code, notes, and snippets.

@mbostock mbostock/.block forked from jasondavies/README.md
Last active Nov 15, 2016

Embed
What would you like to do?
Adaptive Resampling
license: gpl-3.0

D3 3.0’s projections use adaptive resampling to increase the accuracy of projected lines and polygons while still performing efficiently. On the left is no resampling, where obvious polygonal artifacts are visible due to projected lines becoming curves. Uniform resampling improves the appearance, but is inefficient because most of the resampling points are wasted, and areas of extreme distortion still exhibit artifacts. Adaptive resampling takes an idea from line simplification and resamples only where needed, producing high-quality results with low computational overhead.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
.title {
font: bold 16px "Helvetica Neue";
text-transform: capitalize;
}
.graticule {
fill: none;
stroke: #999;
stroke-width: .5px;
}
.resample {
stroke: #f00;
stroke-width: 1.5px;
fill: none;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 320,
height = 580,
velocity = .003,
time = Date.now();
var projection = d3.geo.equirectangular()
.rotate([0, 0, 89])
.translate([width / 2, height / 2])
.scale(85)
.precision(0);
var path = d3.geo.path()
.projection(projection);
var graticule = d3.geo.graticule();
d3.select("body")
.call(svg, "no resampling", [180].concat(d3.range(-90, 180, 90), [180]).map(function(x) { return [x, 0]; }), 0)
.call(svg, "uniform resampling", [180].concat(d3.range(-176, 180, 4), [180]).map(function(x) { return [x, 0]; }), 0)
.call(svg, "adaptive resampling", [[-180, 0], [-90, 0], [0, 0], [90, 0], [180, 0]], .5);
redraw();
function svg(body, title, coordinates, precision) {
var svg = body.append("svg")
.datum({
type: "LineString",
coordinates: coordinates,
precision: precision
})
.attr("width", width)
.attr("height", height);
svg.append("text")
.attr("class", "title")
.attr("x", width / 2)
.attr("y", height - 50)
.style("text-anchor", "middle")
.text(title);
var g = svg.append("g")
.attr("transform", "rotate(90 " + projection.translate() + ")");
g.append("path")
.attr("class", "resample");
g.append("path")
.datum(graticule)
.attr("class", "graticule");
}
function redraw() {
d3.selectAll("svg > g").each(function(d) {
var g = d3.select(this);
projection.precision(.3);
g.selectAll(".graticule").attr("d", path);
projection.precision(d.precision);
g.selectAll(".resample").attr("d", path);
// Override the path context to extract the resampled points.
path.context(bufferContext());
path(d);
var points = path.context().buffer();
path.context(null);
var point = g.selectAll(".point").data(points);
point.exit().remove();
point.enter().append("circle").attr("class", "point resample").attr("r", 4.5);
point.attr("transform", function(d) { return "translate(" + d + ")"; });
});
}
d3.timer(function() {
var dt = Date.now() - time;
projection.rotate([velocity * dt, 0, 89]);
redraw();
});
function bufferContext() {
var buffer = [];
return {
moveTo: function(x, y) { buffer.push([x, y]); },
lineTo: function(x, y) { buffer.push([x, y]); },
closePath: function() {},
buffer: function() { var _ = buffer; buffer = []; return _; }
};
}
d3.select(self.frameElement).style("height", height + "px");
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.