简体   繁体   English

DataMaps /按标识符隐藏弧

[英]DataMaps / hide arcs by identifier

I've created a world map, using DataMaps . 我使用DataMaps创建了一张世界地图。

My aim is to asynchronously show and hide arcs on the map, based on some API data. 我的目标是基于一些API数据在地图上异步显示和隐藏弧。


What have I already tried 我已经尝试了什么

I am calling my API every 5 seconds and push the response data into the map. 我每隔5秒调用一次API ,并将响应数据推送到地图中。 (This will be replaced by asynchronous calls in the future) (这将在未来被异步调用取代)

In my example below, the arcData array represents my API response. 在下面的示例中, arcData array表示我的API响应。

I am able to access the arcs via DOM manipulation . 我可以通过DOM manipulation访问弧。 In my case I am using d3.selectAll('path.datamaps-arc').transition().duration(3500).style("opacity", 0); 在我的情况下,我使用d3.selectAll('path.datamaps-arc').transition().duration(3500).style("opacity", 0); to slowly fade out all arcs and delete them afterwards. 慢慢淡出所有弧线然后删除它们。

 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); }); 
 <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> 


This solution basically works but: 这个解决方案基本上有效

My Problem 我的问题

All arcs are hided at the same time. 所有弧都同时隐藏。 If i asynchronously call the API in the future, there will be a conflict when the arc is currently drawing, and meanwhile the delete process is triggered. 如果我将来异步调用API,当弧正在绘制时会出现冲突,同时触发删除过程。

What I want 我想要的是

A solution that I can access every arc by some identifier and separately delete them after they are fully drawed. 我可以通过某个标识访问每个弧的解决方案,并在完全绘制后单独删除它们。

All arcs added via DataMaps are actually keyed by their data in JSON format ( datamaps.js#L356 ): 通过DataMaps添加的所有弧实际上都是以JSON格式( datamaps.js#L356 )的data键入的:

var arcs = layer.selectAll('path.datamaps-arc').data( data, JSON.stringify ); 

Notice that DataMaps use JSON.stringify as key function . 请注意, DataMaps使用JSON.stringify作为关键功能 It would be nice if DataMaps provide a way to use custom key function here, but alas... 如果DataMaps提供了一种在这里使用自定义键功能的方法,那就太好了,但是...

While these keys themselves are not persisted, it is enough to ensure us that there would only be one arc for one identical data. 虽然这些密钥本身不是持久的,但足以确保我们只有一个弧用于一个相同的数据。 The arc data is the arc identifier itself. 弧数据是弧标识符本身。

Using these knowledge, we can identify an arc by comparing it's data: 利用这些知识,我们可以通过比较它的数据来识别弧:

var selectedArcs = d3.selectAll('path.datamaps-arc').filter(function(data) {
   // compare data
   return data === someValue;
});

To take it further, we can actually tweak the data we pass to DataMaps.arc so that it will actually holds our compare-friendly identifier. 为了更进一步,我们实际上可以调整传递给DataMaps.arc的数据,以便它实际上保存我们的比较友好标识符。 The origin and destination field is mandatory, but we're free to use any other field to our liking. origindestination字段是强制性的,但我们可以根据自己的喜好自由使用任何其他字段。

{
  id: 'some-unique-identifier',
  origin: {
    latitude: 52.520008,
    longitude: 13.404954
  },
  destination: {
    latitude: 37.618889,
    longitude: -122.375
  }
}

We could then use this tweaked field(s) for identifying our arc: 然后我们可以使用这个调整的字段来识别我们的弧:

var selectedArcs = d3.selectAll('path.datamaps-arc').filter(function(data) {
   return data.id === 'some-unique-identifier';
});

Keep in minds that DataMaps keyed each of our arc using its whole data value; 请记住, DataMaps使用其整个data值键入每个弧。 meaning that two data with same id but different origin and or destination value would be considered two different arc. 意味着具有相同id但不同origin和/或destination两个数据将被视为两个不同的弧。

Here's a simple demonstration using a modified version of the original example: 这是使用原始示例的修改版本的简单演示:

 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(); }); 
 <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> 

Well I have tried to solve your problem. 好吧,我试图解决你的问题。 What I have did is, I have assigned unique ids to each arc of data-map. 我所做的是,我为每个数据映射弧分配了唯一的ID。 It will easily give you access to independent arcs and you can change their transitions accordingly. 它可以轻松访问独立弧,您可以相应地更改它们的过渡。

For demo purpose I have delayed it randomly and it works properly. 为了演示目的,我已经随机延迟它并且它正常工作。 I have delayed first arc by 1000 ms second arc by 2000 ms and third arc by 3000 ms. 我将第一弧延迟了1000毫秒,第二弧延迟了2000毫秒,第三弧延迟了3000毫秒。 You can implement your own algorithm to delay the arcs' transitions as you wish. 您可以实现自己的算法来根据需要延迟弧的转换。 I have added comments in the code which you can refer. 我在您可以参考的代码中添加了注释。

As setInterval is running after every 4000 ms, if delay of any arc is more than 4000 ms then you will be able to see all the arcs generating at the same time only once which is the first time. 由于setInterval在每4000毫秒后运行,如果任何弧的延迟超过4000毫秒,那么您将能够看到所有同时仅生成一次的弧,这是第一次。 After that generation of arcs will be very random, so please just keep it in mind. 在那一代弧之后会非常随机,所以请记住它。

 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); }); 
 <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> 

Hopefully it will solve your problem. 希望它能解决你的问题。 Happy Coding!! 快乐编码!! And thanks for making me explore data-maps. 谢谢你让我探索数据地图。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM