Skip to content

Instantly share code, notes, and snippets.

@GitNoise
Last active June 14, 2020 21:37
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 GitNoise/495ebb584c3460d3c917087fccbb627d to your computer and use it in GitHub Desktop.
Save GitNoise/495ebb584c3460d3c917087fccbb627d to your computer and use it in GitHub Desktop.
Handdrawn Waterman projection
license: mit
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
background: #fcfcfa;
}
.stroke {
fill: none;
stroke: #222;
stroke-width: 1px;
stroke-opacity:0.4
}
.fill {
fill: #fff;
}
.graticule {
fill: none;
stroke: #222;
stroke-width: 0.5px;
stroke-opacity: 0.2;
}
.land {
fill: #9b9b9b;
}
.boundary {
fill: none;
stroke: black;
stroke-opacity: 0.4;
stroke-width: .5px;
}
#filter {
height: 0;
width: 0;
}
.annotation-group text {
font-family: Comic Sans MS;
fill: #222;
fill-opacity: 0.8;
stroke-opacity: 0;
}
.annotation-group path {
stroke: #222;
fill: #222;
}
.annotation-group .connector-dot {
stroke: #fff;
stroke-width: 0.5;
}
</style>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-geo-projection.v1.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rough.js/3.1.0/rough.js"/></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-annotation/2.5.1/d3-annotation.min.js"></script>
<svg id='filter'>
<defs>
<filter id="outline">
<feMorphology
in="SourceAlpha"
result="DILATED"
operator="dilate"
radius="2" />
<feFlood
flood-color="#fff"
flood-opacity="1"
result="OUTLINECOLOUR" />
<feComposite
in="OUTLINECOLOUR"
in2="DILATED"
operator="in"
result="OUTLINE" />
<feMerge>
<feMergeNode in="OUTLINE" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
</svg>
<script>
const pathToRcPath = (d, color) => {
const rcPath = color ? rc.path(path(d), { fill: color }) : rc.path(path(d));
const pathD = d3.select(rcPath)
.select('path')
.attr('d')
return pathD;
}
var width = 960,
height = 500;
var projection = d3.geoPolyhedralWaterman()
projection.rotate([-65,0])
var path = d3.geoPath()
.projection(projection);
var graticule = d3.geoGraticule();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
const rc = rough.svg(svg.node());
var defs = svg.append("defs");
defs.append("path")
.datum({type: "Sphere"})
.attr("id", "sphere")
.attr("d", path);
defs.append("clipPath")
.attr("id", "clip")
.append("use")
.attr("xlink:href", "#sphere");
svg.append("use")
.attr("class", "stroke")
.attr("xlink:href", "#sphere");
svg
.append('path')
.datum({type: "Sphere"})
.attr("id", "sphere")
.attr("d", pathToRcPath);
d3.json("https://gist.githubusercontent.com/mbostock/4090846/raw/d534aba169207548a8a3d670c9c2cc719ff05c47/world-110m.json", function(error, world) {
// draw gaticule
svg.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("clip-path", "url(#clip)")
.attr("d", pathToRcPath);
// draw land
const pathLandRough = path(topojson.feature(world, world.objects.land));
const res = rc.path(pathLandRough, { fill: 'rgba(0,0,0,0.1)', fillStyle: 'cross-hatch', stroke: 'rgba(0,0,0,0.7)' })
res.setAttribute('id', 'roughLand')
svg.node().appendChild(res)
svg.select('#roughLand').selectAll('path')
.each(function() {
const el = d3.select(this)
el.attr("clip-path", "url(#clip)")
})
// draw country paths
svg.insert("path",)
.datum(topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; }))
.attr("class", "boundary")
.attr("clip-path", "url(#clip)")
.attr("d", pathToRcPath);
const createAnnotation = (title, label, lng, lat, offsetX, offsetY) => {
const xy = projection([lng, lat])
return (
{
note: {
title: title,
label: label,
wrap: 150,
},
connector: {
end: "dot",
type: "line",
},
x: xy[0],
y: xy[1],
dx: offsetX,
dy: offsetY
})
}
const annotations = []
annotations.push(createAnnotation('Stockholm (1976)', 'First 20 years', 18.063240, 59.334591, 60, -150 ))
annotations.push(createAnnotation('London (2003)', 'MSc. Machine Learning', -0.118092, 51.509865, -225, 75 ))
annotations.push(createAnnotation('Shanghai (2008)', 'Made first professional dataviz', 121.469170, 31.224361, 250, 20 ))
annotations.push(createAnnotation('Copenhagen (2012)', 'Master of Disaster Management', 12.568337, 55.676098, 75, 225 ))
const makeAnnotations = d3.annotation()
.type(d3.annotationLabel)
.annotations(annotations)
d3.select("svg:last-of-type")
.append("g")
.attr("class", "annotation-group")
.call(makeAnnotations)
});
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