Skip to content

Instantly share code, notes, and snippets.

@tmcw
Created October 26, 2012 17:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tmcw/3960059 to your computer and use it in GitHub Desktop.
Save tmcw/3960059 to your computer and use it in GitHub Desktop.
Preliminary Geo Drawing in d3
var iD = {};
iD.Draw = function() {
var event = d3.dispatch(draw, 'draw'),
x0, x1,
y0, y1;
var feature = {
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: []
}
};
function draw() {
this
.on('mousemove.draw', mousemove)
.on('click.draw', mousedown);
}
// move an elastic band that shows where the next point
// will be
function mousemove(e) {
var target = this;
function mouse() {
var touches = d3.event.changedTouches;
return touches ? d3.touches(target, touches)[0] : d3.mouse(target);
}
var ll = projection.invert(mouse());
var elastic = {
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: []
}
};
if (!feature.geometry.coordinates.length) {
feature.geometry.coordinates[0] = ll;
event.draw(feature);
feature.geometry.coordinates = [];
} else {
var l = feature.geometry.coordinates.length - 1;
elastic.geometry.coordinates = [
feature.geometry.coordinates[l],
ll];
event.draw(feature, elastic);
}
}
// add a point
function mousedown(e) {
var target = this;
function mouse() {
var touches = d3.event.changedTouches;
return touches ? d3.touches(target, touches)[0] : d3.mouse(target);
}
var ll = projection.invert(mouse());
feature.geometry.coordinates.push(ll);
event.draw(feature);
d3.event.stopPropagation();
}
return d3.rebind(draw, event, "on");
};
<!DOCTYPE html>
<style>
path {
fill: none;
}
path.boundary {
stroke: #2CA25F;
stroke-width: 4;
pointer-events:none;
}
path.elastic {
stroke: #CF50C5;
stroke-width: 4;
pointer-events:none;
}
#axes {
stroke: #BDBDBD;
stroke-width: 0.5;
}
</style>
<body>
<script src="http://d3js.org/d3.v2.js"></script>
<script src="draw.js"></script>
<script>
var width = 960,
height = 500,
projection = d3.geo.mercator().scale(1024).translate([512, 256]),
path = d3.geo.path().projection(projection);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.call(d3.behavior.zoom()
.translate(projection.translate())
.scale(projection.scale())
.on("zoom", redraw));
var axes = svg.append("g").attr("id", "axes"),
xAxis = axes.append("line").attr("y2", height),
yAxis = axes.append("line").attr("x2", width);
var tileg = svg.append('g').attr('id', 'tiles');
var overlay = svg.append('g').attr('id', 'overlay');
function tileUrl(d) {
return 'http://a.tiles.mapbox.com/v3/tmcw.map-hehqnmda/' + d.join('/') + '.png';
}
function redraw() {
if (d3.event) {
projection
.translate(d3.event.translate)
.scale(d3.event.scale);
}
var t = projection.translate(),
s = projection.scale(),
z = Math.max(Math.log(s) / Math.log(2) - 8, 0);
rz = Math.floor(z),
ts = 256 * Math.pow(2, z - rz);
// This is the 0, 0 px of the projection
var tile_origin = [s / 2 - t[0], s / 2 - t[1]];
var tiles = [];
var cols = d3.range(Math.max(0, Math.floor((tile_origin[0] - width) / ts)),
Math.max(0, Math.ceil((tile_origin[0] + width) / ts)));
var rows = d3.range(Math.max(0, Math.floor((tile_origin[1] - height) / ts)),
Math.max(0, Math.ceil((tile_origin[1] + height) / ts)));
cols.forEach(function(x) {
rows.forEach(function(y) {
tiles.push([Math.floor(z), x, y]);
});
});
var tiles = tileg.selectAll('image.tile')
.data(tiles, function(d) { return d.join(',') });
tiles.exit()
.transition()
.duration(250)
.style("opacity", 0.0)
.remove();
tiles.enter().append('image')
.attr('class', 'tile')
.attr('xlink:href', tileUrl);
tiles.attr({ width: ts, height: ts })
.attr('transform', function(d) {
return 'translate(' + [(d[1] * ts) - tile_origin[0], (d[2] * ts) - tile_origin[1]] + ')';
})
xAxis.attr("x1", t[0]).attr("x2", t[0]);
yAxis.attr("y1", t[1]).attr("y2", t[1]);
overlay.selectAll('path.boundary')
.attr("d", path);
}
redraw();
overlay.insert("path")
.attr("class", "boundary");
overlay.insert("path")
.attr("class", "elastic");
var d = iD.Draw();
tileg.call(d);
d.on('draw', function(feature, elastic) {
console.log(elastic);
overlay.selectAll('path.elastic')
.data([elastic])
.attr("d", path);
overlay.selectAll('path.boundary')
.data([feature])
.attr("d", path);
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment