>

리플렛 줌 레벨 (0..22)을 부여하면 geoMercator 투영을위한 D3 스케일링 값을 어떻게 계산합니까? zoom = 0이면 전 세계가 단일 타일 (256x256)에 맞습니다. 타일에서 월드 크기는 2 ^ zoom x 2 ^ zoom 타일입니다.

  • 답변 # 1

    메르카토르 맵에 대한 d3 스케일과 비교 :

    메르카토르지도는 다음 공식을 사용합니다 :

    var point =  [x, Math.log(Math.tan(Math.PI / 4 + y / 2))]; 
    
    

    d3 맵의 스케일 팩터는 기본적으로 다음 변환을 적용합니다 :

      point[0] =  point[0] * k;
       point[1] =  -point[1] * k;
    
    

    d3 메르카토르 투영의 기본 맵 스케일은 961/2π 또는 961 픽셀 x 360 도입니다.

    메르카토르 공식의 단점 중 하나는 "전체"세계의 정사각형보기가 실제로 남/북쪽 ± 85.05113도에서 튀어 나오는 것입니다. 웹 메르카토르는 컨 포멀 프로젝션이 아니므로이를 푸시 할 수 있습니다. 리플렛은 "전체"세계의 범위를 북쪽/남쪽으로 ± 89.15도까지 밀어냅니다.

    따라서 적절한 메르카토르를 사용하는 d3과 웹 메르카토르를 사용하는 Leaflet은 스케일 값이 잘 맞지 않을 수 있음을 의미합니다. GIS.stackexchange에 대한이 답변은 둘 사이의 불일치에 대한 자세한 정보를 제공합니다.

    하지만 여전히 두 개를 정렬 할 수 있습니다 (대부분의 경우).

    <시간>

    아래 주석에서 Yurik이 언급 한 한 가지 방법은 확대/축소 수준과 타일 크기를 사용하여 배율을 얻는 것입니다.

    웹 맵 서비스는 확대/축소 수준을 높이면 표시된 타일 수가 4 배가되는 타일 그리드를 사용합니다. 확대/축소 수준 1에서 세계는 하나의 타일에, 확대/축소 수준 2에서 세계는 네 개의 사각형 타일에 맞습니다. 타일 ​​수에 대한 일반적인 공식은 다음과 같습니다.

    타일 수 = 4 ^ zoomLevel

    가장 중요한 것은 확대 할 때마다지도 (한 줄)를 통과하는 데 필요한 타일 수가 두 배가되는 것입니다.

    이를 시작점으로하여 두 가지를 일치시키는 방법을 알아낼 수 있습니다.

    d3 geoMercator는 961/(2*Math.PI) 를 사용합니다  기본 스케일로-이것은 적도의 360도 (또는 2 라디안)를 961 픽셀에 분산시킵니다. 타일 ​​기반 레이어에서 작동하도록 설정하려면 타일 크기와 확대/축소 수준 만 알면됩니다.

    우리가 사용하기 위해서는 적도가 얼마나 많은 픽셀에 퍼져 있는지 알아야합니다 :

    tileSize * Math.pow(2,zoomLevel)

    이것은 적도를 둘러싸는 모든 타일의 너비를 알려줍니다. 그런 다음이를 2Pi로 나누고 d3 스케일을 얻을 수 있습니다 :

    projection.scale(tileSize * Math.pow(2,zoomLevel) / (2 * Math.PI))

    d3 메르카토르와 웹 메르카토르의 차이로 인해 위치와 줌 거리에 따라 왜곡 문제가 발생할 수 있지만 대부분의 상황에서 좋은 정렬을 제공해야합니다.

    <시간>

    또는 전단지지도의 실제 모서리를 사용하여 적절한 척도를 결정할 수 있습니다 :

    D3에는 투영이 지리적 범위를 svg 범위에 맞출 수있는 방법이 있습니다. projection.fitExtent() . 이 방법은 지오 존 또는 지오메트리를 취합니다. 이 답변에서는 geojson을 사용하고 있습니다.

    .getBounds()  전단지 맵 범위를 반환하므로 geojson 경계 상자를 상당히 쉽게 만들 수 있습니다.

    var bbox = {
        "type": "Polygon",
        "coordinates": [
            [
                [mymap.getBounds()._northEast.lng, mymap.getBounds()._northEast.lat], 
                [mymap.getBounds()._northEast.lng, mymap.getBounds()._southWest.lat], 
                [mymap.getBounds()._southWest.lng, mymap.getBounds()._southWest.lat], 
                [mymap.getBounds()._southWest.lng, mymap.getBounds()._northEast.lat],
                [mymap.getBounds()._northEast.lng, mymap.getBounds()._northEast.lat]
            ]
        ]
    }
    
    

    권선 순서는 d3에서 실제로 중요합니다. 바깥 쪽 고리는 시계 반대 방향입니다.

    그런 다음 투영을 해당 범위에 맞게 설정하면됩니다 :

    var projection = d3.geoMercator()
       .fitSize([600, 400], bbox);
    
    

    약간 수정 된 전단지 예제 (중심점 및 확대/축소 변경)를 사용하면 전체 내용이 다음과 같습니다.

    	var features = {
      "type": "FeatureCollection",
      "features": [
        {
          "type": "Feature",
          "properties": {},
          "geometry": {
            "type": "Polygon",
            "coordinates": [
              [
                [
                  -0.17565250396728513,
                  51.510118018740904
                ],
                [
                  -0.17586708068847653,
                  51.509744084227556
                ],
                [
                  -0.17584562301635742,
                  51.50871574849058
                ],
                [
                  -0.17359256744384766,
                  51.50613812964363
                ],
                [
                  -0.17204761505126953,
                  51.50552375337273
                ],
                [
                  -0.16966581344604492,
                  51.50481587478995
                ],
                [
                  -0.16599655151367188,
                  51.50454874793857
                ],
                [
                  -0.1624774932861328,
                  51.504001132997686
                ],
                [
                  -0.16058921813964844,
                  51.5039744199054
                ],
                [
                  -0.16033172607421875,
                  51.50426826305929
                ],
                [
                  -0.16013860702514648,
                  51.5043884710761
                ],
                [
                  -0.16016006469726562,
                  51.50465559886706
                ],
                [
                  -0.15996694564819336,
                  51.50510971251776
                ],
                [
                  -0.16282081604003906,
                  51.505737450406535
                ],
                [
                  -0.16466617584228516,
                  51.5058710105437
                ],
                [
                  -0.16835689544677734,
                  51.50588436653591
                ],
                [
                  -0.1705455780029297,
                  51.506098061878475
                ],
                [
                  -0.17273426055908203,
                  51.506672363145654
                ],
                [
                  -0.17282009124755857,
                  51.50681927626061
                ],
                [
                  -0.17468690872192383,
                  51.508729103648925
                ],
                [
                  -0.17511606216430664,
                  51.50999782583918
                ],
                [
                  -0.17526626586914062,
                  51.510144728231545
                ],
                [
                  -0.17565250396728513,
                  51.510118018740904
                ]
              ]
            ]
          }
        }
      ]
    };
    
    	var mymap = L.map('mapid').setView([51.5, -0.171], 14);
    	L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
    		maxZoom: 18,
    		attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
    			'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
    			'Imagery © <a href="http://mapbox.com">Mapbox</a>',
    		id: 'mapbox.streets'
    	}).addTo(mymap);
    	
    	var svg = d3.select('#mapid')
    	  .append('svg')
    	  .attr('width',600)
    	  .attr('height',400);
    	
    	
    	
    	// Create a geojson bounding box:
    	var bbox = {
    		"type": "Polygon",
    		"coordinates": [
    			[
    				[mymap.getBounds()._northEast.lng, mymap.getBounds()._northEast.lat], 
    				[mymap.getBounds()._northEast.lng, mymap.getBounds()._southWest.lat], 
    				[mymap.getBounds()._southWest.lng, mymap.getBounds()._southWest.lat], 
    				[mymap.getBounds()._southWest.lng, mymap.getBounds()._northEast.lat],
    			    [mymap.getBounds()._northEast.lng, mymap.getBounds()._northEast.lat]
    			]
    		]
        }
    	
    	
    	var projection = d3.geoMercator()
    	   .fitSize([600, 400], bbox);
    	
    	var path = d3.geoPath().projection(projection);
    	
    	svg.append("path")
    	  .datum(features)
    	  .attr('d',path);
    	
    
    

    		svg {
    			z-index: 10000;
    			position: relative;
    		}
    	
    
    

    <div id="mapid" style="width: 600px; height: 400px;"></div>
    	
    	<link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
        <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" integrity="sha512-07I2e+7D8p6he1SIM+1twR5TIrhUQn9+I6yjqD53JQjFiMf8EtC93ty0/5vJTZGF8aAocvHYNEDJajGdNx1IsQ==" crossorigin=""/>
        <script src="https://unpkg.com/[email protected]/dist/leaflet.js" integrity="sha512-A7vV8IFfih/D732iSSKi20u/ooOfj/AGehOKq0f4vLT1Zr2Y+RX7C+w8A1gaSasGtRUZpF/NZgzSAu4/Gc41Lg==" crossorigin=""></script>
    	
    	<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.js"></script>
    
    

    지도가 변경 될 때 투영을 업데이트하기위한 코드를 추가하지 않았지만 이는 단순히 경계 상자를 다시 계산하고 fitSize 메서드를 적용하는 것입니다.

  • 이전 androiddatabasesqlitesqliteexception"selectamountfromnilanjan_tablewherename" - 구문 오류 (코드 1)가 표시됩니다
  • 다음 Swagger Codegen 기존 클래스 사용