index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
svg {
font: 16px sans-serif;
font-weight: bold;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.line0 {
fill: none;
stroke: rgba(255,0,0,0.85);
stroke-width: 5px;
stroke-linecap: round;
stroke-linejoin: round;
}
.line1 {
fill: none;
stroke: rgba(0,0,255,0.85);
stroke-width: 5px;
stroke-linecap: round;
stroke-linejoin: round;
}
.circle0, .circle1{
cursor: pointer;
}
#tooltip{
position: absolute;
top: 40px;
left: 80px;
display: none;
width: 160px;
height: auto;
padding: 10px;
background-color: white;
border-radius: 10px;
box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
pointer-events: none;
opacity: 0.85;
}
#tooltip p{
margin: 0;
font-family: sans-serif;
font-size: 16px;
line-height:20px;
}
#temp{
color: rgba(255,0,0,0.85);
}
#humid{
color: rgba(0,0,225,0.85);
}
</style>
</head>
<body>
<div id="tooltip">
<p><strong id="date"></strong></p>
<p><strong id="time"></strong></p>
<p>温度: <span id="temp"></span>℃</span></p>
<p>湿度: <span id="humid"></span>%</p>
</div>
<script src="http://code.jquery.com/jquery-2.1.0.min.js"></script>
<script src="http://d3js.org/d3.v3.js"></script>
<script>
//グラフクラス
var cGraph = function(){}
var timer;
//グラフの描画メソッド
cGraph.prototype.draw = function(){
var margin = {top: 20, right: 50, bottom: 30, left: 50},
//width = 960 - margin.left - margin.right,
width = innerWidth - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
//var parseDate = d3.time.format('%d-%b-%y').parse;
var parseDate = d3.time.format('%Y%m%d-%H%M%S').parse;
var formatDate = d3.time.format('%Y年%m月%d日');
var formatTime = d3.time.format('%H時%M分');
//グラフの幅
var x = d3.time.scale()
.range([0, width]);
//グラフの高さ
var y = d3.scale.linear()
.range([height, 0]);
//グラフの高さ
var y0 = d3.scale.linear()
.range([height, 0]);
//グラフの高さ
var y1 = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient('bottom')
.ticks(d3.time.months, 1)
.tickFormat(d3.time.format('%_m月'));
//.tickFormat(d3.time.format('%b'));
//.ticks(5)
//.ticks(10)
//.ticks(15)
//.tickFormat(d3.time.format('%Y/%m/%d'));
var yAxis = d3.svg.axis()
.scale(y)
.orient('left');
var yAxisLeft = d3.svg.axis().scale(y0)
.orient('left').ticks(5)
.tickFormat(function(d){return d + '℃'});
var yAxisRight = d3.svg.axis().scale(y1)
.orient('right').ticks(5)
.tickFormat(function(d){return d + '%'});
var line0 = d3.svg.line()
.x(function(d) { return x(d.date); })
//.y(function(d) { return y(d.temp); });
.y(function(d) { return y0(d.temp); });
var line1 = d3.svg.line()
.x(function(d) { return x(d.date); })
//.y(function(d) { return y(d.humid); });
.y(function(d) { return y1(d.humid); });
var svg = d3.select('body').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 + ')');
//CSV読み込み
d3.csv('data.csv', function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
//console.log(d.date);
//console.log(formatDate(d.date));
//d.date = formatDate(d.date);
d.temp = +d.temp;
d.humid = +d.humid;
});
x.domain(d3.extent(data, function(d) { return d.date; })).nice();
//y.domain(d3.extent(data, function(d) { return d.temp; }));
//y.domain(d3.extent(data, function(d) { return d.humid; }));
/*
y0.domain([0, d3.max(data, function(d) { return Math.max(d.temp); })]);
y1.domain([0, d3.max(data, function(d) { return Math.max(d.humid); })]);
*/
y0.domain([d3.min(data, function(d) { return Math.min(d.temp); }), d3.max(data, function(d) { return Math.max(d.temp); })]).nice();
y1.domain([d3.min(data, function(d) { return Math.min(d.humid); }), d3.max(data, function(d) { return Math.max(d.humid); })]).nice();
svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + height + ')')
.attr('fill','rgba(0,0,0,0.85)')
.call(xAxis);
//.append('text')
//.attr('transform', 'translate(-35, 20)')
//.text('日付');
//左y軸(温度)
svg.append('g')
.attr('class', 'y axis')
.attr('fill','rgba(255,0,0,0.85)')
//.call(yAxis)
.call(yAxisLeft);
/*
.append('text')
.attr('transform', 'translate(80, -20) rotate(0)')
.attr('y', 6)
.attr('dy', '.71em')
//.attr('dy', '5em')
.attr('fill','rgba(255,0,0,0.85)')
.style('text-anchor', 'end')
.text('温度 (℃)');
*/
//右y軸(湿度)
svg.append('g')
.attr('class', 'y axis')
.attr('transform', 'translate(' + (width-18) + ' ,0)')
.attr('fill','rgba(0,0,255,0.85)')
//.call(yAxis)
.call(yAxisRight);
/*
.append('text')
.attr('transform', 'translate(-5, -20) rotate(0)')
.attr('y', 6)
.attr('dy', '.71em')
//.attr('dy', '5em')
.attr('fill','rgba(0,0,255,0.85)')
.style('text-anchor', 'end')
.text('湿度 (%)');
*/
//グラフ温度
svg.append('path')
.datum(data)
.attr('class', 'line0')
.attr('d', line0)
.attr('opacity','0')
.transition()
.duration(500)
.attr('opacity','1.0');
//グラフ湿度
svg.append('path')
.datum(data)
.attr('class', 'line1')
.attr('d', line1)
.attr('opacity','0')
.transition()
.delay(500)
.duration(500)
.attr('opacity','1.0');
//横方向と縦方向のグリッド間隔を自動生成
var rangeX = d3.range(0, width-18, 20);
var rangeY = d3.range(0, height, 20);
// 縦方向のグリッドを生成
svg.selectAll('line.y')
.data(rangeY)
.enter()
.append('line')
.attr('x1', 0).attr('y1', function(d,i){return d; })
.attr('x2', width-18).attr('y2', function(d,i){return d ;});
// 横方向のグリッドを生成
svg.selectAll('line.x')
.data(rangeX)
.enter()
.append('line')
.attr('x1', function(d,i){return d;}).attr('y1', 0)
.attr('x2', function(d,i){return d;}).attr('y2', height);
// グリッドを描画
svg.selectAll('line')
.attr('stroke', 'rgba(0,0,0,0.3)')
.attr('shape-rendering', 'crispEdges');
svg.selectAll('circle.t')
.data(data)
.enter()
.append('circle')
.attr('cx', function(d, i) { return x(d.date); })
.attr('cy', function(d, i) { return y0(d.temp); })
.attr('r', 0)
.attr('class', 'circle0')
.style('fill','rgba(255,0,0,0.85)')
.on('click',function(d){
$('#tooltip').fadeIn();
$('#date').text(formatDate(d.date));
$('#time').text(formatTime(d.date));
$('#temp').text(d.temp);
$('#humid').text(d.humid);
clearTimeout(timer);
timer = setTimeout(function(){
$('#tooltip').fadeOut();
}, 5000);
})
.on('mouseover',function(d){
$('#tooltip').fadeIn();
$('#date').text(formatDate(d.date));
$('#time').text(formatTime(d.date));
$('#temp').text(d.temp);
$('#humid').text(d.humid);
clearTimeout(timer);
timer = setTimeout(function(){
$('#tooltip').fadeOut();
}, 5000);
})
.transition()
// .delay(function(d, i){
// return (i+1) * 1000;
// })
.duration(1000)
.attr('r', 6);
svg.selectAll('circle.h')
.data(data)
.enter()
.append('circle')
.attr('cx', function(d, i) { return x(d.date); })
.attr('cy', function(d, i) { return y1(d.humid); })
.attr('r', 0)
.attr('class', 'circle1')
.style('fill','rgba(0,0,255,0.85)')
.on('click',function(d){
$('#tooltip').fadeIn();
$('#date').text(formatDate(d.date));
$('#time').text(formatTime(d.date));
$('#temp').text(d.temp);
$('#humid').text(d.humid);
clearTimeout(timer);
timer = setTimeout(function(){
$('#tooltip').fadeOut();
}, 5000);
})
.on('mouseover',function(d){
$('#tooltip').fadeIn();
$('#date').text(formatDate(d.date));
$('#time').text(formatTime(d.date));
$('#temp').text(d.temp);
$('#humid').text(d.humid);
clearTimeout(timer);
timer = setTimeout(function(){
$('#tooltip').fadeOut();
}, 5000);
})
.transition()
.delay(500)
// .delay(function(d, i){
// return (i+1) * 1000;
// })
.duration(1000)
.attr('r', 6);
});
};
//DOMの構築
$(function(){
//グラフの初回描画
var graph = new cGraph();
graph.draw();
var timer;
timer = false;
//リサイズ時svgサイズ変更
$(window).resize(function() {
if (timer !== false) {
clearTimeout(timer);
}
timer = setTimeout(function() {
d3.select('svg').remove();
graph.draw();
}, 200);
});
});
</script>
</body>
</html>
data.csv
date,temp,humid
20130301-010101,12.54,38.63
20130401-010101,16.73,24.37
20130501-010101,18.53,20.52
20130515-010101,20.23,30.52
20130601-010101,18.21,20.63
20130615-010101,21.73,35.36
20130701-010101,24.84,30.73
20130706-010101,27.25,20.49
20130707-010101,23.26,40.29
20130709-010101,22.27,30.72
20130815-010101,32.65,30.72
20131010-010101,14.26,36.93