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> |