上一篇: 力导向图 https://blog.csdn.net/zjw_python/article/details/98617650
下一篇: 盒须图 https://blog.csdn.net/zjw_python/article/details/99581418
代码结构和初始化画布的Chart对象介绍,请先看 https://blog.csdn.net/zjw_python/article/details/98182540
本图完整的源码地址: https://github.com/zjw666/D3_demo/tree/master/src/map/china
1 图表效果
2 数据
在D3中,地图所使用的数据格式为TopoJSON
,一般获得这种数据格式步骤为,去网络上下载公开的地图数据(例如natureEarth等网站),使用GDAL提供的ogr2ogr
工具,将shape
类型文件转换为GeoJSON
或TopoJSON
。除此之外,一些便捷的网站提供指定地区TopoJSON格式数据的下载,例如这里。总之,获取地图数据并转化为指定格式是一件不容易的事。
在本文的源码中,提供了中国地图的TopoJSON数据
3 关键代码
导入数据TopoJSON格式的地图数据
d3.json('./chinaTopo.json').then(function(data){
....
建立投影模型,将球面坐标转换为平面坐标
/* ----------------------------尺度转换------------------------ */
const projection = d3.geoMercator()
.center([104, 38])
.scale(355)
.translate([chart.getBodyWidth()/2, chart.getBodyHeight()/2])
选取特征元素,这里需要用到topojson
库
/* ----------------------------准备数据------------------------ */
const handleData = topojson.feature(data, data.objects['中国']).features;
运用d3.geoPath
渲染地图轮廓
扫描二维码关注公众号,回复:
9300418 查看本文章
/* ----------------------------渲染地图轮廓------------------------ */
chart.renderMap = function(){
const path = d3.geoPath()
.projection(projection);
let map = chart.body().selectAll('path')
.data(handleData);
map.enter()
.append('path')
.attr('class', (d) => 'provinces ' + d.properties.name)
.merge(map)
.attr('d', path)
.attr('fill', (d,i) => chart._colors(i % 10));
map.exit()
.remove();
}
渲染省市中心
/* ----------------------------渲染省市中心点------------------------ */
chart.renderCenter = function(){
handleData.pop(); //去除数组最后一个非省市元素
chart.body().selectAll('circle')
.data(handleData)
.enter()
.append('circle')
.attr('class', (d) => 'center-' + d.properties.name)
.attr('cx', (d) => {
return projection(d.properties.center)[0];
})
.attr('cy', (d) => {
return projection(d.properties.center)[1];
})
.attr('r', 2)
.attr('fill', 'red')
.attr('stroke', 'black');
}
绑定鼠标交互事件,当鼠标悬停在指定区域的时候显示省信息
/* ----------------------------绑定鼠标交互事件------------------------ */
chart.addMouseOn = function(){
//防抖函数
function debounce(fn, time){
let timeId = null;
return function(){
const context = this;
const event = d3.event;
timeId && clearTimeout(timeId)
timeId = setTimeout(function(){
d3.event = event;
fn.apply(context, arguments);
}, time);
}
}
d3.selectAll('.provinces')
.on('mouseover', function(d){
const e = d3.event;
const position = d3.mouse(chart.svg().node());
d3.select(e.target)
.attr('fill', config.hoverColor);
chart.svg()
.append('text')
.classed('tip', true)
.attr('x', position[0]+5)
.attr('y', position[1])
.attr('fill', config.textColor)
.text(d.properties.name);
})
.on('mouseleave', function(d,i){
const e = d3.event;
d3.select(e.target)
.attr('fill', chart._colors(i%10));
d3.select('.tip').remove();
})
.on('mousemove', debounce(function(){
const position = d3.mouse(chart.svg().node());
d3.select('.tip')
.attr('x', position[0]+5)
.attr('y', position[1]-5);
}, 6)
);
}