Skip to content

Instantly share code, notes, and snippets.

@clhenrick
Last active February 14, 2018 03:12
Show Gist options
  • Save clhenrick/d273577dbc4e2ea8779ccaca800eab3e to your computer and use it in GitHub Desktop.
Save clhenrick/d273577dbc4e2ea8779ccaca800eab3e to your computer and use it in GitHub Desktop.
Elevation Profile
license: mit

Elevation Profile (area chart)

For a route starting at New Haven, CT and ending at Hartford, CT.

Built with blockbuilder.org

var data = [{"y":39,"x":0.18},{"y":36,"x":0.32},{"y":41,"x":0.47},{"y":48,"x":0.64},{"y":55,"x":0.83},{"y":61,"x":0.98},{"y":66,"x":1.14},{"y":65,"x":1.28},{"y":65,"x":1.45},{"y":64,"x":1.83},{"y":93,"x":1.98},{"y":67,"x":2.24},{"y":61,"x":2.41},{"y":64,"x":2.58},{"y":62,"x":3.55},{"y":86,"x":4.54},{"y":65,"x":4.83},{"y":68,"x":5.01},{"y":59,"x":5.19},{"y":62,"x":5.59},{"y":82,"x":6.39},{"y":107,"x":7.07},{"y":172,"x":7.3},{"y":116,"x":7.61},{"y":148,"x":7.88},{"y":180,"x":8.07},{"y":128,"x":8.25},{"y":161,"x":8.49},{"y":158,"x":8.65},{"y":194,"x":8.81},{"y":152,"x":9.03},{"y":170,"x":9.19},{"y":115,"x":9.37},{"y":116,"x":9.57},{"y":147,"x":9.76},{"y":138,"x":9.91},{"y":144,"x":10.06},{"y":171,"x":10.21},{"y":149,"x":10.38},{"y":137,"x":10.73},{"y":161,"x":10.88},{"y":159,"x":11.07},{"y":175,"x":11.23},{"y":148,"x":11.38},{"y":153,"x":11.57},{"y":145,"x":12.27},{"y":144,"x":12.46},{"y":187,"x":12.77},{"y":150,"x":13.3},{"y":157,"x":13.77},{"y":181,"x":13.93},{"y":153,"x":14.3},{"y":157,"x":14.52},{"y":180,"x":14.75},{"y":153,"x":14.96},{"y":163,"x":15.14},{"y":182,"x":15.53},{"y":176,"x":15.73},{"y":216,"x":15.91},{"y":226,"x":16.28},{"y":225,"x":16.45},{"y":181,"x":16.66},{"y":187,"x":16.93},{"y":203,"x":17.1},{"y":173,"x":17.34},{"y":169,"x":17.62},{"y":214,"x":17.77},{"y":143,"x":17.99},{"y":136,"x":18.26},{"y":160,"x":18.41},{"y":139,"x":18.62},{"y":166,"x":18.97},{"y":166,"x":19.12},{"y":164,"x":19.57},{"y":155,"x":19.77},{"y":158,"x":20.08},{"y":141,"x":20.32},{"y":135,"x":20.54},{"y":137,"x":20.71},{"y":141,"x":20.88},{"y":145,"x":21.16},{"y":155,"x":21.38},{"y":144,"x":21.79},{"y":150,"x":22.15},{"y":150,"x":22.68},{"y":146,"x":22.94},{"y":162,"x":23.12},{"y":150,"x":23.35},{"y":195,"x":23.54},{"y":201,"x":23.73},{"y":235,"x":23.87},{"y":228,"x":24.04},{"y":225,"x":24.28},{"y":210,"x":24.54},{"y":225,"x":24.82},{"y":231,"x":25.02},{"y":229,"x":25.16},{"y":283,"x":25.34},{"y":310,"x":25.51},{"y":309,"x":25.86},{"y":259,"x":26.13},{"y":205,"x":26.59},{"y":185,"x":26.73},{"y":178,"x":26.88},{"y":175,"x":27.09},{"y":182,"x":27.33},{"y":183,"x":27.58},{"y":186,"x":27.75},{"y":191,"x":27.92},{"y":191,"x":28.08},{"y":184,"x":28.23},{"y":186,"x":28.5},{"y":189,"x":28.84},{"y":190,"x":29.01},{"y":197,"x":29.71},{"y":198,"x":30.46},{"y":199,"x":30.72},{"y":197,"x":30.87},{"y":178,"x":31.16},{"y":179,"x":31.31},{"y":199,"x":31.54},{"y":174,"x":31.71},{"y":192,"x":31.86},{"y":219,"x":32.01},{"y":238,"x":32.17},{"y":241,"x":32.32},{"y":231,"x":32.48},{"y":235,"x":32.65},{"y":238,"x":32.85},{"y":243,"x":33.01},{"y":245,"x":33.61},{"y":254,"x":33.86},{"y":275,"x":34.01},{"y":269,"x":34.38},{"y":190,"x":35.12},{"y":250,"x":35.65},{"y":227,"x":36.31},{"y":236,"x":37.25},{"y":275,"x":37.85},{"y":287,"x":38.56},{"y":278,"x":38.91},{"y":246,"x":39.11},{"y":286,"x":39.29},{"y":307,"x":39.68},{"y":288,"x":39.86},{"y":298,"x":40.01},{"y":326,"x":40.16},{"y":316,"x":40.31},{"y":319,"x":40.52},{"y":243,"x":40.66},{"y":227,"x":40.81},{"y":210,"x":40.96},{"y":243,"x":41.1},{"y":234,"x":41.3},{"y":197,"x":41.45},{"y":234,"x":41.62},{"y":185,"x":42.01},{"y":218,"x":42.91},{"y":172,"x":43.82},{"y":200,"x":43.97},{"y":195,"x":44.14},{"y":182,"x":44.46},{"y":174,"x":44.64},{"y":176,"x":44.8},{"y":178,"x":44.99},{"y":177,"x":45.24},{"y":181,"x":45.49},{"y":159,"x":45.64},{"y":160,"x":45.79},{"y":182,"x":45.98},{"y":304,"x":46.44},{"y":337,"x":46.62},{"y":404,"x":46.78},{"y":482,"x":47.19},{"y":464,"x":47.48},{"y":333,"x":47.95},{"y":249,"x":48.2},{"y":215,"x":48.45},{"y":233,"x":48.65},{"y":197,"x":48.82},{"y":157,"x":49.01},{"y":127,"x":49.2},{"y":146,"x":49.48},{"y":119,"x":49.65},{"y":118,"x":49.84},{"y":104,"x":50.16},{"y":106,"x":50.43},{"y":99,"x":50.58},{"y":94,"x":50.83},{"y":99,"x":51.17},{"y":103,"x":51.35},{"y":104,"x":51.51},{"y":110,"x":51.71},{"y":111,"x":51.9},{"y":82,"x":52.04},{"y":70,"x":52.41},{"y":76,"x":52.56},{"y":69,"x":52.72},{"y":62,"x":52.92},{"y":61,"x":53.11},{"y":65,"x":53.27},{"y":61,"x":53.5},{"y":77,"x":53.68},{"y":82,"x":53.99},{"y":94,"x":54.14},{"y":97,"x":54.52},{"y":89,"x":54.75},{"y":55,"x":54.93},{"y":70,"x":55.08},{"y":62,"x":55.31},{"y":55,"x":55.46},{"y":51,"x":55.78},{"y":45,"x":56.08},{"y":49,"x":56.35}];
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body {
margin:0;
position:fixed;
top:0;right:0;bottom:0;left:0;
padding: 10px;
}
/* svg { border: 1px solid aqua; } */
text tspan {
font-weight: bold;
}
text.heading {
font-size: 0.7em;
}
</style>
</head>
<body>
<script src="data.js"></script>
<script>
totalDistance = Math.round(data[data.length - 1].x);
let elevGain = data.reduce((acc, cur, idx, arr) => {
if (idx > 0 && (cur.y > arr[idx - 1].y)) {
acc += cur.y - arr[idx - 1].y;
}
return acc;
}, 0);
elevGain = Math.round(elevGain * 3.28084);
const chartMargins = {
top: 10,
right: 10,
bottom: 50,
left: 50
};
const chartWidth = 860;
const chartHeight = 300;
const width = chartWidth - chartMargins.right - chartMargins.left;
const height = chartHeight - chartMargins.top - chartMargins.bottom;
const svg = d3.select('body').append('svg')
.attr('width', chartWidth)
.attr('height', chartHeight);
const g = svg.append('g')
.attr('transform', "translate(" + chartMargins.left + "," + chartMargins.top + ")");
const xScale = d3.scaleLinear()
.range([0, width])
.domain(d3.extent(data, d => d.x));
const yScale = d3.scaleLinear()
.range([height, 0])
.domain(d3.extent(data, d => d.y));
const areaFn = d3.area()
.x(d => xScale(d.x))
.y0(yScale(d3.min(data, d => d.y)))
.y1(d => yScale(d.y))
.curve(d3.curveBasis);
g.append('path')
.datum(data)
.attr('fill', 'steelblue')
.attr('d', areaFn);
g.append('g')
.attr('transform', `translate(0, ${height})`)
.call(d3.axisBottom(xScale))
.append('text')
.attr('fill', '#333')
.attr('y', 35)
.attr('x', width / 2)
.text('Distance in miles');
g.append('g')
.call(d3.axisLeft(yScale))
.append('text')
.attr('fill', '#333')
.attr('transform', 'rotate(-90)')
.attr('y', -35)
.attr('x', -height / 2)
.attr('text-anchor', 'end')
.text('Height, in feet');
// label for total distance
g.append('g')
.append('text')
.classed('heading', true)
.attr('y', height + 35)
.attr('x', 0)
.attr('font-family', 'sans-serif')
.text('Total distance:')
.append('tspan')
.text(` ${totalDistance} mi`);
// label for total elevation gain
g.append('g')
.append('text')
.classed('heading', true)
.attr('y', height + 35)
.attr('x', width)
.attr('font-family', 'sans-serif')
.attr('text-anchor', 'end')
.attr('startOffset', '100%')
.text('Elevation gain:')
.append('tspan')
.text(` ${elevGain.toLocaleString()} ft`);
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment