2016-12-10,11 Code for Saga データの見える化による地域課題解決ハッカソン@佐賀大学の成果です。
開発:Timeflyers(タイムフライヤーズ) Tatsuo Sugimoto, Shujiro Matsunaga, Satoshi Tsutsui, Kosei Hara
データソース:あそぼーさが, 気象庁, Mapbox
xxxxxxxxxx
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.4.0/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.2/leaflet.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.2/leaflet.css"/>
<link href="https://fonts.googleapis.com/css?family=PT+Sans:700" rel="stylesheet">
<style>
@font-face {
font-family: 'weathericons';
src: url('https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.9/font/weathericons-regular-webfont.eot');
src: url('https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.9/font/weathericons-regular-webfont.eot?#iefix') format('embedded-opentype'),
url('https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.9/font/weathericons-regular-webfont.woff2') format('woff2'),
url('https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.9/font/weathericons-regular-webfont.woff') format('woff'),
url('https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.9/font/weathericons-regular-webfont.ttf') format('truetype'),
url('https://cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.9/font/weathericons-regular-webfont.svg#weather_iconsregular') format('svg');
font-weight: normal;
font-style: normal;
}
body {
font-family: 'PT Sans', sans-serif;
margin: 0;
padding: 0;
background: #000;
}
#months, #high, #rain, #snow {
position: absolute;
top: 0;
height: 100%;
z-index: 1000;
}
#months {
left: 0;
width: 80px;
}
#high {
left: 80px;
}
#rain {
left: 110px;
}
#snow {
left: 140px;
display: none;
}
.month, .high, .rain, .snow {
display: -webkit-flex;
display: flex;
-webkit-align-items: center;
align-items: center;
-webkit-justify-content: center;
justify-content: center;
height: calc((100% - 30px)/ 12);
user-select: none;
cursor: pointer;
}
.month {
background-color: #222;
color: #fff;
text-align: center;
font-weight: bold;
vertical-align: middle;
cursor: pointer;
}
.month:nth-child(odd) {
background-color: #333;
}
.month[month="0"], .high[month="0"], .rain[month="0"], .snow[month="0"] {
height: 30px;
font-family: 'weathericons';
/*border-radius: 15px;*/
}
.month[month="0"] {
color: hsl(0, 0%, 50%);
}
.high[month="0"] {
color: #ff8200;
}
.rain[month="0"] {
color: #0af;
}
.high, .rain {
font-family: 'weathericons';
color: rgba(255, 255, 255, 0.75);
}
.month:hover {
background-color: #601818;
}
.month.on {
background-color: #822;
}
.high, .rain, .snow {
width: 30px;
}
.high.on, .rain.on, .snow.on {
width: 60px;
color: #000;
}
.rain.on {
margin-left: 30px;
}
#map {
margin-left: 140px;
width:calc(100% - 140px);
height:100%;
}
#logo {
font-family: 'PT Sans', sans-serif;
font-size: 28px;
text-align: right;
text-shadow: white 1px 1px 0px, white -1px 1px 0px,
white 1px -1px 0px, white -1px -1px 0px;
}
.desc {
background-color: rgba(255, 255, 255, 0.75);
font-size: 14px;
font-weight: bold;
line-height: 175%;
border-radius: 4px;
padding: 4px;
border: 1px solid #fff;
}
#map .leaflet-layer {
/*filter: hue-rotate(180deg);*/
}
</style>
<body>
<div>
<div id="months"></div>
<div id="high"></div>
<div id="rain"></div>
<div id="snow"></div>
<div id="map"></div>
</div>
<script>
var titleStr = "Saga Event Time Machine";
var descStr = `佐賀のイベント情報をマップに表示します。<br />
イベント情報をみたい月を選択してください。`;
var currentMonth = 1;
var markers = [];
var eventData;
var weatherData;
var map = L.map('map').setView([33.25, 130.25], 11);
L.tileLayer(
'https://api.mapbox.com/styles/v1/mapbox/light-v9/tiles/256/{z}/{x}/{y}?access_token=pk.eyJ1Ijoic3VnaTIwMDAiLCJhIjoiY2l3anY3cWgzMDAzcTJ0cDJpdG1sZGZ3biJ9.kmev1_-7umt2LZrAMUJiyA',{
// 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
// attribution: 'Map data © <a href="https://openstreetmap.org">OpenStreetMap</a>',
attribution: '<a href="https://www.mapbox.com/">Mapbox</a>',
maxZoom: 18,
}).addTo(map);
L.control.scale({imperial:false}).addTo(map);
var logo = L.control({position: 'topright'});
logo.onAdd = function(map) {
var div = L.DomUtil.create('div', 'logo');
// div.innerHTML= "<img src='logo.png'/>";
div.innerHTML = ["<div id='logo'>", titleStr, "</div><div class='desc'>", descStr, "</div>"].join('');
return div;
};
logo.addTo(map);
// d3.select('.leaflet-top.leaflet-right')
// .append('div')
// .attr('class', 'leaflet-control-attribution leaflet-control')
// .text('test');
var months = d3.range(13); // 0 .. 12
// months.unshift(0);
// set month
d3.select('#months').selectAll('div.month')
.data(months)
.enter()
.append('div')
.attr('class', 'month')
.attr('month', function(d){return d;})
// .style('background-color', function(d,i){if(i%2==0){return '#333';}})
.text(function(d){
if (d == 0) {
return '';//'\f092';
}
return d + '月';
})
.on('click', function(){
var e = d3.select(this);
var m = e.attr('month');
updateMonth(m);
});
// set high
d3.select('#high').selectAll('div.high')
.data(months)
.enter()
.append('div')
.attr('class', 'high')
.attr('month', function(d){return d;});
// set rain
d3.select('#rain').selectAll('div.rain')
.data(months)
.enter()
.append('div')
.attr('class', 'rain')
.attr('month', function(d){return d;});
// set snow
d3.select('#snow').selectAll('div.snow')
.data(months)
.enter()
.append('div')
.attr('class', 'snow')
.attr('month', function(d){return d;});
var highColor = d3.scaleSequential(d3.interpolateOranges);
var rainColor = d3.scaleSequential(d3.interpolateBlues);
var snowColor = d3.scaleSequential(d3.interpolateBlues);
d3.csv('weather.csv', function(data) {
data.forEach(function(d){
d.month = +d.month;
d.high = +d.high;
d.rain = +d.rain;
d.snow = +d.snow;
d.rainday = +d.rainday;
d.snowday = +d.snowday;
});
highColor.domain(d3.extent(data, function(d){return d.high;}));
rainColor.domain(d3.extent(data, function(d){return d.rainday;}));
snowColor.domain(d3.extent(data, function(d){return d.snowday;}));
data.unshift({
month: 0,
high: 0,
rain: 0,
snow: 0,
rainday: 0,
snowday: 0
});
weatherData = data;
var thermometerStr = '';
var raindropStr = '';
var snowflakeStr = '';
var hotStr = '';
d3.selectAll('div.high')
.data(data)
.text(function(d,i){
if (i == 0) { return thermometerStr; }
else if (d.high >= 30.0) {
// return hotStr;
} else {
return ''; //d.high;
}
})
.style('background-color', function(d){ return highColor(d.high); });
d3.selectAll('div.rain')
.data(data)
.text(function(d,i){
if (i == 0) { return raindropStr; }
else if (d.snowday > 0){
return snowflakeStr;
} else {
return '';
}
})
.style('background-color', function(d){ return rainColor(d.rainday); });
d3.selectAll('div.snow')
.data(data)
// .text(function(d){return d.rain;})
.text(function(d,i){
if (i == 0) { return ''; }
return d.snowday;
})
.style('background-color', function(d){ return snowColor(d.snowday); })
.style('color', function(d, i){
if (i == 0) {
return '#000';
}
return rainColor(d.snowday);
});
});
d3.csv('events.csv', function(data){
eventData = data;
updateMonth(currentMonth);
});
function updateMonth(month) {
currentMonth = month;
var monthWeatherData = weatherData[currentMonth];
var monthEventData = eventData.filter(function(d){
return (d.month == currentMonth);
})
d3.select('#map .leaflet-layer')
.style('filter', 'hue-rotate(' + (currentMonth / 12.0 * 360.0) + 'deg)')
d3.selectAll('div.month').classed('on', false);
// d3.selectAll('div.high').classed('on', false);
// d3.selectAll('div.rain').classed('on', false);
d3.select('div.month[month="'+currentMonth+'"]').classed('on', true);
// d3.select('div.high[month="'+currentMonth+'"]').classed('on', true);
// d3.select('div.rain[month="'+currentMonth+'"]').classed('on', true);
// set desc
var weatherStr = `${ currentMonth }月は${ monthEventData.length }件のイベントが登録されています。<br />
平均最高気温は${ monthWeatherData.high }℃です。<br />
ひと月のあいだに${ d3.format('d')(monthWeatherData.rainday) }日ほど雨が降りそうです。`;
if (monthWeatherData.snowday > 0) {
weatherStr += `<br />
また、雪が降ることもあります。`;
}
if (monthWeatherData.high >= 30) {
weatherStr += `<br />
とても暑いので屋外の活動に注意してください。`;
}
if (currentMonth === '0') {
weatherStr = descStr;
}
d3.select('div.desc').html(weatherStr);
markers.forEach(function(element, index, array){
map.removeLayer(element);
});
markers = [];
monthEventData.forEach(function(element, index, array){
var marker = L.marker([element.latitude, element.longtitude]).addTo(map);
marker.bindPopup(`${ element.start } – ${ element.end }<br />
<strong>${ element.title }</strong><br />
${ element.place }`);
markers.push(marker);
});
}
</script>
</body>
https://cdnjs.cloudflare.com/ajax/libs/d3/4.4.0/d3.min.js
https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.2/leaflet.js
https://d3js.org/d3-scale-chromatic.v1.min.js