D3JsDay17 Fill the color,Zoom in on center—地图各项操作及填色

改变path的样貌

首先观看以下程序码

const width = 800;
const height = 600;
const svg = d3.select("body").append("svg")
              .attr("width", width)
              .attr("height", height);
const  projection = d3.geoMercator();
console.log(typeof(projection));
const path = d3.geoPath()
.projection(projection);
const g = svg.append("g");
d3.json("World_Countries.json").then(function(topojsonData) {
  console.log(topojsonData);
  const convertedGeojson =topojson
          .feature(topojsonData, topojsonData.objects.World_Countries);
  const getGeoFeature = convertedGeojson.features;
g.selectAll("path")
  .data(
      getGeoFeature
          )
  .join("path")
  .style("stroke", "gray")
  .style("stroke-width","1")
  .style("stroke-opacity",".5")
  .style("fill","white")
  .attr("d", path)
  ;
})

昨天我们所画出的地图是黑色的区块,如果我们只有撰写.style("fill","white")设定成白色的话,由於你的svg背景也是白色,所以整个地图将会看起来像消失一般

因此我们撰写.style("stroke", "gray")的地方将加入线段并且设定成灰色,为了让线段不要太过突兀,可以设定他的透明度和线段粗细如.style("stroke-width","1").style("stroke-opacity",".5")所示。

连续颜色比例尺转换

https://ithelp.ithome.com.tw/upload/images/20211002/20125095SijF6CuWJd.png

这边提到它的range是[0,1],我们可尝试着撰写一下程序码看看会印出什麽

const a = d3.scaleSequential().domain([0,100]);
console.log(a(1));

其实这里会印出的东西相当於先前提到的scaleLinear()使用range([0,1])的函式
如下

const b = d3.scaleLinear().domain([0,1000]).range([0,1]);
console.log(b(1));

底下有一个范例是转换你所输入的数字变成一个色彩的范例,然而官方说明提到如果没有指定domain的话将会预设成domain([0,1]),换句话说它会预设成domainrange都是**(0,1)**,因此不论你输入什麽数字都会转换成同一种色彩。

因此我们可以给予一个domain来表示预计转换的数字范围
程序码如下

var rainbow = d3.scaleSequential(function(t) {
          return d3.hsl(t * 360, 1, 0.5) + "";
          }).domain([1,20]);
console.log( rainbow(5));//印出rgb(188, 255, 0) 

可以尝试将rainbow带入不同的数字会印出不同的rgb参数

补充说明HSL是一种色彩表示方式,第一个数字代表颜色范围是0~360,第二个数字和第三个数字代表饱和度和亮度范围都是0到1更多可以参考HSL和HSV维基
scaleSequentiald3官方API
其他更多的色彩可参考d3官方色彩API

因此我们可以宣告一个diversityColor变数里面使用t来设定不同的颜色,这边饱和度和亮度设定0.9,为了确保格式正确使用formatRgb()方法来转换,另外全世界大概两百多个国家,我们设置domain([0,250])

const diversityColor = d3.scaleSequential(t => d3.hsl(t * 360,.9,.9).formatRgb()).domain([0,250]);

接下来宣告完之後我们就再刚刚插入data的地方使用i遍历每个区块程序码如下

g.selectAll("path")
  .data(
      getGeoFeature
          )
  .join("path")
  .style("stroke", "gray")
  .style("stroke-width","1")
  .style("stroke-opacity",".5")
  .style("fill",(d,i)=>(diversityColor(i)))
  .attr("d", path);

之後你应该会看到的画面如下

https://ithelp.ithome.com.tw/upload/images/20211002/20125095HcdnD39hB1.png

设经纬度、缩放、旋转角度

假如你画出来的地图位置不是你所要的话,又或者显示面积太小的话该如何处理,例如本范例当中是放入世界地图,如果我们要呈现台湾要如何处置?

这边可以参考D3官方projection

直接用将参数带入到projection作方法链连接
程序码如下

const  projection = d3.geoMercator()
                        .center([120, 23])
                        .scale(5000)
                        .rotate([0,0,0]);

由上面的程序码我们设定scale(5000)和台湾的经纬度,带入center([120, 23])就可以让世界地图移动到台湾的地方并且放大,另外可以旋转角度,有兴趣的人可以自行试试看

设置完会看到如下图

https://ithelp.ithome.com.tw/upload/images/20211002/20125095WsIoviZpws.png

zoom()缩放位移函式

zoom事件

我们在使用GoogleMap地图的时候通常可以透过滚轮、滑鼠连续点两下可以放大、滑鼠按住後移动可以位移地图,在d3里面可以使用zoom事件来表示这些行为如下图说明

https://ithelp.ithome.com.tw/upload/images/20211002/201250956tgBRo6Kfo.png

我们撰写以下程序码

 const zoom = d3.zoom()
              .on('zoom', function(event) {
                  console.log(event.transform);
                  g.selectAll('path')
                   .attr('transform', event.transform);
                });

event.transform

这里用on()来监听zoom事件,尝试着印出event.transform看看,将会看到以下片段
https://ithelp.ithome.com.tw/upload/images/20211002/20125095MutEdGDMK9.png

这边k表示缩放距离,x和y表示位移座标

官方文件说明如下,大致上的意思是使用高中数学所学的矩阵的概念转换位置,web运作原理是来自於SVG的transformMatrix有兴趣的人可以参考SVGtransformMatrixMDN章节

https://ithelp.ithome.com.tw/upload/images/20211002/20125095SdRBFLbljA.png

我们使用.on('zoom', function(event) {})绑定事件之後,後面callback函式里面可以带入要执行的动作,我们藉由所抓取的zoom事件来对应要改变属性transform。

另外记得的一点是创建一个zoom的行为的时候记得要挂载到某个元素上面
官方说明如下图

https://ithelp.ithome.com.tw/upload/images/20211002/20125095j3aJ2ycGJF.png

D3官方Zoom官方API

scaleExtent()函式限制缩放焦距

这个函式只要是可以让使用者在透过滚轮或是滑鼠点击两下的时候不要无限放大(或是无限缩小)
综合以上的程序码如下

 const zoom = d3.zoom().scaleExtent([1,10])
                      .on('zoom', function(event) {
                          console.log(event.transform);
                          g.selectAll('path')
                           .attr('transform', event.transform)
                           ;
                        });
svg.call(zoom);

我们设定下限是1也就是不让使用者缩小,也可以设定负值让使用者缩小

另外zoom()这个功能不限於只能用在地图这边的使用,在一般的<svg> <rect> <circle>等等皆可使其放大缩小位移

本日完整程序码如下

const width = 800;
    const height = 600;
    const svg = d3.select("body").append("svg")
                    .attr("width", width)
                    .attr("height", height);
    const  projection = d3.geoMercator();
    console.log(typeof(projection));
    const path = d3.geoPath()
    .projection(projection);
    const g = svg.append("g");
    d3.json("World_Countries.json").then(function(topojsonData) {
        console.log(topojsonData);
        const convertedGeojson =topojson
                .feature(topojsonData, topojsonData.objects.World_Countries);
        const getGeoFeature = convertedGeojson.features;
    g.selectAll("path")
        .data(
            getGeoFeature
                )
        .join("path")
        .attr("d", path)
        ;
    })

总结

本日学习到可以设定经纬度的中心点center()和指定缩放倍数缩放大小scale()以及旋转角度rotate()

设定path的线段粗细、颜色、透明度,区块的颜色填充和颜色的产生

设定焦距的缩放位移

本日页面如下

gitpage

明天将会找寻一个实际资料来做视觉化呈现地图


<<:  大共享时代系列_016_共享餐桌

>>:  Day.23 「更加认识 DOM,并初次了解事件绑定」 —— JavaScript DOM

Re: 新手让网页 act 起来: Day22 - React Hooks 之 useCallback

前言 useCallback 常常会被用来优化效能,减少 React 不必要的 render ,但如...

[DAY09] 部署用 Designer 做好的 Pipeline 到 Batch

DAY09 部署用 Designer 做好的 Pipeline 到 Batch 有些应用场合是 Ba...

Day 24 - 影像处理篇 - 用Canvas实作动态绿幕抠像 - 成为Canvas Ninja ~ 理解2D渲染的精髓

上一篇我们提到我们接着要开始玩一些比较有趣的实作~ 所以我们就来讲讲怎麽在web端实作绿幕抠像(Gr...

予焦啦!Golang 记忆体初始化

本节是以 Golang 4b654c0eeca65ffc6588ffd9c99387a7e4800...

iOS·iOS开发面试-关於底层的那些坑

如果你有时间的,不妨也拿笔本子测试一下,看看能做多少,在文章点赞留言我会第一时间发你答案!或者加我...