Built with blockbuilder.org
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.25.5/d3-legend.js"></script>
<style>
.tooltip {
background-color: rgba(0, 0, 0, 0.8);
color: #fafafa;
padding: 5px;
border-radius: 4px;
transition: opacity 0.2s ease;
font-size: 12px;
text-align: left;
font-weight: bold;
}
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<script>
// Feel free to change or delete any of the code you see in this editor!
d3.json('cyclist-data.json', function(error, data) {
// data = data.sort(function(x, y){
// return d3.ascending(x.Year, y.Year);})
var margin = {top: 20, right: 20, bottom: 30, left: 40},
w = 600 - margin.left - margin.right,
h = 500 - margin.top - margin.bottom,
padding = 20,
space_for_label =10;
space_for_title =2;
var color = d3.scaleOrdinal(d3.schemeCategory10);
var svg = d3.select("body")
.append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left+"," +
margin.top+")");
//scale
var xScale = d3.scaleLinear()
.domain([d3.min(data, d=>d.Year ),
d3.max(data, d=>d.Year ) + space_for_label])
.rangeRound([margin.left, w + margin.left]);
//want to list from 1 to max
var yScale = d3.scaleLinear()
.domain([
d3.min(data, d=>d.Place) -
space_for_title ,
d3.max(data, d=>d.Place) +1])
.rangeRound([0, h]);
var xAxis = d3.axisBottom()
.scale(xScale)
.ticks(5);
var yAxis = d3.axisLeft()
.scale(yScale)
.ticks(5);
//tooltip
var tip = d3.select('body')
.append('div')
.attr('class', 'tooltip');
//legend
var ordinal = d3.scaleOrdinal()
.domain(["With Doping Allegation", "Without Doping Allegation"])
.range(["red","grey"]);
svg.append("g")
.attr("class", "legendOrdinal")
.attr("transform", "translate(350,30)");
var legendOrdinal = d3.legendColor()
.shape("path", d3.symbol().type(d3.symbolCircle).size(100)())
.shapePadding(10)
.scale(ordinal);
//draw circle
svg.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr('cx',d=>xScale(d.Year ))
.attr('cy',d=>yScale(d.Place))
.attr('r',5)
.style("fill", d=>d.Doping===''?"grey":"red" )
.on('mousemove', (d) => {
tip
.style('position', 'absolute')
.style('left', `${d3.event.pageX + 10}px`)
.style('top', `${d3.event.pageY + 20}px`)
.style('display', 'inline-block')
.style('opacity', '0.9')
.html(`
<span>${d.Name}: ${d.Nationality}</span>
<span>Year: ${d.Year}</span>
<br>
<span>${d.Doping}</span>
`);
})
.on('mouseout', () => tip.style('display', 'none'));
//text label
svg.selectAll('text')
.data(data)
.enter()
.append('text')
.attr('x',d=>xScale(d.Year ) + 5)
.attr('y',d=>yScale(d.Place) + 5)
.text(d => d.Name)
.style('font-size', '12px')
.style('font-family', 'futura');
//draw axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
svg.append("g")
.attr("class", "xaxis")
.attr("transform", "translate(0,"+ h +")")
.call(xAxis);
//axis label
svg.append('text')
.text('Year')
.style('font-size', '18px')
.attr('x', w/2 )
.attr('y', h + margin.top + 10)
.style('font-family', 'futura');
svg.append('text')
.text('places')
.style('font-size', '18px')
.attr('transform', 'rotate(-90)')
.attr('y', - margin.left/2 )
.attr('x', -h/2)
.style('font-family', 'futura');
//title
svg.append('text')
.text('Cyclist Doping')
.style('font-size', '22px')
.style('font-weight', 'bold')
.style('font-family', 'futura')
.attr('x', w/2 )
.attr('y', 0);
//add legend
svg.select(".legendOrdinal")
.call(legendOrdinal)
.style('font-family', 'futura')
.style('font-size', '12px');
})
</script>
</body>
https://d3js.org/d3.v4.min.js
https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.25.5/d3-legend.js