2014-02-08 4 views
1

d3.svg.line().interpolate() 옵션을 사용하여 d3 - smooth edges로 그려진 다각형을주고 싶지만 이상한 결과가 나타납니다. 그것은이 [[lat1, long1], [lat2, long2] ...]처럼 보이는, 그래서 내가 먼저 수정 - 응답이있을 때 호출 -D3 추기경 보간이 잘못되었습니다.

내가 세계로 API는 그래서 routingCallback 함수 형태 [lat1, long1, alt1, lat2, long2, alt2 ...]에 좌표 데이터를 여기에 노키아에서 폴리곤 데이터를받을 수 있습니다. d3.svg.line()에서이 좌표 배열을 사용하여 픽셀 위치를 계산합니다.을 사용하여 맵에 다각형을 그려서 map.latLngToLayerPoint() 함수를 사용합니다. 다각형의 실제 그림은 데이터를 사용할 수있는 모든 시간이지도가 나는이 부드러운 가장자리를 생산하는 기대하지만, 대신에 난 작은 얻을

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

을 확대 도착 직후 routingCallback에서 호출 리셋()에서 발생 모든 구석에 루프. 빨간색 오버레이는 보간없이 동일한 다각형입니다. 구석에만 포인트가 있습니다. 포인트가 없습니다.

strange looking corners when using d3 cardinal interpolation. red overlay is the same polygon without interpolation

그것은 점 (시계 방향/반 시계 방향)의 순서와 함께 할 수있는 뭔가가 있나요? 포인트를 재 배열하려고했지만 아무 일도 일어나지 않았다.

+1

이 경우 점의 순서는 중요하지 않습니다. 전체 예제를 게시 할 수 있습니까? –

+1

각 구석의 직전 및 직후에 점을 추가하여 둥근 모서리를 만들려고합니까? 어떤 경우에는 잘못된 순서로 앞뒤에 추가한다고 생각합니다. 하지만 요점은 더 이상 필요하지 않다고 생각합니다. 추기경 보간은 지정된 핵심 포인트 만 사용하여 모서리를 부드럽게 만듭니다. 선 기능에서 [장력] (https://github.com/mbostock/d3/wiki/SVG-Shapes#wiki- line_tension) 매개 변수를 변경하여 모퉁이의 반경을 대략 제어 할 수 있습니다. – AmeliaBR

+0

@LarsKotthoff 내 게시물을 업데이트하고보다 완벽한 예를 추가했습니다. – Flavio

답변

3

경로에 모든 정점을 추가하는 경우 패턴을 다시 만들 수있는 유일한 방법은 두 번입니다. 선형 보간에서는 눈에 띄지 않지만 프로그램이 점을 부드럽게 연결하려고하면 루프가 발생합니다.

http://fiddle.jshell.net/weuLs/

편집 : 문제가 당신의 calculateIsolineResponse 기능에 같은 코드를 자세히 살펴보면

, 그것은 보인다; 내가 Leaflet API에 그 이름이 보이지 않기 때문에 그것이 사용자 정의 코드라고 가정합니다. 점을 복제하는 이유를 파악하려면 디버깅해야합니다. 하나는 첫 번째 지점 인 경우에

refinedData = refinedData.filter(function(d,i,a){ 
     return ((!i) || (d[0] != a[i-1][0]) || (d[1] != a[i-1][1])); 
    }); 

하는 필터가 true를 돌려 것이다 : 당신이 그 코드를 변경할 수없는 경우

, 간단한 솔루션은 중복 된 점을 제거하는 필터를 통해 점 배열을 실행하는 것입니다 배열에서 또는 lat 또는 lon 값이 이전 점과 다른 경우 중복 된 점은 false를 반환하고 배열에서 필터링됩니다.

+1

신난다, 그것은 정확한 문제이었다!calculateIsolineResponse는 응답을 포함하는 노키아 HERE 라우터의 속성이므로 수정할 수 없습니다. 그러나 데이터를 정제 한 후 모든 두 번째 지점을 제거하면됩니다. 매우 감사합니다! 남은 유일한 질문은 여기 API가 왜 두 번씩 모든 포인트를 반환하는지입니다. – Flavio

관련 문제