先说一下D3有很多的地图投影方法,但是很遗憾的是没有拿到比较细化的世界地图的json数据,所以以常见的投影方式做了一个例子。
安利一下获取中国地图的json数据:http://datav.aliyun.com/tools/atlas/#&lat=33.521903996156105&lng=104.29849999999999&zoom=4
附上世界地图的json数据:
https://download.youkuaiyun.com/download/m0_37777005/11219133
要积分的,别骂我,因为穷。。。
老样子,先看截图。
先看中国地图的实现。
import * as d3 from 'd3';
export default function mapEasy(id, data) {
const width = 800;
const height = 800;
// 画布
const svg = d3
.select(id)
.append('svg')
.attr('width', width)
.attr('height', height);
//敲黑板:投影方式。
const projection = d3
.geoMercator()
.center([107, 31])
.scale(600)
.translate([width / 2, height / 2]);
const path = d3.geoPath().projection(projection);
const color = d3.schemeCategory10;
svg
.selectAll('g')
.data(data.features)
.enter()
.append('g')
.append('path')
.attr('d', path)
.attr('stroke', '#000')
.attr('stroke-width', 1)
.attr('opacity', 0.6)
.attr('fill', function(d, i) {
return color[i % 10];
})
.on('mouseover', function() {
d3.select(this).attr('opacity', 1);
})
.on('mouseout', function() {
d3.select(this).attr('opacity', 0.6);
});
// 添加坐标
svg
.selectAll('g')
.append('text')
.attr('font-size', 12)
.attr('text-anchor', 'middle')
.attr('x', d => {
const position = projection(d.properties.centroid || [0, 0]);
return position[0];
})
.attr('y', d => {
const position = projection(d.properties.centroid || [0, 0]);
return position[1];
})
.attr('dy', d => {
//这里为什么这么写呢,因为澳门和香港重合了,挤到一起了。
if (d.properties.name === '澳门') {
return 15;
}
})
.text(d => d.properties.name);
}
然后我们来看球形地图和世界地图的
import * as d3 from 'd3';
export default function mapFilter(id, data) {
//...省略一样的初始步骤
const sphere = {
type: 'Sphere',
};
const projection = d3
.geoOrthographic()//球形投影
.fitExtent([[700, 1], [width, height]], sphere)
.translate([width / 2, height / 4])
.precision(0.1);
const projection2 = d3
.geoEqualEarth()//平面的投影,这里方法很多,可以到官方文档上看看,然后进行替换试一下。有很多不一样的投影呈现出来。
.translate([width / 2, height / 1.3])
.scale(100);
const path = d3.geoPath().projection(projection);
const path2 = d3.geoPath().projection(projection2);
const color = d3.schemeCategory10;
const gridGenerator = d3.geoGraticule();//经纬线
//画经纬线
svg
.append('g')
.attr('class', 'grid')
.append('path')
.datum(gridGenerator)
.attr('class', 'graticule')
.attr('d', path)
.attr('opacity', 0.5)
.attr('stroke-width', '1px')
.attr('stroke', '#fff');
//球形
svg
.selectAll('.map')
.data(data.features)
.enter()
.append('g')
.append('path')
.attr('d', path)
.attr('stroke', '#000')
.attr('stroke-width', 1)
.attr('opacity', 0.6)
.attr('fill', function(d, i) {
return color[i % 10];
});
//mark:球形地图其实可以加一个mouse的拖拽事件,大概思路应该通过改变projection的rotate这样就可以转动了。如果有哪位大佬实现了,可以教教我。
//平面的
svg
.selectAll('.geomap')
.data(data.features)
.enter()
.append('g')
.attr('class', 'geomap')
.append('path')
.attr('d', path2)
.attr('fill', function(d, i) {
return color[i % 10];
});
}