The Bonne projection is available as d3.geo.bonne in d3-geo-projection. See also the Werner projection.
-
-
Save w8r/2a79bfd4647eca6795543a0cf18409d7 to your computer and use it in GitHub Desktop.
Bonne
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: gpl-3.0 | |
height: 900 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://unpkg.com/d3"></script> | |
<script src="https://unpkg.com/d3-geo-projection"></script> | |
<script src="https://unpkg.com/topojson"></script> | |
<style> | |
body { | |
background: #fcfcfa; | |
padding: 0; | |
margin: 0; | |
} | |
.stroke { | |
fill: none; | |
stroke: #000; | |
stroke-width: 3px; | |
} | |
.fill { | |
fill: #fff; | |
} | |
.graticule { | |
fill: none; | |
stroke: #777; | |
stroke-width: .5px; | |
stroke-opacity: .5; | |
} | |
.land { | |
fill: #222; | |
} | |
.boundary { | |
fill: none; | |
stroke: #fff; | |
stroke-width: .5px; | |
} | |
.fool { | |
background-image: url('bouffon.jpg'); | |
background-position: center top; | |
background-repeat: no-repeat; | |
background-size: contain; | |
display: block; | |
position: absolute; | |
top: 0; | |
} | |
.map { | |
position: relative; | |
} | |
</style> | |
</head> | |
<body> | |
<script src="index.js"></script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const height = document.documentElement.clientHeight; | |
const width = document.documentElement.clientWidth - 30; | |
const imageUrl = 'bouffon.jpg'; | |
const projection = d3.geoBonne() | |
.center([0, 27]) | |
.parallel(15) | |
.scale(60) | |
.translate([width / 2, height / 2]) | |
.precision(0.2); | |
const path = d3.geoPath() | |
.projection(projection); | |
const graticule = d3.geoGraticule(); | |
var canvas, ctx, cw, cx, cpath, cprojection, | |
world, land, boundary; | |
// Given a 4x4 perspective transformation matrix, and a 2D point (a 2x1 vector), | |
// applies the transformation matrix by converting the point to homogeneous | |
// coordinates at z=0, post-multiplying, and then applying a perspective divide. | |
function project(m, p) { | |
p = multiply(m, [p[0], p[1], 0, 1]); | |
return [p[0] / p[3], p[1] / p[3]]; | |
} | |
// Post-multiply a 4x4 matrix in column-major order by a 4x1 column vector: | |
// [ m0 m4 m8 m12 ] [ v0 ] [ x ] | |
// [ m1 m5 m9 m13 ] * [ v1 ] = [ y ] | |
// [ m2 m6 m10 m14 ] [ v2 ] [ z ] | |
// [ m3 m7 m11 m15 ] [ v3 ] [ w ] | |
function multiply(m, v) { | |
return [ | |
m[0] * v[0] + m[4] * v[1] + m[8 ] * v[2] + m[12] * v[3], | |
m[1] * v[0] + m[5] * v[1] + m[9 ] * v[2] + m[13] * v[3], | |
m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * v[3], | |
m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3] | |
]; | |
} | |
const img = new Image(); | |
img.onload = () => { | |
const { naturalWidth, naturalHeight } = img; | |
const imageWidth = Math.min(width, naturalWidth); | |
const imageHeight = naturalHeight * (naturalWidth / imageWidth); | |
const background = d3.select('body') | |
.insert('div', '.map') | |
.classed('fool', true) | |
.style('background-image', `url(${imageUrl})`) | |
.style('width', imageWidth + 'px') | |
.style('height', imageHeight + 'px'); | |
cw = imageWidth * 2; ch = imageHeight * 2; | |
canvas = background | |
.append('canvas') | |
.classed('map', true) | |
.attr('width', cw) | |
.attr('height', ch) | |
.style('width', cw / 2 + 'px') | |
.style('height', ch / 2 + 'px'); | |
cprojection = d3.geoBonne() | |
.center([0, 27]) | |
.parallel(17) | |
.scale(220) | |
.translate([cw / 2, ch / 2 - 270]) | |
//.fitSize([cw, ch]) | |
.precision(1); | |
ctx = canvas.node().getContext('2d'); | |
ctx.lineJoin = 'round'; | |
ctx.lineCap = 'round'; | |
cpath = d3.geoPath() | |
.projection(cprojection) | |
.context(ctx); | |
}; | |
img.src = imageUrl; | |
const svg = d3.select('body').append('svg') | |
.attr('width', width) | |
.attr('height', height); | |
svg.append('defs').append('path') | |
.datum({type: 'Sphere'}) | |
.attr('id', 'sphere') | |
.attr('d', path); | |
svg.append('use') | |
.attr('class', 'stroke') | |
.attr('xlink:href', '#sphere'); | |
svg.append('use') | |
.attr('class', 'fill') | |
.attr('xlink:href', '#sphere'); | |
const graticuleSvg = svg.append('path') | |
.datum(graticule) | |
.attr('class', 'graticule') | |
.attr('d', path); | |
d3.json('world-50m.json', function(error, data) { | |
if (error) throw error; | |
world = topojson.presimplify(data); | |
world = topojson.simplify(world, 0.5); | |
const landSvg = svg.insert('path', '.graticule') | |
.datum(topojson.feature(world, world.objects.land)) | |
.attr('class', 'land') | |
.attr('d', path); | |
land = topojson.feature(world, world.objects.land); | |
boundary = topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; }); | |
const velocity = 0.02; | |
const svgBoundary = svg.insert('path', '.graticule') | |
.datum(boundary) | |
.attr('class', 'boundary') | |
.attr('d', path); | |
d3.timer(function(elapsed) { | |
if (!ctx) return; | |
ctx.clearRect(0, 0, cw, ch); | |
cprojection.rotate([velocity * elapsed, 0]); | |
ctx.beginPath(); | |
cpath(graticule.outline()); | |
ctx.strokeStyle = '#000000'; | |
ctx.lineWidth = 1; | |
ctx.fillStyle = '#ffffff'; | |
ctx.fill(); | |
ctx.stroke(); | |
ctx.beginPath(); | |
cpath(land); | |
ctx.fillStyle = '#222222'; | |
ctx.fill(); | |
ctx.beginPath(); | |
cpath(boundary); | |
ctx.strokeStyle = '#ffffff'; | |
ctx.lineWidth = 1; | |
ctx.closePath(); | |
ctx.stroke(); | |
ctx.beginPath(); | |
cpath(graticule()); | |
ctx.strokeStyle = '#000000'; | |
ctx.lineWidth = 0.2; | |
ctx.stroke(); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment