D3を使って2点間の緯度経度を補完し、トランジションさせる。
Built with blockbuilder.org
license: mit |
D3を使って2点間の緯度経度を補完し、トランジションさせる。
Built with blockbuilder.org
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"/> | |
<title></title> | |
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.css"/> | |
<style> | |
html, body { | |
padding: 0px; | |
margin: 0px; | |
} | |
html, body, #map { | |
width: 100%; | |
height: 100%; | |
} | |
.tick line { | |
stroke-dasharray: 2 2 ; | |
stroke: #ccc; | |
} | |
#interface { | |
position: absolute; | |
top:10px; | |
left: 40px; | |
width: 308px; | |
height: 28px; | |
padding: 4px; | |
background-color: white; | |
z-index: 9999; | |
} | |
#interface button { | |
color:white; | |
background-color: blue; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="interface"> | |
<select id="ease-type"> | |
<option>easeLinear</option> | |
<option>easeElastic</option> | |
<option>easeBounce</option> | |
<option>easeSin</option> | |
<option>easeQuad</option> | |
<option>easeCubic</option> | |
<option>easePoly</option> | |
<option>easeCircle</option> | |
<option>easeExp</option> | |
<option>easeBack</option> | |
</select> | |
<input id="duration" type="number" value="1500"></input> | |
<button id="startBtn">transition</button> | |
</div> | |
<div id="map"></div> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/4.1.1/d3.min.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet-src.js"></script> | |
<script> | |
!(function(){ | |
"use strict" | |
var map //leaflet obj | |
var soruce = { | |
lat:36.3219088, | |
lng:139.0032936, | |
} | |
var current = { | |
lat:soruce.lat, | |
lng:soruce.lng | |
} | |
var target = { | |
lat:35.6811673, | |
lng:139.76705160000006, | |
} | |
var data = {soruce:soruce, current:current, target:target} | |
main(); | |
function main(data) { | |
addLmaps() | |
renderCircle() | |
} | |
function addLmaps() { | |
//Leaflet初期設定 | |
map = L.map('map').setView([36.058829 , 139.50993900000003], 9); | |
L.tileLayer('https:\/\/a.tiles.mapbox.com\/v4\/mapbox.streets\/{z}\/{x}\/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NDg1bDA1cjYzM280NHJ5NzlvNDMifQ.d6e-nNyBDtmQCVwVNivz7A', { | |
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' | |
}).addTo(map); | |
//Leafletに用意されたsvgを使う | |
map._initPathRoot(); | |
} | |
//位置→座標変換 | |
function projectPoint(x, y) { | |
var point = map.latLngToLayerPoint(new L.LatLng(y, x)); | |
return point; | |
} | |
function renderCircle() { | |
var svg = d3.select("#map").select("svg"); | |
var circle = svg.append("circle") | |
.datum(data) | |
.attr("stroke", "gray") | |
.attr("fill", "red") | |
.attr("fill-opacity", 0.6) | |
.attr("r", 20) | |
.on("click", function(d){ | |
moveTween(d.soruce, d.target, 3000, d3.easeBounce) | |
}) | |
map.on("viewreset", update); | |
update(); | |
//サークルを地図上でトランジションさせる。 | |
d3.select("#startBtn").on("click", function(){ | |
var easeType = document.querySelector("#ease-type").value; | |
var duration = document.querySelector("#duration").value; | |
reset(); | |
moveTween(data.soruce, data.target, duration, d3[easeType]); | |
}) | |
//緯度経度を画面座標に変換してcircleの位置を移動する | |
function update() { | |
circle.attr("transform", function(d){ | |
var p = projectPoint(d.current.lng, d.current.lat); | |
return "translate("+[p.x,p.y]+")"; | |
}); | |
} | |
//位置をリセット | |
function reset(){ | |
data.current.lat = data.soruce.lat; | |
data.current.lng = data.soruce.lng; | |
circle.datum(data); | |
update(); | |
} | |
//2点間の緯度経度を補完する | |
function moveTween(soruce, target, duration, ease) { | |
if(!ease) ease = d3.easeLinear; | |
var scale = d3.scaleLinear().domain([0, duration]).range([0, 1]).clamp(true); | |
var interpolateLat = d3.interpolate(soruce.lat, target.lat); | |
var interpolateLng = d3.interpolate(soruce.lng, target.lng); | |
var t = d3.timer(function(elapsed) { | |
var c = ease(scale(elapsed)); | |
data.current.lat = interpolateLat(c); | |
data.current.lng = interpolateLng(c); | |
circle.datum(data); | |
update() | |
if (elapsed > duration) t.stop(); | |
}, 100); | |
} | |
} | |
}()); | |
</script> | |
</body> | |
</html> |