首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DataMaps /按标识符隐藏弧

DataMaps /按标识符隐藏弧
EN

Stack Overflow用户
提问于 2019-03-29 08:39:49
回答 2查看 648关注 0票数 2

我用DataMaps创建了一个世界地图。

我的目标是基于一些API数据异步显示和隐藏地图上的弧。

我已经尝试过什么了

我每5秒调用一次API,并将响应数据推送到地图中。(这将在将来被异步调用所取代)

在下面的示例中,arcData array表示我的API响应。

我可以通过DOM manipulation访问这些弧。在我的例子中,我使用d3.selectAll('path.datamaps-arc').transition().duration(3500).style("opacity", 0);慢慢淡出所有的弧,然后删除它们。

代码语言:javascript
复制
var arcData = //Test Data
[
  {
    origin: 
    {
          latitude: 52.520008,
          longitude: 13.404954
    },
    destination: {
          latitude: 37.618889,
          longitude: -122.375
    }
 },
 {   origin: 
    {
          latitude: 52.520008,
          longitude: 13.404954
    },
    destination: {
          latitude: 25.793333,
          longitude:-80.290556
    }
 },
 {
    origin: 
    {
          latitude: 52.520008,
          longitude: 13.404954
    },
    destination: {
          latitude: 35.877778,
          longitude: -78.7875
    }
 }
];


$(document).ready(function() {
  var map = new Datamap({ //create data map
    element: document.getElementById('container'),
    fills: {
      defaultFill: "#343a40",
    }
  });
  
  //call API every 4 seconds [Workaround for this fiddle]  
  setInterval(function() {
    //add arcs to map
    map.arc(arcData, {strokeWidth: 2, animationSpeed: 1000, strokeColor: '#b1dd00'}); // add arc Data

    //Remove all arcs [should be replaced by a function that asynchronously hides single arcs after x seconds]
    d3.selectAll('path.datamaps-arc').transition().duration(3500).style("opacity", 0);
    d3.selectAll('path.datamaps-arc').transition().delay(3500).remove();
  }, 4000);
});
代码语言:javascript
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/topojson/1.6.9/topojson.min.js"></script>
<script src="https://datamaps.github.io/scripts/datamaps.world.min.js"></script>
<div id="container" style="position: relative; width: 500px; height: 300px;"></div>

此解决方案基本有效,但:

我的问题

所有的弧形都同时被隐藏起来。如果将来异步调用API,则在当前绘制弧时会出现冲突,同时会触发删除进程。

我想要什么

一个解决方案,我可以访问每个弧的一些标识符,并分别删除他们后,他们完全绘制。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-04-02 04:30:51

通过DataMaps添加的所有弧实际上都由其JSON格式(datamaps.js#L356)的data键控:

代码语言:javascript
复制
var arcs = layer.selectAll('path.datamaps-arc').data( data, JSON.stringify ); 

注意,DataMaps使用JSON.stringify作为键函数。如果DataMaps能在这里提供一种使用自定义键函数的方法,那就太好了。

虽然这些密钥本身不持久化,但足以确保对于一个相同的数据只有一条弧线。弧数据本身就是弧标识符。

利用这些知识,我们可以通过比较弧的数据来识别弧形:

代码语言:javascript
复制
var selectedArcs = d3.selectAll('path.datamaps-arc').filter(function(data) {
   // compare data
   return data === someValue;
});

为了更进一步,我们实际上可以调整传递给DataMaps.arc的数据,以便它实际上保存我们的比较友好标识符。origindestination字段是强制性的,但是我们可以自由地使用任何我们喜欢的其他字段。

代码语言:javascript
复制
{
  id: 'some-unique-identifier',
  origin: {
    latitude: 52.520008,
    longitude: 13.404954
  },
  destination: {
    latitude: 37.618889,
    longitude: -122.375
  }
}

然后,我们可以使用这个经过调整的字段来识别我们的弧:

代码语言:javascript
复制
var selectedArcs = d3.selectAll('path.datamaps-arc').filter(function(data) {
   return data.id === 'some-unique-identifier';
});

请记住,DataMaps使用其整个data值为每个弧键入了键;这意味着两个具有相同id但不同的origin和或destination值的数据将被视为两种不同的弧。

下面是一个简单的演示,它使用了原始示例的修改版本:

代码语言:javascript
复制
var arcData = //Test Data
[
  {
    id: 123,
    origin: 
    {
          latitude: 52.520008,
          longitude: 13.404954
    },
    destination: {
          latitude: 37.618889,
          longitude: -122.375
    }
 },
 	{ 
  	id: 'abc',
    origin: 
    {
          latitude: 52.520008,
          longitude: 13.404954
    },
    destination: {
          latitude: 25.793333,
          longitude:-80.290556
    }
 },
 	{
    id: 'xyz',
    origin: 
    {
          latitude: 52.520008,
          longitude: 13.404954
    },
    destination: {
          latitude: 35.877778,
          longitude: -78.7875
    }
 }
];


$(document).ready(function() {
  var map = new Datamap({ //create data map
    element: document.getElementById('container'),
    fills: {
      defaultFill: "#343a40",
    }
  });
  
  function drawMap() {
    map.arc(arcData, {strokeWidth: 2, animationSpeed: 1000, strokeColor: '#b1dd00'});
  };
  
  function removeArc(id) {  
    var all = d3.selectAll('path.datamaps-arc');
    var sel = all.filter(function(data) {
      return data.id === id;
    });
    sel.transition().duration(1000).style("opacity", 0).remove();
  };
  
  $('button').on('click', function(){ 
    var id = $(this).data('arc');
    if (id) {
      removeArc(id);
    } else {
      drawMap();
    }
  });
  
  drawMap();
});
代码语言:javascript
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/topojson/1.6.9/topojson.min.js"></script>
<script src="https://datamaps.github.io/scripts/datamaps.world.min.js"></script>

<button type="button" data-arc="123">Remove Arc id:123</button>
<button type="button" data-arc="abc">Remove Arc id:abc</button>
<button type="button" data-arc="xyz">Remove Arc id:xyz</button>
<button type="button">Redraw</button>
<div id="container" style="position: relative; width: 500px; height: 300px;"></div>

票数 2
EN

Stack Overflow用户

发布于 2019-04-01 11:17:01

我已经试过解决你的问题了。我所做的是,我为每个数据映射弧分配了唯一的did。它将很容易让您访问独立的弧,您可以相应地更改他们的过渡。

为了演示的目的,我随机地延迟了它,它正常工作。我把第一弧延迟1000毫秒,第二弧度延迟2000毫秒,第三弧延迟3000毫秒。您可以实现自己的算法,以延迟弧的过渡,如你所愿。我在代码中添加了注释,您可以参考。

由于setInterval每4000 ms运行一次,如果任何弧的延迟都超过4000 ms,那么您将能够看到所有的弧同时生成一次,这是第一次。在那以后的弧线会非常随机,所以请记住它。

代码语言:javascript
复制
var arcData = //Test Data
                [{
                        origin: {
                            latitude: 52.520008,
                            longitude: 13.404954
                        },
                        destination: {
                            latitude: 37.618889,
                            longitude: -122.375
                        }
                    },
                    {
                        origin: {
                            latitude: 52.520008,
                            longitude: 13.404954
                        },
                        destination: {
                            latitude: 25.793333,
                            longitude: -80.290556
                        }
                    },
                    {
                        origin: {
                            latitude: 52.520008,
                            longitude: 13.404954
                        },
                        destination: {
                            latitude: 35.877778,
                            longitude: -78.7875
                        }
                    }
                ];


            $(document).ready(function() {
                var map = new Datamap({ //create data map
                    element: document.getElementById('container'),
                    fills: {
                        defaultFill: "#343a40",
                    }
                });
                //hide arc function which will take x amount of delay and arc-id which you want to delay.
                function hideArc(delay, arcId) {
                    d3.select('#' + arcId).transition().duration(delay).style("opacity", 0);
                    d3.select('#' + arcId).transition().delay(delay).remove();
                }

                //call API every 4 seconds [Workaround for this fiddle]  
                setInterval(function() {
                    //add arcs to map
                    map.arc(arcData, {
                        strokeWidth: 2,
                        animationSpeed: 1000,
                        strokeColor: '#b1dd00'
                    }); // add arc Data
                    let arcIds = [];// it will hold all the unique arc-ids
                    d3.selectAll('path.datamaps-arc')[0].forEach((ele, index) => {
                        ele.setAttribute('id', 'datamap-arc-' + index);
                        arcIds.push('datamap-arc-' + index);// pushing new generated ids to arcIds array
                    });
                    //mapping of delay and arc-id, this part is replaceable, you can change it the way you want to change the delay of respective arc.   
                    let arcIdAndDelaymapping = arcIds.map((aercId, index) => {
                        return {
                            aercId,
                            delay:1000*(index+1)
                        }
                    })


                    //Remove all arcs [should be replaced by a function that asynchronously hides single arcs after x seconds]
                    //calling hideArc function with their respective delays.  
                    arcIdAndDelaymapping.forEach((arcMapping) => {
                        hideArc(arcMapping.delay, arcMapping.aercId);
                    })
                }, 4000);
            });
代码语言:javascript
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/topojson/1.6.9/topojson.min.js"></script>
<script src="https://datamaps.github.io/scripts/datamaps.world.min.js"></script>
<div id="container" style="position: relative; width: 500px; height: 300px;"></div>

希望它能解决你的问题。编码愉快!!谢谢你让我探索数据地图。

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

https://stackoverflow.com/questions/55413415

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档