|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
|
|
<script src="https://d3js.org/d3.v5.min.js"></script> |
|
|
|
<style type="text/css"> |
|
|
|
svg { |
|
border:1px solid #f0f; |
|
} |
|
|
|
.axis line { |
|
stroke-width:1px; |
|
stroke: #ccc; |
|
stroke-dasharray: 2px 2px; |
|
} |
|
|
|
.axis text { |
|
font-size: 12px; |
|
fill: #777; |
|
} |
|
|
|
.axis path { |
|
display: none; |
|
} |
|
|
|
.ufoGroup text { |
|
fill: #aaa; /*grey out text*/ |
|
font-size: 11px; |
|
} |
|
|
|
.ufoCircle { |
|
fill: limegreen; |
|
} |
|
|
|
.ufoLine { |
|
fill: none; |
|
} |
|
|
|
.ufoLine { |
|
/*removes black fill*/ |
|
fill: none; |
|
/*styles line */ |
|
stroke: darkgray; |
|
stroke-width: 3 ; |
|
} |
|
|
|
</style> |
|
|
|
<body> |
|
<div id='titleDiv'> |
|
<text>UFO Sightings in 2018</text> |
|
<div id="buttonsDiv"></div> |
|
</div> |
|
</body> |
|
|
|
<script> |
|
|
|
//The data |
|
|
|
function drawCircles(thisData) { |
|
const groups = svg.selectAll('.ufoGroup') |
|
.data(thisData, function(d) { return d.month }) |
|
|
|
// groups |
|
// .enter().append('g') |
|
|
|
const enterGroups = groups |
|
.enter().append('g') |
|
// will need to assign class and location to incoming data groups |
|
.attr('class', 'ufoGroup') |
|
.attr('transform', function(d) { return 'translate(' + xScale(d.parsedDate) + ',' + yScale(d.count) + ')'}) |
|
.on('mouseenter', function(d) { |
|
// define hover events |
|
d3.select(this) |
|
.select('text') |
|
.transition() |
|
.duration(0) |
|
.style('opacity', 1) |
|
|
|
d3.selectAll('circle') |
|
.style('opacity', 0.5) |
|
|
|
d3.select(this) |
|
.select('circle') |
|
.transition() |
|
.ease(d3.easeElastic) |
|
.duration(transitionTime) |
|
.attr('r', radius*2) |
|
.style('opacity', 1) |
|
}) |
|
.on('mouseleave', function(d) { |
|
// define mouseleave events |
|
d3.select(this) |
|
.select('text') |
|
.transition() |
|
.style('opacity', 0) |
|
|
|
d3.select(this) |
|
.select('circle') |
|
.transition() |
|
.ease(d3.easeElastic) |
|
.duration(transitionTime) |
|
.attr('r', radius) |
|
|
|
d3.selectAll('circle') |
|
.style('opacity', 1) |
|
}) |
|
|
|
// add new circles |
|
enterGroups.append('circle') |
|
.attr('class', 'ufoCircle') |
|
.style('fill', 'limegreen') |
|
.attr('r', radius) |
|
|
|
// add new text |
|
enterGroups.append('text') |
|
.attr('class', 'ufoText') |
|
.attr('dx', radius) |
|
.attr('dy', -radius) |
|
.text(function(d) { return d.count}) |
|
.style('opacity', 0) |
|
|
|
groups |
|
.merge(groups) |
|
.transition() |
|
.ease(d3.easeElastic) |
|
.duration(transitionTime) |
|
.attr('transform', function(d) { return 'translate(' + xScale(d.parsedDate) + ',' + yScale(d.count) + ')'}) |
|
|
|
groups.exit().remove() |
|
} |
|
|
|
function dataSwap(datasetGroup, fullData) { |
|
|
|
const thisDataGroup = fullData.filter(function(d) { return d.year == datasetGroup}); |
|
|
|
console.log(thisDataGroup); |
|
|
|
xScale |
|
.domain(d3.extent(thisDataGroup, function(d) { return d.parsedDate; })); |
|
|
|
yScale |
|
.domain([0, d3.max(thisDataGroup, function(d) { return d.count; })]); |
|
|
|
xAxis.scale(xScale); |
|
|
|
yAxis.scale(yScale); |
|
|
|
xAxisGroup |
|
.call(xAxis); |
|
|
|
yAxisGroup |
|
.transition() |
|
.duration(transitionTime) |
|
.call(yAxis); |
|
|
|
drawCircles(thisDataGroup); |
|
|
|
|
|
|
|
svg.selectAll('.ufoLine') |
|
.transition() |
|
.ease(d3.easeElastic) //if you use the same ease here as you do with the circles, the line and circles will move together. |
|
.duration(transitionTime) |
|
.attr('d', lineGenerator(thisDataGroup)); |
|
|
|
d3.select('#titleText') |
|
.text('UFO Sightings in ' + datasetGroup); |
|
}; |
|
|
|
const parseTime = d3.timeParse("%m/%Y"); |
|
const margin = {top: 20, right: 30, bottom: 20, left: 30}; |
|
const outerWidth = 700; |
|
const outerHeight = 300; |
|
const innerWidth = outerWidth - margin.left - margin.right; |
|
const innerHeight = outerHeight - margin.top - margin.bottom; |
|
const transitionTime = 1000; |
|
const radius = 10; |
|
|
|
const SVG = d3.select("body").append("svg") |
|
.attr("width", outerWidth) |
|
.attr("height", outerHeight); |
|
|
|
const svg = SVG.append('g') |
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); |
|
|
|
const xScale = d3.scaleTime() |
|
.range([0, innerWidth]); |
|
|
|
const xAxis = d3.axisBottom(xScale) |
|
.tickSize(-innerHeight); |
|
|
|
const yScale = d3.scaleLinear() |
|
.range([innerHeight, 0]) |
|
|
|
const yAxis = d3.axisLeft(yScale) |
|
.tickSize(-innerWidth); |
|
|
|
const lineGenerator = d3.line() |
|
.curve(d3.curveCardinal); |
|
|
|
const xAxisGroup = svg.append("g") |
|
.attr("class", "x axis") |
|
.attr("transform", "translate(0," + innerHeight + ")") |
|
.call(xAxis); |
|
|
|
const yAxisGroup = svg.append("g") |
|
.attr("class", "y axis") //gives group the classes 'y' and 'axis' |
|
.call(yAxis); |
|
|
|
|
|
d3.csv("https://raw.githubusercontent.com/molliemarie/MSIA-D3Course-2019/master/Projects%26Exercises/generalUpdatePattern/data/ufo.csv", function(d) { |
|
return { |
|
date: d.date, |
|
count: +d.count, |
|
month: +d.date.split('/')[0], |
|
parsedDate: parseTime(d.date), |
|
year: parseTime(d.date).getYear() + 1900 |
|
}; |
|
}).then(ready); |
|
|
|
function ready(fullData) { |
|
|
|
const yearList = d3.set(fullData.map(function(d) { return d.year })).values(); |
|
|
|
|
|
const startData = fullData.filter(function(d) { return d.year == 2018; }); |
|
|
|
console.log(startData); |
|
|
|
d3.select('#buttonsDiv') |
|
.selectAll('button') |
|
.data(yearList) |
|
.enter().append('button') |
|
.text(function(d) { return d; }) |
|
.on('click', function(d) { |
|
dataSwap(d, fullData) |
|
}); |
|
|
|
xScale.domain(d3.extent(startData, function(d) { return d.parsedDate; })); |
|
|
|
yScale.domain([0, d3.max(startData, function(d) { return d.count})]); |
|
|
|
xAxisGroup.call(xAxis); |
|
|
|
yAxisGroup.call(yAxis); |
|
|
|
lineGenerator |
|
.x(function(d) { return xScale(d.parsedDate)}) |
|
.y(function(d) { return yScale(d.count)}) |
|
|
|
svg.append('path') |
|
.attr('class', 'ufoLine') |
|
.attr('d', lineGenerator(startData)); |
|
|
|
drawCircles(startData); |
|
} |
|
|
|
|
|
</script> |