DataMaps / 按标识符隐藏弧
DataMaps / hide arcs by identifier
我创建了一张世界地图,使用 DataMaps。
我的目标是根据一些 API 数据在地图上异步显示和隐藏弧。
我已经尝试过什么
我每 5 秒调用一次 API
,并将响应数据推送到地图中。
(以后会被异步调用代替)
在我下面的示例中,arcData array
代表我的 API
响应。
我可以通过 DOM manipulation
访问弧线。
在我的例子中,我使用 d3.selectAll('path.datamaps-arc').transition().duration(3500).style("opacity", 0);
慢慢淡出所有弧线,然后删除它们。
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>
这个解决方案基本有效,但是:
我的问题
同时隐藏所有圆弧。
如果以后异步调用API,当前正在画圆弧时会发生冲突,同时触发删除过程。
我想要的
一个解决方案,我可以通过一些标识符访问每个弧,并在它们完全绘制后单独删除它们。
好吧,我已经尽力解决你的问题了。我所做的是,我为每个数据映射弧分配了唯一的 ID。它会让您轻松访问独立的弧线,并且您可以相应地更改它们的过渡。
出于演示目的,我随机延迟了它并且它可以正常工作。我已将第一弧延迟 1000 毫秒,第二弧延迟 2000 毫秒,第三弧延迟 3000 毫秒。您可以根据需要实施自己的算法来延迟弧的过渡。我在代码中添加了注释,您可以参考。
由于setInterval是运行每4000毫秒后,如果任何弧的延迟超过4000毫秒,那么你将只能看到所有弧同时产生一次,这是第一次.以后弧线的生成会很随机,大家牢记就好了。
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>
希望它能解决您的问题。快乐编码!感谢您让我探索数据地图。
通过 DataMaps are actually keyed by their data
in JSON format (datamaps.js#L356 添加的所有弧线):
var arcs = layer.selectAll('path.datamaps-arc').data( data, JSON.stringify );
注意 DataMaps 使用 JSON.stringify
作为 关键函数 。 如果DataMaps在这里提供一种使用自定义键功能的方法就好了,但是唉...
虽然这些key本身并没有被持久化,但是足以保证我们对于一个相同的数据只会有一个arc。弧数据是弧标识符本身。
利用这些知识,我们可以通过比较数据来识别弧线:
var selectedArcs = d3.selectAll('path.datamaps-arc').filter(function(data) {
// compare data
return data === someValue;
});
更进一步,我们实际上可以调整我们传递给 DataMaps.arc
的数据,以便它实际上包含我们比较友好的标识符。 origin
和 destination
字段是必填字段,但我们可以根据自己的喜好自由使用任何其他字段。
{
id: 'some-unique-identifier',
origin: {
latitude: 52.520008,
longitude: 13.404954
},
destination: {
latitude: 37.618889,
longitude: -122.375
}
}
然后我们可以使用这个调整后的字段来识别我们的弧线:
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; meaning that two data with same id
but different origin
and or destination
value would be considered two different arc.
下面是使用原始示例的修改版本的简单演示:
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>
我创建了一张世界地图,使用 DataMaps。
我的目标是根据一些 API 数据在地图上异步显示和隐藏弧。
我已经尝试过什么
我每 5 秒调用一次 API
,并将响应数据推送到地图中。
(以后会被异步调用代替)
在我下面的示例中,arcData array
代表我的 API
响应。
我可以通过 DOM manipulation
访问弧线。
在我的例子中,我使用 d3.selectAll('path.datamaps-arc').transition().duration(3500).style("opacity", 0);
慢慢淡出所有弧线,然后删除它们。
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>
这个解决方案基本有效,但是:
我的问题
同时隐藏所有圆弧。 如果以后异步调用API,当前正在画圆弧时会发生冲突,同时触发删除过程。
我想要的
一个解决方案,我可以通过一些标识符访问每个弧,并在它们完全绘制后单独删除它们。
好吧,我已经尽力解决你的问题了。我所做的是,我为每个数据映射弧分配了唯一的 ID。它会让您轻松访问独立的弧线,并且您可以相应地更改它们的过渡。
出于演示目的,我随机延迟了它并且它可以正常工作。我已将第一弧延迟 1000 毫秒,第二弧延迟 2000 毫秒,第三弧延迟 3000 毫秒。您可以根据需要实施自己的算法来延迟弧的过渡。我在代码中添加了注释,您可以参考。
由于setInterval是运行每4000毫秒后,如果任何弧的延迟超过4000毫秒,那么你将只能看到所有弧同时产生一次,这是第一次.以后弧线的生成会很随机,大家牢记就好了。
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>
希望它能解决您的问题。快乐编码!感谢您让我探索数据地图。
通过 DataMaps are actually keyed by their data
in JSON format (datamaps.js#L356 添加的所有弧线):
var arcs = layer.selectAll('path.datamaps-arc').data( data, JSON.stringify );
注意 DataMaps 使用 JSON.stringify
作为 关键函数 。 如果DataMaps在这里提供一种使用自定义键功能的方法就好了,但是唉...
虽然这些key本身并没有被持久化,但是足以保证我们对于一个相同的数据只会有一个arc。弧数据是弧标识符本身。
利用这些知识,我们可以通过比较数据来识别弧线:
var selectedArcs = d3.selectAll('path.datamaps-arc').filter(function(data) {
// compare data
return data === someValue;
});
更进一步,我们实际上可以调整我们传递给 DataMaps.arc
的数据,以便它实际上包含我们比较友好的标识符。 origin
和 destination
字段是必填字段,但我们可以根据自己的喜好自由使用任何其他字段。
{
id: 'some-unique-identifier',
origin: {
latitude: 52.520008,
longitude: 13.404954
},
destination: {
latitude: 37.618889,
longitude: -122.375
}
}
然后我们可以使用这个调整后的字段来识别我们的弧线:
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; meaning that two data with sameid
but differentorigin
and ordestination
value would be considered two different arc.
下面是使用原始示例的修改版本的简单演示:
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>