Built with blockbuilder.org
xxxxxxxxxx
<html>
<head>
<meta charset='utf-8'>
<style>
.chart svg{
border:2px dashed #00a5bb;
}
text{
font-size: 20px;
font-family: Open Sans, sans-serif;
}
text.title{
font-size: 36px;
font-weight: 500;
}
text.subTitle{
font-weight: 500;
fill: #777777;
}
text.caption{
font-weight: 400;
font-size: 14px;
fill: #777777;
}
text.label{
font-weight: 600;
}
text.yearText{
font-size: 64px;
font-weight: 700;
opacity: 0.25;
}
.tick text {
fill: #777777;
}
.xAxis .tick:nth-child(2) text {
text-anchor: start;
}
.tick line {
shape-rendering: CrispEdges;
stroke: #dddddd;
}
.tick line.origin{
stroke: #aaaaaa;
}
path.domain{
display: none;
}
</style>
</head>
<body>
<center>
<div class='chart'></div>
</center>
<!-- <script type="text/javascript" src="lib/d3-3.5.6.js"></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<script>
var halo = function(text, strokeWidth) {
text.select(function() { return this.parentNode.insertBefore(this.cloneNode(true), this); })
.style('fill', '#000000')
.style('stroke','#ffffff')
.style('stroke-width',strokeWidth)
.style('stroke-linejoin','round')
.style('opacity',1);
};
d3.csv = d3.dsv(",", "text/csv;charset=gb2312");
d3.csv('South+Chennai+-+Sheet2+(3).csv',function(error,brandData){
if (error) throw error;
const height = 668,width = 1346,top_n = 3,tickDuration = 3600, margin = {
top: 80,
right: 10,
bottom: 20,
left: 10
};
const svg = d3.select('.chart')
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
// console.log(svg);
let barPadding = (height-(margin.bottom+margin.top))/(top_n*5);
let title = svg.append('text')
.attr('class','title')
.attr("transform", "translate(20,60)")
.html('2002-2018年三大运营商营收PK');
let subTitle = svg.append('text')
.attr('class','subTitle')
.attr("transform", "translate(20,96)")
.html('单位:亿元');
let caption = svg.append('text')
.attr('class','caption')
// .attr('transform','translate(800,295)')
.attr('transform', function(){
return `translate(${width}, ${height+80})`
})
.style('text-anchor','end')
.html('数据来源:中国移动、中国电信、中国联通2002-2018年年报');
let year = 2002;
brandData.forEach(d => {
d.value = +d.value,
d.lastValue = +d.lastValue,
d.value = isNaN(d.value) ? 0 : d.value,
d.year = +d.year,
d.colour = d3.hsl(Math.random()*360,0.75,0.75)
});
let yearSlice = brandData.filter(d => d.year == year && !isNaN(d.value))
.sort((a,b) => b.value - a.value)
.slice(0,top_n);
yearSlice.forEach((d,i) => d.rank = i);
let x = d3.scale.linear()
.domain([0, d3.max(yearSlice, d => d.value)])
.range([margin.left, width-margin.right-65]);
let y = d3.scale.linear()
.domain([top_n, 0])
.range([height-margin.bottom, margin.top]);
let xAxis = d3.svg.axis().orient('top')
.scale(x)
.ticks(width > 500 ? 5:2)
.tickSize(-(height-margin.top-margin.bottom))
.tickFormat(d => d3.format(',')(d));
svg.append('g')
.attr('class', 'axis xAxis')
.attr('transform', function(d,i){
return `translate(20, ${margin.top+60})`
})
.call(xAxis)
.selectAll('.tick line')
.classed('origin', d => d == 0);
svg.selectAll('rect.bar')
.data(yearSlice, d => d.name)
.enter()
.append('rect')
.attr('class','bar')
.attr('transform',function(d){
return `translate(${x(0)+20}, ${y(d.rank)+90})`
})
// .attr('width',function(d){return x(d.value)-x(0)-1})
.attr('width',function(d){return x(0)})
.attr('height',function(d){return y(1)-y(0)-barPadding})
.style('fill',d => d.colour);
svg.selectAll('text.label')
.data(yearSlice, d => d.name)
.enter()
.append('text')
.attr('class','label')
.attr('transform',function(d){
return `translate(${x(0)-40}, ${y(d.rank)+5+((y(1)-y(0))/1)-20})`
})
.attr('text-anchor','end')
.html(d => d.name);
svg.selectAll('text.valueLabel')
.data(yearSlice, d => d.name)
.enter()
.append('text')
.attr('class','valueLabel')
// .attr('transform',function(d){
// return `translate(${x(d.value)+5}, ${y(d.rank)+5+((y(1)-y(0))/2)+1})`
// })
.attr('transform',function(d){
return `translate(${x(0)-30}, ${y(d.rank)+5+((y(1)-y(0))/1)-20})`
})
.text(d => d3.format(',.0f')(d.lastValue));
let yearText = svg.append('text')
.attr('class','yearText')
.attr('transform',function(d,i){
return `translate(${width-margin.right}, ${height+40})`
})
.style('text-anchor','end')
.html(~~year)
.call(halo, 10);
let ticker = setInterval(e => {
yearSlice = brandData.filter(d => d.year == year && !isNaN(d.value))
.sort((a,b) => b.value - a.value)
.slice(0,top_n);
console.log(yearSlice);
yearSlice.forEach((d,i) => d.rank = i);
x.domain([0, d3.max(yearSlice, d => d.value)]);
svg.select('.xAxis')
.transition()
.duration(tickDuration)
.ease('poly','1')
.call(xAxis);
let bars = svg.selectAll('.bar').data(yearSlice, d => d.name);
bars
.enter()
.append('rect')
.attr('class',d => `bar ${d.name.replace(/\s/g,'_')}`)
.attr('transform',function(d,i){
return `translate(${x(0)+10}, ${d => y(top_n+1)+5})`
})
.attr('width',d => x(d.value)-x(0)-1)
.attr('height',y(1)-y(0)-barPadding)
// .attrs({
// class: d => `bar ${d.name.replace(/\s/g,'_')}`,
// x: x(0)+1,
// width: d => x(d.value)-x(0)-1,
// y: d => y(top_n+1)+5,
// height: y(1)-y(0)-barPadding
// })
.style('fill', d => d.colour)
.transition()
.duration(tickDuration)
.ease('poly','1')
.attr('transform',function(d){
return `translate(${x(0)+20}, ${y(top_n+1)+90})`
});
bars
.transition()
.duration(tickDuration)
.ease('poly','1')
.attr('width',d => x(d.value)-x(0)-1)
.attr('transform',function(d){
return `translate(${x(0)+20}, ${y(d.rank)+90})`
});
bars
.exit()
.transition()
.duration(tickDuration)
.ease('poly','1')
.attr('width',d => x(d.value)-x(0)-1)
.attr('transform',function(d){
return `translate(0, ${y(top_n+1)+5})`
})
.remove();
let labels = svg.selectAll('.label').data(yearSlice, d => d.name);
labels
.enter()
.append('text')
.attr('class','label')
.attr('transform',function(d){
return `translate(${x(d.value)+10}, ${y(top_n+1)+5+((y(1)-y(0))/1)-20})`
})
.attr('text-anchor','end')
.attr('width',d => x(d.value)-x(0)-1)
.html(d => d.name)
.transition()
.duration(tickDuration)
.ease('poly','1')
.attr('transform',function(d){
return `translate(0, ${y(d.rank)+5+((y(1)-y(0))/1)-20})`
});
labels
.transition()
.duration(tickDuration)
.ease('poly','1')
.attr('transform',function(d){
return `translate(${x(d.value)+10}, ${y(d.rank)+5+((y(1)-y(0))/1)-20})`
});
labels
.exit()
.transition()
.duration(tickDuration)
.ease('poly','1')
.attr('transform',function(d){
return `translate(${x(d.value)+10}, ${y(top_n+1)+5})`
})
.remove();
let valueLabels = svg.selectAll('.valueLabel').data(yearSlice, d => d.name);
valueLabels
.enter()
.append('text')
.attr('class','valueLabel')
.attr('transform',function(d){
return `translate(${x(d.value)+30}, ${y(top_n+1)+5})`
})
// .text(d => d3.format(',.0f')(d.lastValue))
.transition()
.duration(tickDuration)
.ease('poly','1')
.attr('transform',function(d){
return `translate(0, ${y(d.rank)+5+((y(1)-y(0))/1)-20})`
});
valueLabels
.transition()
.duration(tickDuration)
.ease('poly','1')
.attr('transform',function(d){
return `translate(${x(d.value)+30}, ${y(d.rank)+5+((y(1)-y(0))/1)-20})`
})
.tween("text", function(d) {
let k = d3.interpolateRound(d.lastValue, d.value);
return function(t) {
this.textContent = d3.format(',')(k(t));
};
});
valueLabels
.exit()
.transition()
.duration(tickDuration)
.ease('poly','1')
.attr('transform',function(d){
return `translate(${x(d.value)+30}, ${y(top_n+1)+5})`
})
.remove();
yearText.html(~~year);
if(year == 2018){
clearInterval(ticker);
};
// year = d3.format('.1f')((+year+5) + 0.1);
year = year + 1;
},tickDuration);
});
</script>
</body>
</html>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js