用的json文件来源于阿里,实现了简单的交互,即鼠标放在省份上,可以显示该省的现有确诊量。注意领土完整性
v7版本用的是geoMercator()和geoPath;v3版本用的是geo.mercator()和geo.path()。总归还是版本的坑很容易踩
center决定了地图投影的位置,scale决定了地图投影的大小。
projection() 是设定生成器的投影函数,把上面定义的投影传入即可。以后,当使用此生成器计算路径时,会自己加入投影的影响。
<script>
//定义地图的投影
var projection = d3.geoMercator()
.center([100, 38])
.scale(920)
.translate([width/2, height/2]);
//定义地形路径生成器
var geoPath = d3.geoPath()
.projection(projection); //设定投影
</script>
因为地图里的省份容易互相重叠(比如香港、广东和澳门),所以在texts里用transform进行了细微的人工调整。
<script>
var texts = svg.selectAll(".texts")
.data(data.features)
.enter()
.append("text")
.attr("class", "texts")
.text((d,i)=>d.properties.name)
.attr("text-anchor","middle")
.attr("transform", function(d) {
var centroid = geoPath.centroid(d),
x = centroid[0],
y = centroid[1];
if((d.properties.name=="澳门")||(d.properties.name=="安徽省")
||(d.properties.name=="河北省"))
y=y+15;
if((d.properties.name=="香港"))
y=y+10;
//return "translate(" + x + ", " + y + ")";
return `translate(${x},${y})`;
})
.attr('fill','999')
.attr("font-size","8px");
});
</script>
南海部分是直接通过通过img src放到html网页上的。本来想尝试fill到svg的rect里,后来发现不是很方便(意思是我不会)
<img src="南海.png" width="150"/>
tooltip的话之前的博客里也写过,v7是event.pageX,v3是d3.event.pageX
<script>
tooltip.html("现有确诊量:"+t)
.style("visibility","visible")
.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY -10) + "px")
</script>
全部代码:
<html>
<head>
<meta charset="utf-8">
<title>中国数据地图</title>
<style>
.tooltip {
position: absolute;
pointer-events: none;
font-size: 8px;
opacity: 1;
}
.southchinasea {
stroke: black;
stroke-width: 1px;
fill: red;
}
img{
border: 0.3px solid black;
}
</style>
</head>
<body>
<script src="d3.v7.js" charset="utf-8"></script>
<script>
var width=(window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth)*0.8;
var height=(window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight)*0.98;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var covid=[591,113,2,0,1,5,238,0,2330,7,392,0,102,2,8,150,0,7,103,15,0,5,212,1,12,0,2,0,16,0,0,260761,0,0,1371462]
var linear = d3.scaleLinear()
.domain([990,90000])
.range([0,255]);
var color=['#fff7ec','#fee8c8','#fdd49e','#fdbb84',
'#fc8d59','#ef6548','#d7301f','#b30000','rgb(153, 0, 0)'];
//定义地图的投影
var projection = d3.geoMercator()
.center([100, 38])
.scale(920)
.translate([width/2, height/2]);
//定义地形路径生成器
var geoPath = d3.geoPath()
.projection(projection); //设定投影
console.log(geoPath);
//颜色比例尺
//请求ChinaGeo.json
d3.json("China.json").then(function(data){ //100000_full.json A2_100000_full.json
console.log(data);
var scaleColor = d3.scaleOrdinal()
.domain(d3.range(data.features.length))
.range(d3.schemeCategory10);
var groups = svg.append("g");
var tooltip=d3.select("body")
.append("div")
.attr("class","tooltip")
.style("background-color","#d3d3d3")
.style("border-radius", "3px")
.style("padding","5px");
groups.selectAll("path")
.data(data.features)
.enter()
.append("path")
.attr("class","province")
.attr("stroke","#333")
.attr("stroke-width","0.2px")
.attr("info",(d,i)=>covid[i])
.attr("fill",function(d,i){
if(covid[i]<1)
return color[0];
else if(covid[i]<5)
return color[1];
else if(covid[i]<20)
return color[2];
else if(covid[i]<100)
return color[3];
else if(covid[i]<200)
return color[4];
else if(covid[i]<500)
return color[5];
else if(covid[i]<1000)
return color[6];
else if(covid[i]<2000)
return color[7];
else
return color[8];
})
.attr("d",(d,i)=>geoPath(d)) //使用路径生成器
.on("mouseover",function(d,i){
console.log(i);
const change=d3.select(this)
.attr("stroke-width","1.5px")
var t=change.attr("info")
tooltip.html("现有确诊量:"+t)
.style("visibility","visible")
.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY -10) + "px")
})
.on("mouseout",function(d,i){
console.log(i);
d3.select(this)
.attr("stroke-width","0.2px")
tooltip.style('visibility', 'hidden')
});
var texts = svg.selectAll(".texts")
.data(data.features)
.enter()
.append("text")
.attr("class", "texts")
.text((d,i)=>d.properties.name)
.attr("text-anchor","middle")
.attr("transform", function(d) {
var centroid = geoPath.centroid(d),
x = centroid[0],
y = centroid[1];
if((d.properties.name=="澳门")||(d.properties.name=="安徽省")
||(d.properties.name=="河北省"))
y=y+15;
if((d.properties.name=="香港"))
y=y+10;
//return "translate(" + x + ", " + y + ")";
return `translate(${x},${y})`;
})
.attr('fill','999')
.attr("font-size","8px");
});
var title=svg.append("text")
.text("新冠疫情大数据报告")
.attr("x",width/2-100)
.attr("y",40)
.attr("font-size","30")
.attr("fill","#555")
var title=svg.append("text")
.text("5月22日,2022年")
.attr("x",width/2-60)
.attr("y",70)
.attr("font-size","20")
.attr("fill","#555")
</script>
<img src="南海.png" width="150"/>
</body>
</html>