独立坐标的栅格瓦片与矢量(geoJson)地图在Leaflet下加载
一、 前言
利用web加载栅格与矢量地图,大多是基于WGS84 ,或者 web墨卡托。但是在实际过程中,也存在非WGS 84的独立地理坐标,如:游戏地图、CAD作图….我查看了许多开源的地图map容器,leaflet (https://leafletjs.com/) 与 openLayers (http://openlayers.org/) 支持这种独立坐标,窗体的话可以利用sharpMap(https://github.com/SharpMap/SharpMap)。
二、准备工作
本案例要讲的是CAD作图后如何与栅格底图配准并展示在Leaflet。如果只是单纯的游戏地图,可以参考 https://leafletjs.com/examples/crs-simple/crs-simple.html。
数据源:①.栅格底图(可以利用地图下载器)合并成一张大图用于配准,之后可以利用MapTiler转成瓦片或者用GDAL的gdal2tiles.py。
②.独立坐标矢量图层从CAD出图后,利用ArcEngine 或者GDAL转成shp 格式。
三、步骤
3.1).首先在SharpMap窗体中对两个图层进行配准。
①可以通过ArcEngine提供的方法(网上查找)。
②还可以自己写仿射变换,然后重采样,具体利用的是Emgu.CV.CvInvoke.GetAffineTransform 方法,但是发现效果没有AE的好。
3.2)再利用gdal 将shp矢量转geoJson,将配准后的栅格大图转瓦片。
3.3)此时将两个在Leaflet上加载,其中投影需要利用L.CRS.Simple,加载geoJson 利用L.SvgScaleOverlay() (http://bl.ocks.org/Sumbera/7e8e57368175a1433791),栅格瓦片利用 L.tileLayer。
3.4)贴上 Leaflet 的代码:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>栅格and矢量</title>
<link rel="stylesheet" href="http://www.sumbera.com/gist/js/leaflet/svg/scaled/leaflet.css" />
<style>
body {
margin: 0px;
}
#map {
position: absolute;
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<!-- Base libraries-->
<script src="http://www.sumbera.com/gist/js/leaflet/svg/scaled/d3-3.5.5.min.js"></script>
<script src="http://www.sumbera.com/gist/js/leaflet/svg/scaled/leaflet.js"></script>
<script src="L.SvgScaleOverlay.js"></script> <!--http://bl.ocks.org/Sumbera/7e8e57368175a1433791 -->
<script src="test.js" charset="utf-8"></script> <!-- 该JS 是geoJson对象数组-->
<div id="map">
</div>
<div id="tooltip" style="width:230px; height:100px;">
</div>
<script>
var mapExtent = [533435.6179770336, 3120955.497304902, 535565.1120320936,3124568.6378654544]; //minX minY maxX maxY
var mapMinZoom = 0;
var mapMaxZoom = 4;
var mapMaxResolution = 1.0605050075; //你的图像的分辨率 (在tfw 文件中的第一行) (tfw 文件是tif 的地理格式文件)
var mapMinResolution = Math.pow(2, mapMaxZoom) * mapMaxResolution;;
var tileExtent = [533435.6179770336, 3120955.497304902, 535565.1120320936,3124568.6378654544];
var crs = L.CRS.Simple;
crs.transformation = new L.Transformation(1, -tileExtent[0], -1, tileExtent[3]);
crs.scale = function(zoom) {
return Math.pow(2, zoom) / mapMinResolution;
};
crs.zoom = function(scale) {
return Math.log(scale * mapMinResolution) / Math.LN2;
};
var layer;
var lmap = new L.Map('map', {
maxZoom: 10,
minZoom: mapMinZoom,
crs: crs
});
lmap.fitBounds([
crs.unproject(L.point(mapExtent[2], mapExtent[3])),
crs.unproject(L.point(mapExtent[0], mapExtent[1]))
]);
var layer;
layer = L.tileLayer('tile/{z}/{x}/{y}.png', {
minZoom: mapMinZoom,
maxZoom: 10,
maxNativeZoom: mapMaxZoom,
attribution: 'Rendered with <a href="https://leafletjs.com/">Leaflet</a>',
noWrap: false,
tms: false
});
lmap.addLayer(layer);
var circles;
var svgOverlay = L.SvgScaleOverlay();
var radius = 2;
lmap.on("click",function(e){
console.log(e);
});
//------------------------------------------------------------
var datas =[];
for(var i = 0;i<myGeoJson.features.length;i++){ //myGeoJson是我geoJson对象的名字,我的geoJson是地形图
datas.push( myGeoJson.features[i].geometry.coordinates); //
}
<!-- window.load = function(){ -->
<!-- console.log( euCountries); -->
<!-- for(var i = 0;i<euCountries.features.length;i++){ -->
<!-- datas.push( euCountries.features[i].geometry.coordinates); -->
<!-- } -->
<!-- } -->
svgOverlay.onInitData = function () {
if (!circles) {
var g = d3.select(this._g);
circles = g.selectAll("polyline")
.data(datas)
.enter().append('polyline');
// -- opacity based on grouping optimization in point data
circles.attr('stroke','blue');
circles.attr('stroke-width','1');
//circles.style("fill-opacity", 0.8);
circles.style("fill", "none");
}
circles.each(function (d) {
var elem = d3.select(this);
var points = [];
for(var i=0; i<d.length;i++){
try{
var point = lmap.project(L.latLng(new L.LatLng(d[i][1], d[i][0])))._subtract(lmap.getPixelOrigin());
var svgPoint = svgOverlay._svg.createSVGPoint();
svgPoint.x = point.x; svgPoint.y = point.y;
elem[0][0].points.appendItem(svgPoint);
}catch(err){
console.log(err);
}
}
})
};
svgOverlay.onScaleChange = function (scaleDiff) {
if (scaleDiff > 0.5) {
var newRadius = radius * 1 / scaleDiff;
//newRadius = crs.scale(scaleDiff);
var currentRadius = d3.select('polyline').attr("stroke-width");
if (currentRadius != newRadius) {
d3.selectAll("polyline").attr('stroke-width', newRadius);
}
}
}
lmap.addLayer(svgOverlay);
/***********************/
</script>
</body>
</html>
其中 需要自行设置的是①.geoJson文件的加载。
②.栅格图像的范围大小与分辨率大小。
我的geoJson 文件用的是JS 加载方式 在<head>
中引入,因为谷歌浏览器的同源策略。
底图的范围大小 以及栅格的分辨率的设置,即:
这些参数都可以在下图的tfw文件中计算而得,tfw不懂的请自行google。
下一篇: css实现箭头效果