D3のInterpolation機能を使って、地図上のパスを滑らかに補完する。
Smooth pathのD3 ver.4版
Built with blockbuilder.org
license: mit |
D3のInterpolation機能を使って、地図上のパスを滑らかに補完する。
Smooth pathのD3 ver.4版
Built with blockbuilder.org
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Smooth path</title> | |
<style type="text/css"> | |
html, body { | |
width: 100%; | |
height: 100%; | |
margin: 0px; | |
padding: 0px; | |
} | |
#map1{ | |
float: right; | |
width: 50%; | |
height: 100%; | |
} | |
#map2{ | |
float: left; | |
width: 50%; | |
height: 100%; | |
} | |
.SvgOverlay { | |
position: relative; | |
width: 500px; | |
height: 500px; | |
} | |
.SvgOverlay svg { | |
position: absolute; | |
top: -4000px; | |
left: -4000px; | |
width: 8000px; | |
height: 8000px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="map1"></div> | |
<div id="map2"></div> | |
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyA8X-e3Naz_Pu50cP8bdDQUZukKrXMqDGs&libraries=visualization"></script> | |
<script src="//unpkg.com/d3@4.12.2/build/d3.min.js"></script> | |
<script src="index.js"></script> | |
</body> | |
</html> |
//Gmap スタイル指定 | |
const style_array_from_above_here = [ | |
{ | |
featureType: 'water', | |
elementType: 'all', | |
stylers: [ { hue: '#e9ebed' }, { saturation: -78 }, { lightness: 67 }, { visibility: 'simplified' } ] | |
}, | |
{ | |
featureType: 'landscape', | |
elementType: 'all', | |
stylers: [ { hue: '#ffffff' }, { saturation: -100 }, { lightness: 100 }, { visibility: 'simplified' } ] | |
}, | |
{ | |
featureType: 'road', | |
elementType: 'geometry', | |
stylers: [ { hue: '#bbc0c4' }, { saturation: -93 }, { lightness: 31 }, { visibility: 'simplified' } ] | |
}, | |
{ | |
featureType: 'poi', | |
elementType: 'all', | |
stylers: [ { hue: '#ffffff' }, { saturation: -100 }, { lightness: 100 }, { visibility: 'off' } ] | |
}, | |
{ | |
featureType: 'road.local', | |
elementType: 'geometry', | |
stylers: [ { hue: '#e9ebed' }, { saturation: -90 }, { lightness: -8 }, { visibility: 'simplified' } ] | |
}, | |
{ | |
featureType: 'transit', | |
elementType: 'all', | |
stylers: [ { hue: '#e9ebed' }, { saturation: 10 }, { lightness: 69 }, { visibility: 'on' } ] | |
}, | |
{ | |
featureType: 'administrative.locality', | |
elementType: 'all', | |
stylers: [ { hue: '#2c2e33' }, { saturation: 7 }, { lightness: 19 }, { visibility: 'on' } ] | |
}, | |
{ | |
featureType: 'road', | |
elementType: 'labels', | |
stylers: [ { hue: '#bbc0c4' }, { saturation: -93 }, { lightness: 31 }, { visibility: 'on' } ] | |
}, | |
{ | |
featureType: 'road.arterial', | |
elementType: 'labels', | |
stylers: [ { hue: '#bbc0c4' }, { saturation: -93 }, { lightness: -2 }, { visibility: 'simplified' } ] | |
} | |
]; | |
//Google Map 初期化 | |
const mapOpotion = { | |
zoom: 4, | |
mapTypeId: google.maps.MapTypeId.ROADMAP, | |
styles: style_array_from_above_here, | |
center: new google.maps.LatLng(24.3408621, 124.1614194) | |
}; | |
const map1 = new google.maps.Map(document.getElementById('map1'), mapOpotion); | |
const map2 = new google.maps.Map(document.getElementById('map2'), mapOpotion); | |
//データセット読み込み | |
d3.json('line.geojson', main); | |
function main(data) { | |
const drawAction = function() { | |
//オーバーレイ設定 | |
const layer = d3.select(this.getPanes().overlayLayer).append('div').attr('class', 'SvgOverlay'); | |
const svg = layer.append('svg'); | |
const layergroup = svg.append('g').attr('class', 'd3maplayear'); | |
const markerOverlay = this; | |
const overlayProjection = markerOverlay.getProjection(); | |
//Google Projection作成 | |
const googleMapProjection = d3.geoTransform({ | |
point: function(x, y) { | |
const d = overlayProjection.fromLatLngToDivPixel(new google.maps.LatLng(y, x)); | |
this.stream.point(d.x + 4000, d.y + 4000); | |
} | |
}); | |
//パスジェネレーター作成 | |
const path = d3.geoPath().projection(googleMapProjection); | |
const interpolate = d3.line().x((d) => d[0]).y((d) => d[1]).curve(d3.curveBasis); | |
const smoothPath = (pstr) => { | |
const sp = path(pstr).replace(/M|Z/, '').split('L').map((d) => d.split(',')); | |
return interpolate(sp); | |
}; | |
//オーバーレイ描画イベント | |
this.draw = draw; | |
function draw() { | |
const currentMap = this.getMap(); | |
const line = layergroup.selectAll('path').data(data.features); | |
line.attr('d', (d) => { | |
if (currentMap == map2) return smoothPath(d); | |
return path(d); | |
}); | |
const enter = line.enter().append('path'); | |
line | |
.merge(enter) | |
.attr('d', (d) => { | |
if (currentMap == map2) return smoothPath(d); | |
return path(d); | |
}) | |
.attr('stroke', 'orange') | |
.attr('stroke-width', 4) | |
.attr('fill', 'none'); | |
} | |
}; | |
const overlay1 = new google.maps.OverlayView(); //OverLayオブジェクトの作成 | |
const overlay2 = new google.maps.OverlayView(); //OverLayオブジェクトの作成 | |
overlay1.onAdd = drawAction; | |
overlay2.onAdd = drawAction; | |
//作成したSVGを地図にオーバーレイする | |
overlay1.setMap(map1); | |
overlay2.setMap(map2); | |
} |
{ | |
"type": "FeatureCollection", | |
"features": [ | |
{ | |
"type": "Feature", | |
"properties": {}, | |
"geometry": { | |
"type": "LineString", | |
"coordinates": [ | |
[ | |
140.80078125, | |
45.644768217751924 | |
], | |
[ | |
134.47265625, | |
41.96765920367816 | |
], | |
[ | |
138.25195312499997, | |
40.84706035607122 | |
], | |
[ | |
131.66015625, | |
38.34165619279595 | |
], | |
[ | |
134.12109375, | |
37.37015718405753 | |
], | |
[ | |
125.33203125, | |
31.57853542647338 | |
], | |
[ | |
130.166015625, | |
27.371767300523047 | |
], | |
[ | |
125.94726562499999, | |
18.646245142670608 | |
], | |
[ | |
134.560546875, | |
12.039320557540584 | |
], | |
[ | |
141.85546875, | |
14.008696370634658 | |
], | |
[ | |
150.29296875, | |
20.632784250388028 | |
], | |
[ | |
148.0078125, | |
14.093957177836236 | |
], | |
[ | |
152.138671875, | |
16.804541076383455 | |
], | |
[ | |
151.34765625, | |
13.239945499286312 | |
], | |
[ | |
153.193359375, | |
14.264383087562662 | |
], | |
[ | |
153.6328125, | |
11.78132529611229 | |
] | |
] | |
} | |
} | |
] | |
} |