#28- D3.js 地图动起来!用SVG viewbox/D3 fitExtent让地图置中

今天来让地图动起来!
老样子,先看成果~神秘的非洲大陆~

相信没几个人认识这些国家吧XDDD

我自己觉得地图只要格式对的话,其实用D3.js去绘制不难,
我遇到的难点是要让地图置中 XD
下面就会讲解一下

1.格式 & 地图投影
2.利用SVG或是D3内建fitExtent置中
3.上code

今天很多内容主要参考这一篇:使用d3.js绘制地图

D3 地图格式: GeoJason

D3读取地图资料有特定格式,要花时间找一下。
这次用地图用的GeoJSON标准格式,回传让我们可以绘制多边形polygon的点位置
他会长得像这样:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "name": "Algeria",
        "cartodb_id": 1,
        "created_at": "2013-11-12T16:15:59+0100",
        "updated_at": "2013-11-12T16:15:59+0100"
      },
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [ //利用这边的座标画地图
          [
            [
              [
                8.621624,
                36.941797
              ],
             
          ]
        ]
      }
    },...

D3有很多投影方式,今天采用的是像Google地图常用的麦卡伦投影
详细原理有点复杂XD 就先略过了


让地图置中

这边有两个方法让地图漂亮置中~

1.SVG viewbox & preserveAspectRatio
用SVG的viewbox: SVG可视范围,想像SVG是一张大白纸,
viewbox就是告诉SVG
1.我要裁的开始座标
2.我要裁的宽高

而preserveAspectRatio进阶设定比例
这次范例就是设定参数:xMidyMid让他取中间

我的案例就会是

//html
<svg  viewBox="420 130 150 350"  //这边我已经算好要裁减的位置了
      preserveAspectRatio="xMinYMin"
></svg>

这样D3读取资料後,也不用特别设定translate,
就可以置中罗。
不过手机版还要另外设定。

对於SVG viewbox & preserveAspectRatio有兴趣可以参考这一篇(图文精美!)
SVG 研究之路 (23) - 理解 viewport 与 viewbox

2. D3内建fitExtent API
这个简单, 回传地图左上角座标
右下叫座标
D3就会帮我们放入中心点罗

projection = d3
  .geoMercator()
  .fitExtent([[0, 0],[width, height],], data);

上code!

// SVG 基本设定
const width = window.innerWidth * 0.7;
const height = window.innerHeight * 0.6;
const svg = d3.select("svg");

// 先把变数设好
  let projection
  let geoGenerator
  let path

//读资料
d3.json( "https://raw.githubusercontent.com/codeforgermany/click_that_hood/master/public/data/africa.geojson"
).then(function (data) {
  
  //投影基本设定,还有置中
  projection = d3
  .geoMercator()
  .fitExtent([[0, 0],[width, height],], data);
  
  geoGenerator = d3.geoPath().projection(projection);
  
  // 画地图
  svg
    .append("g")
    .selectAll("path")
    .data(data.features)
    .enter()
    .append('g')
    .append("path")
    .attr("fill", "#69b3a2")
    .attr("d", geoGenerator)
    .style("stroke", "#fff")
    .on("mouseover", handleMouseOver)
    .on("mouseout", function (d, i) {
      d3.select(this).transition().duration(300).attr("fill", "#69b3a2");
      d3.selectAll("text")
        .transition()
        .delay(function(d, i) { return 100; })
        .text("");
    });
});

//处理滑鼠hover效果
function handleMouseOver(e, d) {
  let centroid = geoGenerator.centroid(d); //算出中间点

  svg
    .append("text")
    .text(d.properties.name)
    .style("font-size", 30)
    .style("font-weight", "bold")
    .style("display", "inline")
    .attr("transform", "translate(" + centroid + ")")
    .style("fill", "black")
    .transition()
    .delay(function(d, i) { return 100; });

  d3.select(this).transition().duration(300).attr("fill", "yellow");
}



以上!

D3可以做地图资料好好玩!

今天的code在这里,但还是有小bug,点到文字会一直闪 :

试了一些方法没办法解决,但不要强求将文字放在地图旁边就是一个做法哈
有任何想法欢迎留言!


<<:  Android Studio初学笔记-Day29-ButtomNavigationView

>>:  AIS3

[day-12] 一切的基础! Python "运算式与算符"的运用(Part .2)

比较算符   比较算符可大致列出以下几种常用的:   1. 大於(>)、大於等於(>=)...

从 IT 技术面细说 Search Console 的 27 组数字 KPI (24) :检索统计报表 KPI 外的重点项目

在去年的 2021–11–25 那天,Google 终於把 Search Console 的检索统计...

Day 24 - 云端服务评估业务篇

从入职到现在也帮助部门开发了许多的平台和应用服务,而原本虚拟主机的签约也快到期了,然而前阵子除了接触...

30-9 之Presentation Layer - MVP ( Model-View-Presenter )

接下来我们来谈谈 MVP ( Model-View-Presenter ),在知道 MVC 也只是在...

Android Studio 菜鸟笔记本-Day 26-介绍BottomNavigationView

BottomNavigationView是底部导览的控件,就像line下方的四个选项,今天我会分享B...