Add an transparency gradient to the border of a map.
The map is drawn in svg using OSM’s vector tiles API and d3.geo.tile plugin as
shown in this block. The gradient border
is drawn in an overlaying canvas with the
CanvasGradient
interface.
Tiles copyright © OpenStreetMap contributors
<html>
<head>
<meta chartset="utf-8">
<style>
body {
margin: 0;
font-family: monospace;
}
.container > svg,
.container > canvas {
position: absolute;
}
path {
fill: none;
stroke: #000;
stroke-linejoin: round;
stroke-linecap: round;
}
.major_road { stroke: #776; }
.minor_road { stroke: #ccb; }
.highway { stroke: tomato; }
.rail { stroke: #7de; }
.annotation {
text-anchor: middle;
text-shadow: -1px 0 #fff, 0 1px #fff, 1px 0 #fff, 0 -1px #fff;
}
.annotation.large { font-size: 22px; }
.annotation.medium { font-size: 16px; }
.annotation.small { font-size: 12px; }
</style>
</head>
<body>
<div class="container"></div>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="d3.geo.tile.js"></script>
<script>
var width = 960,
height = 500;
var tiler = d3.geo.tile()
.size([width, height]);
var projection = d3.geo.mercator()
.center([-87.95, 43.040150])
.scale((1 << 20) / 2 / Math.PI)
.translate([width / 2, height / 2]);
var path = d3.geo.path()
.projection(projection);
var svg = d3.select(".container").append("svg")
.attr("width", width)
.attr("height", height)
.call(drawMap);
var canvas = d3.select(".container").append("canvas")
.attr("width", width)
.attr("height", height)
.call(addGradientEdge, 75);
function addGradientEdge(selection, borderWidth) {
var context = selection.node().getContext("2d");
var gradientData = [
{
side: "left", x: 0, y: 0, dx: borderWidth, dy: height,
gradient: context.createLinearGradient(0, 0, borderWidth, 0)
},
{
side: "top", x: 0, y: 0, dx: width, dy: borderWidth,
gradient: context.createLinearGradient(0, 0, 0, borderWidth)
},
{
side: "right", x: width - borderWidth, y: 0, dx: borderWidth, dy: height,
gradient: context.createLinearGradient(width, 0, width - borderWidth, 0)
},
{
side: "bottom", x: 0, y: height - borderWidth, dx: width, dy: borderWidth,
gradient: context.createLinearGradient(0, height, 0, height - borderWidth)
},
];
gradientData.forEach(function(d) {
d.gradient.addColorStop(0, "white");
d.gradient.addColorStop(1, "rgba(255, 255, 255, 0)");
context.fillStyle = d.gradient;
context.fillRect(d.x, d.y, d.dx, d.dy);
});
}
function drawMap(selection) {
var annotation_data = [
{
text: "Milwaukee",
coords: [-87.894746, 43.040746],
size: "large"
},
{
text: "Wauwatosa",
coords: [-88.005609, 43.050873],
size: "medium"
},
{
text: "West Allis",
coords: [-88.006764, 43.016687],
size: "medium"
}
];
var tiles = selection.selectAll(".tile")
.data(tiler
.scale(projection.scale() * 2 * Math.PI)
.translate(projection([0, 0])));
tiles.enter().append("g")
.attr("class", "tile")
.each(function(d) {
var tile = d3.select(this);
d3.json("//" + ["a", "b", "c"][(d[0] * 31 + d[1]) % 3] + ".tile.openstreetmap.us/vectiles-highroad/" + d[2] + "/" + d[0] + "/" + d[1] + ".json", function(error, json) {
tile.selectAll("path")
.data(json.features.sort(function(a, b) { return a.properties.sort_key - b.properties.sort_key; }))
.enter().append("path")
.attr("class", function(d) { return d.properties.kind; })
.attr("d", path);
});
});
var annotations = selection.selectAll(".annotation").data(annotation_data);
annotations.enter().append("text")
.attr("class", function(d) { return "annotation " + d.size; })
.attr("x", function(d) { return projection(d.coords)[0]; })
.attr("y", function(d) { return projection(d.coords)[1]; })
.text(function(d) { return d.text; });
}
</script>
</body>
</html>
d3.geo.tile = function() {
var size = [960, 500],
scale = 256,
translate = [size[0] / 2, size[1] / 2],
zoomDelta = 0;
function tile() {
var z = Math.max(Math.log(scale) / Math.LN2 - 8, 0),
z0 = Math.round(z + zoomDelta),
k = Math.pow(2, z - z0 + 8),
origin = [(translate[0] - scale / 2) / k, (translate[1] - scale / 2) / k],
tiles = [],
cols = d3.range(Math.max(0, Math.floor(-origin[0])), Math.max(0, Math.ceil(size[0] / k - origin[0]))),
rows = d3.range(Math.max(0, Math.floor(-origin[1])), Math.max(0, Math.ceil(size[1] / k - origin[1])));
rows.forEach(function(y) {
cols.forEach(function(x) {
tiles.push([x, y, z0]);
});
});
tiles.translate = origin;
tiles.scale = k;
return tiles;
}
tile.size = function(_) {
if (!arguments.length) return size;
size = _;
return tile;
};
tile.scale = function(_) {
if (!arguments.length) return scale;
scale = _;
return tile;
};
tile.translate = function(_) {
if (!arguments.length) return translate;
translate = _;
return tile;
};
tile.zoomDelta = function(_) {
if (!arguments.length) return zoomDelta;
zoomDelta = +_;
return tile;
};
return tile;
};