Created
January 13, 2019 12:42
-
-
Save fdnklg/131b1bd5d107d457897c7b3c4b6645ed to your computer and use it in GitHub Desktop.
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> | |
<style> | |
svg { | |
display: block; | |
margin: 0 auto; | |
} | |
.axis .domain { | |
display: none; | |
} | |
.axis--x text { | |
fill: #999; | |
} | |
.axis--x line { | |
stroke: #aaa; | |
} | |
.axis--activity .tick line { | |
display: none; | |
} | |
.axis--activity text { | |
font-size: 12px; | |
fill: #777; | |
} | |
.chart_grp-count-relative { | |
padding-left: 5px; | |
} | |
path { | |
opacity: 0.3 | |
} | |
</style> | |
</head> | |
<body> | |
<script src="https://d3js.org/d3.v5.min.js"></script> | |
<script> | |
var numHorizons = 4; | |
var margin = { top: 30, right: 10, bottom: 30, left: 0 }, | |
width = 300 - margin.left - margin.right, | |
height = 85 - margin.top - margin.bottom, | |
bisectDate = d3.bisector(function(d) { return d.time; }).left; | |
var formatTime = d3.timeFormat('%Y'); | |
var wrapper = d3.select('body').append('div') | |
.classed('charts', true) | |
var x = function(d) { return d.time; }, | |
xScale = d3.scaleTime().range([0, width]), | |
xValue = function(d) { return xScale(x(d)); }, | |
xAxis = d3.axisBottom(xScale).tickFormat(formatTime).ticks(6); | |
var y = function(d) { return d.value; }, | |
yScale = d3.scaleLinear().clamp(true), | |
y0Value = function(d) { return yScale(0); } | |
y1Value = function(d) { return yScale(y(d)); }; | |
var activity = function(d) { return d.key; }, | |
activityScale = d3.scaleBand().range([0, height]).padding(0.05), | |
activityValue = function(d) { return activityScale(activity(d)); }, | |
activityAxis = d3.axisLeft(activityScale); | |
var horizonScale = d3.scaleQuantize() | |
.range(d3.range(numHorizons)); | |
var fill = function(d) { return d.yExtent[0]; }, | |
fillScale = d3.scaleLinear().range(['lavender', 'purple']).interpolate(d3.interpolateHcl), | |
fillValue = function(d) { | |
return fillScale(fill(d)); | |
}; | |
var area = d3.area() | |
.x(xValue) | |
.y0(y0Value) | |
.y1(y1Value); | |
function peakTime(d) { | |
var i = d3.scan(d.values, function(a, b) { return y(b) - y(a); }); | |
console.log(i) | |
return d.values[i].value; | |
}; | |
// take into account for future coding projects | |
// function row(d) { | |
// return { | |
// activity: d.activity, | |
// time: parseTime(d.time), | |
// value: +d.p_smooth | |
// }; | |
// } | |
function mouseover() { | |
console.log('mouse over') | |
} | |
function mouseout() { | |
console.log('mouse out') | |
} | |
// d3.tsv('data.tsv', row).then((dataFlat) => { | |
d3.json('grps_over_time_restructured.json'). then(data => { | |
data.forEach(category => { | |
category.values.forEach(value => { | |
value.time = new Date(value.time); | |
}) | |
}) | |
data.forEach((category,catIndex) => { | |
function mousemove() { | |
let data = category.values | |
var x0 = xScale.invert(d3.mouse(this)[0]), | |
i = bisectDate(data, x0, 1) | |
d0 = data[i - 1], | |
d1 = data[i], | |
dNew = x0 - d0.date > d1.date - x0 ? d1 : d0; | |
grp_count.text(dNew.value) | |
console.log(dNew.value) | |
focus.attr("transform", "translate(" + xScale(dNew.time) + ")"); | |
focus.select("text").text((d.close)); | |
} | |
let d = category; | |
let grp_count_total = category.values[category.values.length - 1].value; | |
const chart_wrapper = wrapper.append('div') | |
.classed('chart_wrapper', true) | |
const chart_text_wrapper = wrapper.append('div') | |
.classed('chart_text_wrapper', true) | |
const title = chart_text_wrapper.append('span') | |
.classed('chart_title', true) | |
.text(category.key) | |
const grp_count = chart_text_wrapper.append('span') | |
.classed('chart_grp-count', true) | |
.text(grp_count_total) | |
const grp_count_relative = chart_text_wrapper.append('span') | |
.classed('chart_grp-count-relative', true) | |
.text(Math.round((grp_count_total / 3300) * 100) + '%') | |
var svg = chart_wrapper.append('svg') | |
.attr('width', width + margin.left + margin.right) | |
.attr('height', height + margin.top + margin.bottom) | |
.append('g') | |
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); | |
const focus = svg.append("g") | |
.attr("class", "focus") | |
.style("display", "none"); | |
focus.append("rect") | |
.attr("width", 1) | |
.attr("height", 60) | |
.attr('fill', 'black'); | |
// console.log(d3.extent(dataFlat, y)) | |
// Sort by time | |
// dataFlat.sort(function(a, b) { return a.time - b.time; }); | |
// var data = d3.nest() | |
// .key(function(d) { return d.activity; }) | |
// .entries(dataFlat); | |
// console.log(data); | |
// Sort activities by growth | |
data.sort(function(a, b) { return peakTime(b) - peakTime(a); }); | |
xScale.domain([new Date('2008-01-01'),new Date('2019-02-01')]); | |
// activityScale.domain(data.map(function(d) { return d.key; })); | |
yScale.range([activityScale.bandwidth(), 0]); | |
// horizonScale.domain(d3.extent(dataFlat, y)); | |
horizonScale.domain([0,50]); | |
svg.append('g').attr('class', 'axis axis--x') | |
.attr('transform', 'translate(0,' + height + ')') | |
.call(xAxis) | |
svg.append('g').attr('class', 'axis axis--activity') | |
.call(activityAxis); | |
var gActivity = svg | |
.append('g') | |
.attr('class', 'activity activity--' + d.key) | |
.attr('transform', function() { | |
var ty = activityValue(d); | |
return 'translate(0,' + ty + ')'; | |
}) | |
.on("mousemove", mousemove) | |
.on("mouseover", function() { focus.style("display", null); }) | |
.on("mouseout", function() { | |
grp_count.text(grp_count_total) | |
focus.style("display", "none"); | |
}) | |
function horizonData(d) { | |
return horizonScale.range() | |
.map(function(i) { | |
return { | |
yExtent: horizonScale.invertExtent(i), | |
key: d.key, | |
values: d.values | |
}; | |
}); | |
} | |
var gHorizon = gActivity.selectAll('.horizon').data(horizonData(d)) | |
.enter().append('path') | |
.attr('class', 'horizon') | |
.each(function(d,i) { | |
// TODO: create separate y-scales using d3.local() | |
yScale.domain(d.yExtent); | |
d3.select(this) | |
.attr('d', area(d.values)); | |
}) | |
.style('fill', fillValue); | |
}) | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment