2016-10-23 34 views
0

(我的代碼是在端部)D3js投影問題擬合到BBOX當

我的目標是顯示一個國家地圖(在topojson文件中提供),其自動縮放和平移以適合的區域,並且然後在其上顯示幾個點,代表一些城市(給定它們的經緯度座標)。

第一部分很簡單。我發現(不記得是否在SO或bl.ocks.org上),我們可以使用邊界來計算比例和平移。這是完美的,我的國家適應其母區。

第一個問題:爲什麼,如果我縮放/它與它的翻譯變換屬性projection.scale().translate()國家的行爲不一樣呢?我的意思是,當我使用變換屬性該國適應完美,而projection.scale().translate()顯示一個角落裏的小國。

第二部分顯示了我地圖上的一些城市。我的城市的座標爲(這是真實的):

var cities = { 
    features: [ 
    { 
     'type':'Feature', 
     'geometry':{ 
      'type':'Polygon', 
      'coordinates': [2.351828, 48.856578] // Longitude, Latitude 
     }, 
     'properties':{} 
    }, 
    { 
     'type':'Feature', 
     'geometry':{ 
      'type':'Polygon', 
      'coordinates': [5.726945, 45.187778] // Longitude, Latitude 
     }, 
     'properties':{} 
    }, 

}; 

當我嘗試應用規模和翻譯參數(我的祖國,以適應已經縮放和翻譯)或者與projection.scale().translate()變換屬性我城市距離他們應該遠的地方很遠。

第二個問題:爲什麼我不能在國家和城市使用相同的比例/轉換參數?我該如何正確展示我的城市應該在哪裏?

function computeAutoFitParameters(bounds, width, height) { 
    var dx  = bounds[1][0] - bounds[0][0]; 
    var dy  = bounds[1][1] - bounds[0][1]; 
    var x   = (bounds[0][0] + bounds[1][0])/2; 
    var y   = (bounds[0][1] + bounds[1][1])/2; 
    var scale  = 0.9/Math.max(dx/width, dy/height); 
    var translate = [width/2 - scale * x, height/2 - scale * y]; 

    return { 
     scale : scale, 
     translate: translate 
    }; 
} 

// element is the HTML area where the country has to fit. 
var height  = element.height(); 
var width  = element.width(); 
var projection = d3.geo.miller(); 
var path  = d3.geo.path().projection(projection); 

// data is my country (a topojson file with BBox) 
var topojsonCountry = topojson.feature(data, data.objects[country.id]).features; 
var bounds   = path.bounds(topojsonCountry[0]); 
var params   = computeAutoFitParameters(bounds, width, height); 
var scale   = params.scale; 
var translate  = params.translate; 

var svg = d3.select(element[0]).append('svg') 
      .attr('width', width + 'px') 
      .attr('height', height + 'px'); 

svg.append('g') 
.selectAll('path') 
.data(topojsonCountry) 
.enter() 
.append('path') 
    .attr('d', path) 
    .attr('transform', 'translate(' + translate + ')scale(' + scale + ')'); 

svg.selectAll('circle') 
.data(cities.features) // city is defined in the code above 
.enter() 
.append('circle') 
    .attr('transform', function(d) { 
     return 'translate(' + projection(d.geometry.coordinates) + ')'; 
    ) 
    .attr('r', '6px'); 

編輯:我刪除了太多的代碼來簡化它。現在已經修復了。不同的是,我有一系列的城市可以展示,而不僅僅是一個。

在此先感謝。

+0

是否正在使用此代碼?它不應該是'return'translate('+ projection(city.geometries.coordinates)+')';'? –

+0

你說得對。在發佈之前清理我的代碼時,我刪除了太多的代碼。這很好。新的代碼正在工作,但沒有解決我的尺度/翻譯問題(對於我的城市),它​​們距離數毫米,而距離數釐米遠。 –

回答

0

我發現我不得不將null參數添加到我的投影中。綜上所述:

  1. 創建一個最小projection(和path
  2. 應用空scaletranslate參數給projection:根據邊框
  3. projection.scale(1).translate([0, 0])
  4. 計算實際scaletranslate參數像以前一樣顯示國家的地圖(這裏沒有變化)
  5. 組計算scaletranslate參數投影:projection.scale(params.scale).translate(params.translate);
  6. 繪製城市點。

`

// element is the HTML area where the country has to fit. 
var height  = element.height(); 
var width  = element.width(); 
var projection = d3.geo.miller(); 
var path  = d3.geo.path().projection(projection); 

projection.scale(1).translate([0, 0]) // This is new 

// data is my country (a topojson file with BBox) 
var topojsonCountry = topojson.feature(data, data.objects[country.id]).features; 
var bounds   = path.bounds(topojsonCountry[0]); 
var params   = computeAutoFitParameters(bounds, width, height); 

var svg = d3.select(element[0]).append('svg') 
    .attr('width', width + 'px') 
    .attr('height', height + 'px'); 

svg.append('g') 
    .selectAll('path') 
    .data(topojsonCountry) 
    .enter() 
    .append('path') 
     .attr('d', path) 
     .attr('transform', 'translate(' + params.translate + ')scale(' + params.scale + ')'); 

projection.scale(params.scale).translate(params.translate); // This is new 

svg.selectAll('circle') 
    .data(cities.features) 
    .enter() 
    .append('circle') 
    .attr('transform', function(d) { 
     return 'translate(' + projection(d.geometry.coordinates) + ')'; 
    }) 
    .attr('r', '6px') 
    .attr('fill', 'red');