D3 ver.4を使ったGoogleMap上でのボロノイ図描画サンプル。
燃料給油所のデータは国土数値情報より。
license: mit |
<!DOCTYPE html> | |
<html> | |
<head> | |
<style type="text/css"> | |
html, body { | |
margin: 0px; | |
padding: 0px; | |
width: 100%; | |
height: 100%; | |
} | |
#map { | |
width:980px; | |
height: 500px; | |
} | |
.SvgOverlay { | |
position: relative; | |
width: 900px; | |
height: 600px; | |
} | |
.SvgOverlay svg { | |
position: absolute; | |
top: -4000px; | |
left: -4000px; | |
width: 8000px; | |
height: 8000px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="map"></div> | |
<script src="http://maps.googleapis.com/maps/api/js?sensor=false"></script> | |
<script src="//unpkg.com/d3@4.12.2/build/d3.min.js"></script> | |
<script> | |
d3.json('gasStation.geojson', main); | |
function main(pointjson) { | |
//Google Map 初期化 | |
const map = new google.maps.Map(document.getElementById('map'), { | |
zoom: 11, | |
mapTypeId: google.maps.MapTypeId.ROADMAP, | |
center: new google.maps.LatLng(36.322356, 139.013057), | |
}); | |
const overlay = new google.maps.OverlayView(); //OverLayオブジェクトの作成 | |
//オーバレイ追加 | |
overlay.onAdd = function () { | |
const layer = d3.select(this.getPanes().overlayLayer).append("div").attr("class", "SvgOverlay"); | |
const svg = layer.append("svg"); | |
const svgOverlay = svg.append("g").attr("class", "AdminDivisions"); | |
const pointLayer = svgOverlay.append("g"); | |
const voronoiLayer = svgOverlay.append("g"); | |
const markerOverlay = this; | |
const overlayProjection = markerOverlay.getProjection(); | |
//Google Mapの投影法設定 | |
const googleMapProjection = coordinates => { | |
const googleCoordinates = new google.maps.LatLng(coordinates[1], coordinates[0]); | |
const pixelCoordinates = overlayProjection.fromLatLngToDivPixel(googleCoordinates); | |
return [pixelCoordinates.x + 4000, pixelCoordinates.y + 4000]; | |
} | |
//再描画時に呼ばれるコールバック | |
overlay.draw = function () { | |
const width = svg.node().clientWidth; | |
const height = svg.node().clientHeight; | |
//母点位置情報 | |
const pointdata = pointjson.features; | |
//ピクセルポジション情報 | |
const positions = []; | |
pointdata.forEach(d => { | |
positions.push(googleMapProjection(d.geometry.coordinates)); //位置情報→ピクセル | |
}); | |
//母点表示 | |
const updatePoint = pointLayer.selectAll(".point").data(positions) | |
const enterPoint = updatePoint.enter() | |
.append("circle") | |
.attr("class", "point") | |
.attr("r", 2); | |
const point = updatePoint.merge(enterPoint) | |
.attr("transform", d => `translate(${d[0]}, ${d[1]})` ) | |
//ボロノイ変換関数 | |
const voronoi = d3.voronoi() | |
.extent([[-1, -1],[width+1, height+1]]); | |
//ボロノイ境界ポリゴンデータを生成する | |
const polygons = voronoi(positions).polygons(); | |
//境界表示 | |
voronoiLayer.selectAll(".cell").remove(); //一旦全消しして際appendする方がスムーズに地図が動いた。 | |
voronoiLayer.selectAll(".cell").data(polygons) | |
.enter() | |
.append("path") | |
.attr("class", "cell") | |
.attr("fill", "none") | |
.attr("stroke", "red") | |
.attr("d", d => { | |
if(!d) return null | |
return "M" + d.filter( df => df != null ).join("L") + "Z" | |
}) | |
}; | |
}; | |
//作成したSVGを地図にオーバーレイする | |
overlay.setMap(map); | |
}; | |
</script> | |
</body> | |
</html> |