Javascript D3基数线插值看起来是错误的
我试图使用Javascript D3基数线插值看起来是错误的,javascript,svg,d3.js,leaflet,Javascript,Svg,D3.js,Leaflet,我试图使用d3.svg.line().interpolate()选项为用d3绘制的多边形提供平滑边,但我得到了奇怪的结果 我从nokia HERE api接收多边形数据作为世界坐标数据,格式为[lat1,long1,alt1,lat2,long2,alt2…],因此在routingCallback函数中(响应时调用该函数),我首先对其进行优化,使其看起来像这样[[lat1,long1],[lat2,long2]…]。在d3.svg.line()中,我使用这个坐标数组来计算像素位置。我用这个函数在
d3.svg.line().interpolate()
选项为用d3绘制的多边形提供平滑边,但我得到了奇怪的结果
我从nokia HERE api接收多边形数据作为世界坐标数据,格式为[lat1,long1,alt1,lat2,long2,alt2…]
,因此在routingCallback函数中(响应时调用该函数),我首先对其进行优化,使其看起来像这样[[lat1,long1],[lat2,long2]…]
。在d3.svg.line()中,我使用这个坐标数组来计算像素位置。我用这个函数在地图上画多边形。多边形的实际绘制发生在reset()中,该函数在数据可用且每次缩放地图时立即从routingCallback调用
var map = new L.Map("map", {"center": [52.515, 13.38], zoom: 12})
.addLayer(new L.TileLayer('http://{s}.tile.cloudmade.com/---account key---/120322/256/{z}/{x}/{y}.png'));
map.on("viewreset", reset);
var svg = d3.select(map.getPanes().overlayPane).append("svg"),
g = svg.append("g").attr("class", "leaflet-zoom-hide group-element"),
bounds = [[],[]],
polygon,
refinedData,
line = d3.svg.line()
.x(function(d) {
var location = L.latLng(d[0], d[1]),
point = map.latLngToLayerPoint(location);
return point.x;
})
.y(function(d) {
var location = L.latLng(d[0], d[1]),
point = map.latLngToLayerPoint(location);
return point.y;
})
.interpolate("cardinal"),
routingCallback = function(observedRouter, key, value) {
if(value == "finished") {
var rawData = observedRouter.calculateIsolineResponse.isolines[0].asArray(),
refinedData = [];
for(var i = 2; i < rawData.length; i += 3) {
var lon = rawData[i-1],
lat = rawData[i-2];
refinedData.push([lat, lon]);
}
if(polygon)
polygon.remove();
polygon = g
.data([refinedData])
.append("path")
.style("stroke", "#000")
.style("fill", "none")
.attr("class", "isoline");
reset();
}
if(value == "failed") {
console.log(observedRouter.getErrorCause());
}
};
getIsolineData = function(isoline) {
return data;
};
function reset() {
var xExtent = d3.extent(refinedData, function(d) {
var location = L.latLng(d[0], d[1]);
var point = map.latLngToLayerPoint(location);
return point.x;
});
var yExtent = d3.extent(refinedData, function(d) {
var location = L.latLng(d[0], d[1]);
var point = map.latLngToLayerPoint(location);
return point.y;
});
bounds[0][0] = xExtent[0];
bounds[0][1] = yExtent[0];
bounds[1][0] = xExtent[1];
bounds[1][1] = yExtent[1];
var topLeft = bounds[0],
bottomRight = bounds[1];
svg .attr("width", bottomRight[0] - topLeft[0])
.attr("height", bottomRight[1] - topLeft[1])
.style("left", topLeft[0] + "px")
.style("top", topLeft[1] + "px");
g .attr("transform", "translate(" + -topLeft[0] + "," + -topLeft[1] + ")");
polygon.attr("d", line);
}
var-map=newl.map(“map”,{“center”:[52.515,13.38],zoom:12})
.addLayer(新的L.TileLayer('http://{s}.tile.cloudmade.com//--account key--/120322/256/{z}/{x}/{y}.png');
地图打开(“视图重置”,重置);
var svg=d3.select(map.getPanes().overlypane).append(“svg”),
g=svg.append(“g”).attr(“类”,“传单缩放隐藏组元素”),
界限=[],[],
多边形,
精炼塔,
line=d3.svg.line()
.x(函数(d){
var位置=L.latLng(d[0],d[1]),
点=地图latLngToLayerPoint(位置);
返回点x;
})
.y(功能(d){
var位置=L.latLng(d[0],d[1]),
点=地图latLngToLayerPoint(位置);
返回点y;
})
.插入(“基数”),
routingCallback=函数(observedRouter、键、值){
如果(值=“已完成”){
var rawData=observedRouter.CalculateSolineResponse.isolines[0]。asArray(),
精炼数据=[];
对于(变量i=2;i
我希望这能产生平滑的边缘,但相反,我在每个角落都有一个小的环。红色覆盖是没有插值的同一多边形。在拐角处只有点。中间没有添加点
它是否与点的顺序有关(顺时针/逆时针)?我试图重新排列这些点,但似乎什么也没有发生。我可以重新创建您得到的图案的唯一方法是将每个顶点添加到路径两次。这在线性插值中不明显,但在程序尝试平滑连接点时会导致循环 编辑: 仔细看一下您的代码,问题似乎出在
calculatesolineresponse
函数中;我在传单API中没有看到这个名称,所以我假设它是自定义代码。您需要对其进行调试,以找出复制点的原因
如果无法更改该代码,简单的解决方案是通过过滤器运行points数组,该过滤器将删除重复的点:
refinedData = refinedData.filter(function(d,i,a){
return ( (!i) || (d[0] != a[i-1][0]) || (d[1] != a[i-1][1]) );
});
如果该过滤器是数组中的第一个点,或者lat或lon值与前一个点不同,则该过滤器将返回true。重复的点将返回false,并从数组中筛选出来。在这种情况下,点的顺序应该无关紧要——您可以发布一个完整的示例吗?您是否正试图通过在每个角点之前和之后添加点来创建圆角?在这种情况下,我认为您添加的前后顺序不正确。但更重要的是,我不认为有必要——基数插值的目的是用指定的关键点来平滑角点。通过更改line函数中的参数,您可以大致控制角的半径。@Larskothoff我更新了我的帖子并添加了一个更完整的示例。@AmeliaBR我添加了一个新的多边形图像。红色过度显示没有插值的多边形的外观。在拐角处只有点,没有添加任何内容inbetween@Flavio你能不能也发一份你的数据样本,这样我们就可以重现这个问题?太棒了,这就是问题所在!calculateIsolineResponse是nokia HERE路由器的一个属性,它包含响应,因此我无法修改它。但在细化数据后消除每一秒都是可行的。非常感谢!剩下的唯一一个问题是,为什么HERE api会将每个点返回两次:)?!