@patricksurry/g3
Version:
A flexible Javascript framework for building steam gauge instrument panels that display live external metrics from flight (or other) simulators like XPlane or MS FS2020
86 lines (72 loc) • 2.53 kB
HTML
<html>
<head>
<style>
svg text {
font-family: Gill Sans,Gill Sans MT,Calibri,sans-serif;
text-anchor: middle;
dominant-baseline: central;
font-stretch: condensed;
}
</style>
<body>
<script src="https://d3js.org/d3.v7.min.js"></script>
<svg width=1200 height=600> </svg>
<script>
const projection = d3.geoProjection(function(lngrad, latrad) {
return [Math.sin(lngrad), 2*latrad/Math.PI];
}).scale(100).translate([0,0]).clipAngle(90).rotate([45,0]);
projection.gradient = ([lng, lat]) => {
const [rlng, rlat] = projection.rotate();
return [Math.cos((lng + rlng)*Math.PI/180), 1];
};
projection.deformation = ([lng, lat]) => {
// returns an SVG transformation representing how a an infinitesimal square at [lng, lat]
// is projected to a rhombus centered at the projected [x, y],
// see https://en.wikipedia.org/wiki/Infinitesimal_strain_theory
// TOOD make clipping and absolute/relative (i.e. including translate) options
const [x,y] = projection([lng, lat]);
var [sx, sy] = projection.gradient([lng, lat]);
if (sx <= 0) sx = sy = 0; // clip rear-facing objects
return `translate(${x},${y}) scale(${sx},${sy})`;
}
projection.path = d3.geoPath(projection);
var svg = d3.select('svg')
.append('g')
.attr('transform', 'translate(600, 300)');
svg.append('path')
.attr('style', 'stroke: red; stroke-width: 3; fill: none')
.attr('d',
projection.path({
type: "LineString",
coordinates: d3.range(-540, 541, 5).map(v => [v, v/6])
})
);
var ticks = svg.selectAll(null)
.data(d3.range(0, 360, 30))
.enter().append('g');
var tickmarks = ticks.append('path')
.datum(v => {return {type: 'LineString', coordinates: [[v,-5], [v, 5]]}})
.attr('style', 'stroke: grey; fill: none')
.attr('d', projection.path);
var ticklabels = ticks.append('text')
.text(v => v)
.datum(v => [v, 10])
.attr('transform', projection.deformation)
svg.append('path')
.attr('style', 'stroke: blue; stroke-width: 3; fill: none')
.attr('d',
projection.path({
type: "LineString",
coordinates: d3.range(-180, 180, 30).map(v => [v, 0])
})
);
setInterval(function() {
const [lng, lat] = projection.rotate();
projection.rotate([lng+5,lat]);
tickmarks.transition().duration(250).attr('d', projection.path);
ticklabels.transition().duration(250).attr('transform', projection.deformation);
}, 250);
</script>
</body>
</html>