Skip to content

Instantly share code, notes, and snippets.

@veltman
Last active October 5, 2024 15:25
Pencil/watercolor map style

Trying for a pencil/watercolor sort of effect. Each state is blurred and clipped to itself to create a stroke that bleeds inward. Turbulence and displacement filters muss the borders a little, and some line interpolation rounds the corners.

Chrome, Firefox, and Safari each apply the filters very differently!

See also: Pencil sketch, Colorized atlas style

US TopoJSON via Mike Bostock

<!DOCTYPE html>
<meta charset="utf-8">
<style>
path {
stroke-width: 2px;
fill: none;
}
.mesh path {
stroke: #555;
opacity: 0.8;
stroke-width: 1.5px;
stroke-linejoin: round;
}
rect {
stroke: none;
fill: rgba(224,186,148,0.3);
}
</style>
<body>
<svg>
<defs>
<filter id="tint">
<feColorMatrix values="1.1 0 0 0 0 0 1.1 0 0 0 0 0 0.9 0 0 0 0 0 1 0" />
</filter>
<filter id="splotch">
<feTurbulence type="fractalNoise" baseFrequency=".01" numOctaves="4" />
<feColorMatrix values="0 0 0 0 0, 0 0 0 0 0, 0 0 0 0 0, 0 0 0 -0.9 1.2" result="texture" />
<feComposite in="SourceGraphic" in2="texture" operator="in" />
<feGaussianBlur stdDeviation="3.5" />
</filter>
<filter id="pencil">
<feTurbulence baseFrequency="0.03" numOctaves="6" type="fractalNoise" />
<feDisplacementMap scale="4" in="SourceGraphic" xChannelSelector="R" yChannelSelector="G" />
<feGaussianBlur stdDeviation="0.5" />
</filter>
</defs>
</svg>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.20/topojson.min.js"></script>
<script>
var width = 960,
height = 500;
var projection = d3.geo.albers()
.rotate([96, 0])
.parallels([29.5, 45.5])
.center([-0.62, 38.65])
.scale(1065)
.translate([width / 2, height / 2])
.precision(.1);
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("filter", "url(#tint)");
var defs = d3.select("defs");
svg.append("rect")
.attr("width", width)
.attr("height", height);
var line = d3.svg.line()
.interpolate("cardinal")
.tension(0.75);
var colors = ["#00c65e", "#c60084", "#c6c600", "#09a3bd", "#b15313"];
d3.json("us.json", function(err, us) {
var neighbors = topojson.neighbors(us.objects.states.geometries),
mesh = topojson.mesh(us,us.objects.states),
features = topojson.feature(us, us.objects.states).features;
features.forEach(function(d,i){
// Greedy color selection
d.properties.color = colors.filter(function(c){
return neighbors[i].map(function(n){
return features[n].properties.color;
}).indexOf(c) === -1;
})[0];
// Mix it up a bit, get fifth color in
colors.push(colors.shift());
// circular <use> doesn't work in FF
defs.append("clipPath")
.attr("id", "clip" + i)
.append("path")
.attr("d", path(d));
});
svg.selectAll(".state")
.data(features)
.enter()
.append("path")
.attr("class", "state")
.attr("d", path)
.style("fill", function(d){
return transparent(d.properties.color, 0.3);
})
.style("stroke", function(d,i){
return d.properties.color;
})
.attr("clip-path", function(d,i){
return "url(#clip" + i + ")";
})
.attr("filter", "url(#splotch)");
svg.append("g")
.attr("class", "mesh")
.attr("filter", "url(#pencil)")
.selectAll(".path")
.data(mesh.coordinates)
.enter()
.append("path")
.attr("d", function(d){
return line(d.map(projection));
});
});
function transparent(color, alpha) {
var rgb = d3.rgb(color);
return "rgba(" + [rgb.r, rgb.g, rgb.b, alpha].join(",") + ")";
}
</script>
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment