Skip to content

Instantly share code, notes, and snippets.

@da1fujimoto
Last active December 12, 2019 02:45
Show Gist options
  • Save da1fujimoto/d15b32e238686519fd1b7172f97ddde3 to your computer and use it in GitHub Desktop.
Save da1fujimoto/d15b32e238686519fd1b7172f97ddde3 to your computer and use it in GitHub Desktop.
D3 Bar Chart Demo v5
license: mit
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="description" content="">
<title></title>
<!-- Custom CSS -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<div><button>Randomise</button></div>
<div class="canvas"></div>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.9.1/d3-tip.min.js"></script>
<script src="main.js"></script>
</body>
const svg = d3.select('.canvas').append('svg')
.attr('width', 700)
.attr('height', 400);
let dataset = [{
date: "2019/1/1",
value1: 70,
value2: 10
},
{
date: "2019/2/1",
value1: 65.1,
value2: 2.5
},
{
date: "2019/3/1",
value1: 81.6,
value2: 5.1
},
{
date: "2019/4/1",
value1: 55.3,
value2: 2.6
},
{
date: "2019/5/1",
value1: 30.6,
value2: 2.9
},
{
date: "2019/6/1",
value1: 55.4,
value2: 3.3
},
{
date: "2019/7/1",
value1: 72.9,
value2: 12.4
},
{
date: "2019/8/1",
value1: 82.2,
value2: 8.3
},
{
date: "2019/9/1",
value1: 66.4,
value2: 1.3
},
{
date: "2019/10/1",
value1: 73.3,
value2: 1.9
},
{
date: "2019/11/1",
value1: 25.4,
value2: 9.2
},
{
date: "2019/12/1",
value1: 57.4,
value2: 5.6
}
];
const margin = {
top: 50,
right: 30,
bottom: 50,
left: 30
};
const width = svg.attr('width') - margin.left - margin.right;
const height = svg.attr('height') - margin.top - margin.bottom;
const timeparser = d3.timeParse('%Y/%m/%d');
const format = d3.timeFormat('%Y/%m');
const g = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);
dataset = dataset.map(d => {
return {
date: timeparser(d.date),
value1: d.value1,
value2: d.value2
}
});
// scaler
const x = d3.scaleBand()
.range([0, width])
.domain(dataset.map(d => d.date))
.paddingInner(0.3)
.paddingOuter(0.3);
const y = d3.scaleLinear()
.range([height, 0])
.domain([0, 100]);
const xAxisCall = d3.axisBottom(x)
.tickFormat(format);
const yAxisCall = d3.axisLeft(y);
const xAxis = g.append('g')
.attr('class', 'axis axis-x')
.attr('transform', `translate(0, ${height})`)
.call(xAxisCall);
const yAxis = g.append('g')
.attr('class', 'axis axis-y')
.call(yAxisCall);
const rectGroup = g.append('g');
const tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(d => `<p><strong>${format(d.date)}</strong></p><p>${d.value1}%</p><p>${d.value2}%</p>`);
g.call(tip);
const getRandom = (min, max) => {
return ~~(Math.random() * (max + 1 - min) + min);
};
const dataRandomize = () => {
return dataset.map(d => {
return {
date: d.date,
value1: getRandom(20, 79),
value2: getRandom(0, 19)
};
});
};
const update = data => {
const rect = rectGroup.selectAll('.bar-value1')
.data(data);
const rect2 = rectGroup.selectAll('.bar-value2')
.data(data);
rect.enter()
.append('rect')
.attr('class', 'bar bar-value1')
.attr('width', x.bandwidth())
.attr('x', d => x(d.date))
.attr('y', d => y(d.value2))
.attr('height', 0)
.style('fill', '#4c94ff')
.style('opacity', 0)
.on('mouseover', (d, i, n) => tip.show(d, n[i]))
.on('mouseout', tip.hide)
.transition()
.duration(700)
.delay((d, i) => i * 30 + 100)
.ease(d3.easeExpInOut)
.attr('y', d => y(d.value1) - (height - y(d.value2)))
.attr('height', d => height - y(d.value1))
.style('opacity', 1);
rect2.enter()
.append('rect')
.attr('class', 'bar bar-value2')
.attr('width', x.bandwidth())
.attr('x', d => x(d.date))
.attr('y', height)
.attr('height', 0)
.style('fill', '#0061e0')
.style('opacity', 0)
.on('mouseover', (d, i) => {
const selRec1 = rectGroup.selectAll('.bar-value1').nodes()[i];
tip.show(d, selRec1);
})
.on('mouseout', tip.hide)
.transition()
.duration(700)
.delay((d, i) => i * 30)
.ease(d3.easeExpInOut)
.attr('y', d => y(d.value2))
.attr('height', d => height - y(d.value2))
.style('opacity', 1);
rect.transition()
.duration(700)
.delay((d, i) => i * 30 + 100)
.ease(d3.easeExpInOut)
.attr('y', d => y(d.value1) - (height - y(d.value2)))
.attr('height', d => height - y(d.value1));
rect2.transition()
.duration(700)
.delay((d, i) => i * 30)
.ease(d3.easeExpInOut)
.attr('y', d => y(d.value2))
.attr('height', d => height - y(d.value2));
};
update(dataset);
d3.select('button')
.on('click', () => {
dataset = dataRandomize();
update(dataset);
});
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 10px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
font-size: 10px;
}
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment