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/[email protected]/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> |