首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >ReactJS D3 -如何放大D3地球世界地图

ReactJS D3 -如何放大D3地球世界地图
EN

Stack Overflow用户
提问于 2020-06-05 23:13:40
回答 1查看 2.3K关注 0票数 3

我正在开发一个使用ReactJS的网络应用程序。我在React组件中有一个使用D3呈现的世界地图。它具有基本功能,例如,每当单击世界地图中的某个国家时(因此“放大”),就会调整geoMercator().fitSize()。但是,我希望用户能够通过滚动鼠标轮来缩放自定义的数量,但是我不知道如何做到这一点。当我在网上搜索时,我偶然发现了d3的缩放功能,但是例子都是通过调整比例来完成的,但我不知道如何将它应用到d3-geo上,它似乎没有缩放,但只有投影。

这是目前为止我的代码

代码语言:javascript
运行
AI代码解释
复制
function GeoChart() {

    const svgRef = useRef();
    const wrapperRef = useRef();
    const [dimensions, setDimensions] = useState(useResizeObserver(wrapperRef));
    const [selectedCountry, setSelectedCountry] = useState(null);

    useEffect(() => {
        const svg = select(svgRef.current);
        const { width, height } = wrapperRef.current.getBoundingClientRect();

        const minProp = leadCount ? min(leadCount, count => count.count) : null
        const maxProp = leadCount ? max(leadCount, count => count.count) : null
        const colorScale = scaleLinear()
            .domain([minProp, maxProp])
            .range(["#ccc", "red"]);

        // projects geo-coordinates on a 2D plane
        const projection = geoMercator()
            .fitSize([width, height], selectedCountry || data)
            .precision(100);

        // takes geojson data,
        // transforms that into the d attribute of a path element
        const pathGenerator = geoPath().projection(projection);

        // render each country
        svg
            .selectAll(".country")
            .data(data.features)
            .join("path")
            .on("click", feature => {
                console.log(selectedCountry)
                setSelectedCountry(selectedCountry === feature ? null : feature);
            })
            .attr("class", "country")
            .transition()
            .attr("fill", feature => findLeadCount(feature.properties.name))
            .attr("d", feature => pathGenerator(feature))

}, [data, dimensions, selectedCountry]);

return (
        <div ref={wrapperRef} style={{ marginBottom: "2rem" }}>
            <svg id="geo-chart" ref={svgRef}></svg>
        </div>
) }

export default GeoChart;

所有的帮助都很感谢,我是D3的新手,所以可能有一些我不知道如何做的事情,帮助引导我朝着正确的方向前进,谢谢!

EN

回答 1

Stack Overflow用户

发布于 2020-06-09 22:11:06

我提供了两种通用的D3解决方案;对React的适应应该相当简单。通过保持它的一般性,答案和片段要清晰得多,尽管答案仍然很长.

坐标

在处理地理投影和缩放时,我们处理的是几个坐标系:

地理坐标(地球上的三维坐标,以degrees)

  • Projected坐标(笛卡尔数据,以像素为单位,投影的result)

  • SVG/Canvas坐标(由svg变换属性应用于投影坐标的平移和缩放)

测量)

可以通过投影函数使用适当的转换和缩放,这样就不需要SVG/画布转换。例如,如果需要进一步放大地图,则将D3投影比例尺或SVG/画布比例尺加倍具有相同的效果。因此,我们可以有效地消除对第三坐标系的考虑,通过设置投影参数,不需要设置SVG/画布变换。

如果我们想避免使用SVG/画布转换,我们将进行语义缩放:我们将根据更新的投影重新绘制所有数据。这个让我们用投影来做所有的工作。

如果我们想要操作SVG/画布转换来实现缩放,我们将进行几何缩放。这只需要对特性的初始绘图进行投影,然后使用SVG/画布转换来移动已经绘制的特性,并根据需要调整它们的大小。

两者各有优缺点。我不会在这里和他们说话,但我会告诉他们这两者是如何实现的。

语义缩放

对于您的用例,这可能是更容易实现的解决方案。

我们可以使用d3.zoom()跟踪当前的翻译和缩放:

代码语言:javascript
运行
AI代码解释
复制
  let zoom = d3.zoom()
    .on("zoom", function() {
        let t = d3.event.transform;                 // get current zoom state
        projection.scale(t.k).translate([t.x,t.y]); // set scale and translate of projection.
        features.attr("d", path)                    // redraw the features
    })

  svg.call(zoom);

以上将允许用户通过摇摄或缩放鼠标与功能交互(通过投影)。变焦跟踪累积变焦、平移和缩放。我们将使用它的值设置类似SVG转换的值,以设置投影参数,然后用更新的投影重新绘制所有功能。

但是,我们需要设置缩放的初始值。变焦的初始比例尺是1,对于d3,d3.geoMercator投影将形成一个~6x6像素的世界。我们可以使用selection.call(zoom.transform, transform)设置初始缩放状态。

代码语言:javascript
运行
AI代码解释
复制
 // Set up an initial projection translate and scale.
 svg.call(zoom.transform, d3.zoomIdentity.translate(width/2,height/2).scale(width/Math.PI/2));

翻译表示视图端口的中心。D3墨卡托投影的尺度通常是一个经度弧度分布在多少像素上。Mercator的默认中心是0,0,所以上面的中心是地图并将其缩放到viewport。

zoom.transform触发缩放事件,重要的是更新缩放状态,以便投影和缩放处于对齐状态。

最棘手的部分是使用fitSize() -这会修改投影,但不会修改缩放状态。然而,fitSize()只修改投影的翻译和缩放,而不是中心。因此,我们可以简单地提取当前比例并进行转换,并以编程方式触发具有以下数据的缩放事件:

代码语言:javascript
运行
AI代码解释
复制
 function centerOnFeature(feature) {
    projection.fitSize([width,height],feature);
    var k = projection.scale();
    var t = projection.translate();
    svg.call(zoom.transform, d3.zoomIdentity.translate(...t).scale(k));
  }

注意,这确实设置了两次投影参数:一次使用fitSize,一次在变焦事件函数中,这是可以避免的,但是性能命中应该是不存在的,需要绘制特性。

下面是正在工作的三个代码块(最后一个代码块略有调整):

代码语言:javascript
运行
AI代码解释
复制
var width = 480;
var height = 480;

var svg = d3.select("svg");
var projection = d3.geoMercator();
var path = d3.geoPath(projection);

d3.json("https://d3js.org/world-110m.v1.json").then(function(world) {

  // Draw the world.
  let countries = topojson.feature(world, world.objects.countries).features;
  let features =  svg.selectAll("path")
    .data(countries)
    .enter()
    .append("path")

  // Let the zoom take care of modifying the projection:
  let zoom = d3.zoom()
    .on("zoom", function() {
        let t = d3.event.transform;  
        projection.scale(t.k).translate([t.x,t.y]);
        features.attr("d", path)
    })

  svg.call(zoom);
    
    
   
  // Set up an initial projection translate and scale.
  svg.call(zoom.transform, d3.zoomIdentity.translate(width/2,height/2).scale(width/Math.PI/2));
    
  // Let us click on a country:
  features.on("click", function(d) {
        projection.fitSize([width,height],d);
        var k = projection.scale();
        var t = projection.translate();
        svg.call(zoom.transform, d3.zoomIdentity.translate(...t).scale(k));
      })
  
  // Some buttons to programatically set the translate and scale:  
  d3.select("div")
      .selectAll(null)
      .data([{label:"Angola",id:"024"},{label:"New Zealand",id:"554"}])
      .enter()
      .append("button")
      .text(function(d) { return d.label; })
      .on("click", function(d) {
        projection.fitSize([width,height],getCountrybyID(d.id,countries));
        var k = projection.scale();
        var t = projection.translate();
        svg.call(zoom.transform, d3.zoomIdentity.translate(...t).scale(k));
      })

});

// Helper function:
function getCountrybyID(id,countries) {
  for(var i = 0; i < countries.length; i++) {
    if(id == countries[i].id) return countries[i];
  }
}
代码语言:javascript
运行
AI代码解释
复制
path {
  stroke: #ccc;
  stroke-width: 1px;
  fill: #333;
}
代码语言:javascript
运行
AI代码解释
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<div>.</div>
<svg width="480" height="480"></svg>

几何缩放

这可能会造成更多的混乱,因为它很容易混淆语义和几何,但应该同样容易实现。

投影将使用一次:最初绘制特征。使用fitSize()缩放到某些特性将修改投影的转换和缩放。由于我们使用SVG/Canvas转换来适当地缩放和居中映射,所以不能使用这个修改的投影来绘制新特性:它将导致应用缩放和两次转换。在这个场景中,一个解决方案是有一个不受fitSize()干扰的重复规模。

同样,让我们使用d3.zoom()来跟踪当前的转换和缩放,但是这次使用它来修改SVG上的转换:

代码语言:javascript
运行
AI代码解释
复制
  let zoom = d3.zoom()
    .on("zoom", function() {
        g.attr("transform", d3.event.transform);    // apply the current zoom to a parent holding our features
    })

   svg.call(zoom);

同样,上面的内容将允许用户通过摇摄或缩放鼠标来与功能交互。

我们不需要设置初始缩放状态,只需在设置初始投影参数之后绘制我们想要的功能:

代码语言:javascript
运行
AI代码解释
复制
let projection = d3.geoMercator()
    .translate([width/2,height/2])
    .scale(width/Math.PI/2);

let path = d3.geoPath(projection);

features.attr("d", path);

而且,要以编程方式缩放到特定国家或功能,我们可以使用:

代码语言:javascript
运行
AI代码解释
复制
function centerOnFeature(feature) {
    projection.fitSize([width,height],feature);
    let k = projection.scale() / t0.k; // relative to initial scale.
    let x = projection.translate()[0] - t0.x * k; // relative to initial scale.
    let y = projection.translate()[1] - t0.y * k; // relative to initial scale.
    svg.call(zoom.transform, d3.zoomIdentity.translate(x,y).scale(k));
}

这里我使用t0跟踪初始投影、翻译和缩放。我们想知道初始投影中坐标值的相对变化,然后用selection.call(zoom.transform,...将这个相对变化应用到缩放中。

下面是正在工作的这三个代码块(稍加调整--例如计算缩放时的笔画宽度):

代码语言:javascript
运行
AI代码解释
复制
var width = 480;
var height = 480;

var t0 = {k:width/2/Math.PI,x:width/2,y:height/2};

var svg = d3.select("svg");
var g = svg.append("g");
var projection = d3.geoMercator().translate([t0.x,t0.y]).scale(t0.k);
var path = d3.geoPath(projection);

d3.json("https://d3js.org/world-110m.v1.json").then(function(world) {

  // Draw the world.
  let countries = topojson.feature(world, world.objects.countries).features;
  
  let features =  g.selectAll("path")
    .data(countries)
    .enter()
    .append("path")
    .attr("d", path)
    .style("stroke-width",1);

  // Let the zoom take care of modifying the projection:
  let zoom = d3.zoom()
     .on("zoom", function() {
       g.attr("transform", d3.event.transform);    // apply current transform to a parent holding our features
       features.style("stroke-width", 1/d3.event.transform.k); // update stroke width.
    })

  svg.call(zoom);

    
  // Let us click on a country:
  features.on("click", function(d) {
        projection.fitSize([width,height],d);
        let k = projection.scale() / t0.k; // relative to initial scale.
        let x = projection.translate()[0] - t0.x * k; // relative to initial scale.
        let y = projection.translate()[1] - t0.y * k; // relative to initial scale.
        svg.call(zoom.transform, d3.zoomIdentity.translate(x,y).scale(k));
      })

  // Some buttons to programatically set the translate and scale:  
  d3.select("div")
      .selectAll(null)
      .data([{label:"Angola",id:"024"},{label:"New Zealand",id:"554"}])
      .enter()
      .append("button")
      .text(function(d) { return d.label; })
      .on("click", function(d) {
        projection.fitSize([width,height],getCountrybyID(d.id,countries));
        let k = projection.scale() / t0.k; // relative to initial scale.
        let x = projection.translate()[0] - t0.x * k; // relative to initial scale.
        let y = projection.translate()[1] - t0.y * k; // relative to initial scale.
        svg.call(zoom.transform, d3.zoomIdentity.translate(x,y).scale(k));
      })

});

// Helper function:
function getCountrybyID(id,countries) {
  for(var i = 0; i < countries.length; i++) {
    if(id == countries[i].id) return countries[i];
  }
}
代码语言:javascript
运行
AI代码解释
复制
path {
  stroke: #ccc;
  fill: #333;
}
代码语言:javascript
运行
AI代码解释
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<div>.</div>
<svg width="480" height="480"></svg>

混合进场

最好避免这种情况。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62228556

复制
相关文章
hough变换理解[通俗易懂]
hough变换概念 在计算机中,经常需要将一些特定的形状图形从图片中提取出来,如果直接用像素点来搜寻非常困难,这时候需要将图像从像素按照一定的算法映射到参数空间。hough变化提供了一种从图像像素信息到参数空间的变换方法。对于像直线,圆,椭圆这样的规则曲线hough是一种常用的算法。hough变化最大的优点在于特征边缘描述中间隔的容忍性并且该变换不受图像噪声的影响。
全栈程序员站长
2022/07/25
9520
hough变换理解[通俗易懂]
GeoJSON 和 TopoJSON
GeoJSON 和 TopoJSON 是符合 JSON 语法规则的两种数据格式,用于表示地理信息。 1. GeoJSON   GeoJSON 是用于描述地理空间信息的数据格式。GeoJSON 不是一种新的格式,其语法规范是符合 JSON 格式的,只不过对其名称进行了规范,专门用于表示地理信息。   GeoJSON 的最外层是一个单独的对象(object)。这个对象可表示: 几何体(Geometry)。 特征(Feature)。 特征集合(FeatureCollection)。   最外层的 GeoJSON
用户1149564
2018/01/11
2.4K0
形象理解傅里叶变换!
来源:机器学习杂货店 本文约3100字,建议阅读6分钟本文分享一篇关于傅立叶变换理解的文章。 这篇文章可以说是介绍傅里叶变换最清晰通俗的,没有之一,直接把你当做小学生来讲,通过大量的动画不但告诉你傅里叶变换是什么,还告诉你傅里叶变换能干什么。 难能可贵的是,你可以通过手动绘制图案和拖动滑块来加深读傅里叶变换的理解。 动画链接: https://www.jezzamon.com/fourier/index.html 傅里叶变换是一种在各个领域都经常使用的数学工具。这个网站将为你介绍傅里叶变换能干什么,为什么
数据派THU
2023/03/29
8450
形象理解傅里叶变换!
仿射变换及其变换矩阵的理解
这篇文章不包含透视变换(projective/perspective transformation),而将重点放在仿射变换(affine transformation),将介绍仿射变换所包含的各种变换,以及变换矩阵该如何理解记忆。
李拜六不开鑫
2019/05/31
3.6K0
topojson转换与应用
topojson很早就问其大名,但日常用的比较多的还是geojson为主,最近在项目里面开始用到了,所以就写此文记录一下。
牛老师讲GIS
2021/09/10
1.9K0
这次终于彻底理解了傅里叶变换
原文链接:https://github.com/Jezzamonn/fourier 译者:virtualwiz
小白学视觉
2022/04/06
1.1K0
这次终于彻底理解了傅里叶变换
三维变换矩阵的理解
邹成卓
2017/07/26
9.4K7
三维变换矩阵的理解
这次终于彻底理解了傅里叶变换
来源:深度学习爱好者本文共3100字,建议阅读6分钟本文最清晰通俗的介绍傅里叶变换。 这篇文章可以说是介绍傅里叶变换最清晰通俗的,没有之一,直接把你当做小学生来讲,通过大量的动画不但告诉你傅里叶变换是什么,还告诉你傅里叶变换能干什么。难能可贵的是,你可以通过手动绘制图案和拖动滑块来加深读傅里叶变换的理解。 可以点击链接: https://www.jezzamon.com/fourier/index.html 查看动画! 傅里叶变换是一种在各个领域都经常使用的数学工具。这个网站将为你介绍傅里叶变换能干什么,
数据派THU
2022/03/04
5360
D3动画
D3.js提供了多种工具支持数据可视化的交互,其中d3.transition让简单而高效的为图像添加动画成为了可能。
vincentKo
2022/09/19
9230
D3动画
理解图傅里叶变换和图卷积
图神经网络(GNN)代表了一类强大的深度神经网络架构。在一个日益互联的世界里,因为信息的联通性,大部分的信息可以被建模为图。例如,化合物中的原子是节点,它们之间的键是边。
deephub
2023/08/30
3970
理解图傅里叶变换和图卷积
D3 介绍
D3.js 是一个基于数据的操作文档的 JavaScript 库,可以让你绑定任何数据到 DOM,支持 DIV 这种图案生成,也支持 SVG 这种图案的生成(如果你对 SVG 不熟悉,请先看一下这篇文章,它介绍了 SVG、VML 和 Canvas)。D3 帮助你屏蔽了浏览器差异,做出来图案的效果可以说是炫目得一塌糊涂,可是代码却很简洁。在我第一次听人介绍 D3 的时候,确实被其示例震撼到了,大量的例子在这里可以找到。
四火
2022/07/15
1.4K0
D3 介绍
深入理解向量进行矩阵变换的本质
向量的理解 上图表述的是平面上一点,在以i和j为基的坐标系里的几何表示,这个点可以看作(x,y)也可以看作是向量ox与向量oy的和。
坑吭吭
2018/10/10
1.7K0
深入理解向量进行矩阵变换的本质
傅里叶变换的意义和理解(通俗易懂)
从我们出生,我们看到的世界都以时间贯穿,股票的走势、人的身高、汽车的轨迹都会随着时间发生改变。这种以时间作为参照来观察动态世界的方法我们称其为时域分析。而我们也想当然的认为,世间万物都在随着时间不停的改变,并且永远不会静止下来。但如果我告诉你,用另一种方法来观察世界的话,你会发现世界是永恒不变的,你会不会觉得我疯了?我没有疯,这个静止的世界就叫做频域。
全栈程序员站长
2022/09/13
2.9K0
傅里叶变换的意义和理解(通俗易懂)
从经典动力学理解勒让德变换
勒让德变换在经典力学和统计力学中是非常常用的一个数学工具,其变换了一个函数的所有(或部分)自变量,也改变了函数的形式,最终却不改变函数所表征的意义。最典型的案例是从拉格朗日动力学到哈密顿动力学的勒让德变换的应用,最终证明了两种力学框架的一致性。但是勒让德变换作为一个数学工具,光看形式的话很容易让人不明所以,这里我们代入一个经典动力学的案例,来看看勒让德变换的真实物理含义是什么。
DechinPhy
2022/05/10
7400
从经典动力学理解勒让德变换
几种图像变换 刚体变换 仿射变换 投影变换
转自:https://www.cnblogs.com/bnuvincent/p/6691189.html
bye
2020/10/30
3.1K0
几种图像变换 刚体变换  仿射变换 投影变换
8条github使用小技巧
  作为全球最大的开源及私有软件项目托管社区平台,github可以显著地帮助从事编程相关工作的人员提升自己的技术水平,也是费老师我日常最常浏览学习的技术类网站。
Feffery
2022/05/30
4110
8条github使用小技巧
手把手|如何用Python绘制JS地图?
编译:佘彦遥 程序注释:席雄芬 校对:丁雪 原文链接:https://github.com/python-visualization/folium/blob/master/README.rst Folium是建立在Python生态系统的数据整理(Datawrangling)能力和Leaflet.js库的映射能力之上的开源库。用Python处理数据,然后用Folium将它在Leaflet地图上进行可视化。 概念 Folium能够将通过Python处理后的数据轻松地在交互式的Leaflet地图上进行可视化展示
大数据文摘
2018/05/22
4K0
提升Github使用体验的8个技巧
作为全球最大的开源及私有软件项目托管社区平台,github可以显著地帮助从事编程相关工作的人员提升自己的技术水平,也是费老师我日常最常浏览学习的技术类网站。
朱卫军 AI Python
2022/07/06
5390
提升Github使用体验的8个技巧
图像变换之Census变换
图像的Census变换 Census变换属于非参数图像变换的一种,它能够较好地检测出图像中的局部结构特征,如边缘、角点特征等。传统Census变换的基本思想是:在图像区域定义一个矩形窗口,用这个矩形窗口遍历整幅图像。选取中心像素作为参考像素,将矩形窗口中每个像素的灰度值与参考像素的灰度值进行比较,灰度值小于或等于参考值的像素标记为0,大于参考值的像素标记为1,最后再将它们按位连接,得到变换后的结果,变换后的结果是由0和1组成的二进制码流。Census变换的实质是将图像像素的灰度值编码成二进制码流,以此来获取
一棹烟波
2018/01/12
2K0
图像变换之Census变换
OpenCV 图像变换之 —— 通用变换
我们目前所看到的仿射变换和透射变换是一些更为一般的处理过程中特殊的例子。本质上,这两种变换有着相似的特性:它们把源图像的像素从一个地方映射到目标图像的另一个地方。事实上,其他一些操作也有着相同的结构。本文学习一些类似的变换,而后学习如何让OpenCV实现自己的映射变换。
为为为什么
2022/08/09
3.2K0
OpenCV 图像变换之 —— 通用变换

相似问题

Weka java:生成arff文件

15

在weka中分类来自ARFF的数据

11

Weka线性回归ClassNotFoundException

411

weka稀疏arff文件

41

WEKA线性回归转换问题

11
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档