D3 ver.4を使った四分木描画サンプル。
燃料給油所のデータは国土数値情報より。
license: mit |
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<html> | |
<head> | |
<style> | |
html, body { | |
margin: 0px; | |
padding: 0px; | |
width: 100%; | |
height: 100%; | |
} | |
svg { | |
width:980px; | |
height: 500px; | |
background-color:#ede4cd; | |
} | |
h1 { | |
color:#666; | |
} | |
</style> | |
</head> | |
<body> | |
<svg></svg> | |
<script src="//unpkg.com/d3@4.12.2/build/d3.min.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/topojson/3.0.0/topojson.min.js"></script> | |
<script> | |
const width = 980; | |
const height = 500; | |
const svg = d3.select("svg"); | |
const mapLayer = svg.append("g"); | |
const treeLayer = svg.append("g"); | |
const projection = d3.geoMercator(); | |
const path = d3.geoPath(); | |
const q = d3.queue(); | |
q | |
.defer(d3.json, "takasaki.topojson") | |
.defer(d3.json, "gasStation.geojson") | |
.await((error, maps2topo, point2geo) => { | |
const maps2geo = topojson.feature(maps2topo, maps2topo.objects.takasaki); | |
//読み込んだ地図データが描画領域に収まるように自動的にプロジェクションを調整する。 | |
projection.fitExtent([[0,0],[width, height]], maps2geo); | |
path.projection(projection); | |
drawMaps(maps2geo); | |
drawVoronoi(point2geo); | |
}); | |
function drawMaps(geojson){ | |
//地図表示 | |
const map = mapLayer.attr("id", "map") | |
.selectAll("path") | |
.data(geojson.features) | |
.enter() | |
.append("svg:path") | |
.attr("d", path) | |
.attr("fill", "#99ff99") | |
.attr("fill-opacity", 1) | |
.attr("stroke", "black"); | |
} | |
function drawVoronoi(geojson){ | |
const pointdata = geojson.features; | |
const positions = []; | |
pointdata.forEach(d => { | |
positions.push(projection(d.geometry.coordinates)); //位置情報をピクセル座標に変換する | |
}); | |
//母点表示 | |
treeLayer.selectAll(".point") | |
.data(positions) | |
.enter() | |
.append("circle") | |
.attr("class", "point") | |
.attr("transform", d => `translate(${d[0]}, ${d[1]})` ) | |
.attr("r", 2); | |
// 四分木生成 | |
var quadtree = d3.quadtree() | |
.extent([[-1, -1], [width + 1, height + 1]]) | |
.addAll(positions) | |
treeLayer.selectAll(".node") | |
.data(nodes(quadtree)) | |
.enter() | |
.append("rect") | |
.attr("class", "node") | |
.attr("fill", "none") | |
.attr("stroke", "black") | |
.attr("x", function(d) { return d.x0; }) | |
.attr("y", function(d) { return d.y0; }) | |
.attr("width", function(d) { return d.y1 - d.y0; }) | |
.attr("height", function(d) { return d.x1 - d.x0; }); | |
} | |
//rect要素で処理しやすいように、四分木の座標データを配列に変換する | |
function nodes(quadtree) { | |
var nodes = []; | |
quadtree.visit(function(node, x0, y0, x1, y1) { | |
node.x0 = x0, node.y0 = y0; | |
node.x1 = x1, node.y1 = y1; | |
nodes.push(node); | |
}); | |
return nodes; | |
} | |
</script> | |
</body> | |
</html> |