openlayers是开源地图,地图瓦片清晰度和信息都没有商业地图那么完善,在此基础上,套上谷歌地图这一层皮就完美了!
墨卡托投影
OpenLayers 采用的是墨卡托投影,Google Maps也是墨卡托投影,那么在openlayers上显示的坐标和google应该可以是同一种坐标,设备上传的是gps经纬度,首先要把gps的位置显示在ol上,必须转换为ol的坐标系
// 广州珠江帝景坐标,源gps经纬度
var lonLat = [113.3219361305, 23.1067781880];
// 转换为ol坐标
var coord = ol.proj.transform(lonLat, 'EPSG:4326', 'EPSG:3857');
// 或者, 下面默认转3857坐标
var coord = ol.proj.fromLonLat(lonLat);
谷歌地图Tile
在ol中,声明瓦片的方法很简单
var osmLayer = new ol.layer.Tile({
source: new ol.source.OSM()
})
开源地图允许使用第三方瓦片,例如google map,百度地图,下面介绍google map的瓦片
谷歌国际化地图瓦片
var osmLayer = new ol.layer.Tile({
source: new ol.source.TileImage({url: 'http://maps.google.com/maps/vt?pb=!1m5!1m4!1i{z}!2i{x}!3i{y}!4i256!2m3!1e0!2sm!3i375060738!3m9!2spl!3sUS!5e18!12m1!1e47!12m3!1e37!2m1!1ssmartmaps!4e0'})
})
谷歌地域化地图瓦片
这种瓦片可以在不同国家显示不同语言,很强大
var osmLayer = new ol.layer.Tile({
source: new ol.source.OSM({
url: 'http://mt{0-3}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}',
attributions: [
new ol.Attribution({ html: '© Google' }),
new ol.Attribution({ html: '<a href="https://developers.google.com/maps/terms">Terms of Use.</a>' })
]
})
})
完美套上谷歌地图瓦片后,测试了一下,在中国同样的坐标系,在ol和google瓦片是有偏差的,美国,日本,韩国,香港,台湾暂时没发现这问题
美国华盛顿的坐标,上面是套的google地图,下面是ol地图
在中国,坐标明显有了偏移,红色的位置才是正确的
那么需要针对中国坐标稍作调整,可以看出,偏移量不是很大,那么在中国区域每次定位时候,只需要把偏移差给计算进去就行了
在调整坐标时候,发现坐标x和y偏移量有固定的偏差,x偏差约600,y偏差约-300,转换方法如下,after是正确的坐标
var before = ol.proj.transform(lonLat, 'EPSG:4326', 'EPSG:3857');
var offsetX = 600;
var offsetY = -300;
var after = [before[0] + offsetX, before[1] + offsetY];
最后展示的结果
中国地图纠正
上面解决了偏移问题,那么现在面临了另一个问题,如何判断GPS的经纬度是在中国区域呢?
调用google api,需翻墙,有访问限制
https://maps.googleapis.com/maps/api/geocode/json?latlng=11.2742848,75.8013801
$.get("https://maps.googleapis.com/maps/api/geocode/json?latlng=23.1082829028,113.3215552569", function(location) {
console.log(location);
var countryL = location.results[0].address_components[4].long_name;
var countryS = location.results[0].address_components[4].short_name
console.log(countryS) // CN
})
缺点:不同经纬度返回数组不确定,这样获取对应的国家代码也烦
调用 geoNames api,需翻墙,也有访问限制
http://ws.geonames.org/countryCodeJSON?lat=23.1067781880&lng=113.3219361305&username=kobe
$.get("http://ws.geonames.org/countryCodeJSON?lat=23.1067781880&lng=113.3219361305&username=kobe", function(location) {
var countryCode = location.countryCode; // CN
})
返回结果很简单,比google api方便处理
{"languages":"zh-CN,yue,wuu,dta,ug,za","distance":"0","countryCode":"CN","countryName":"China"}
turf库
turf这个库也是很牛逼,开发地图利器,坐标处理很强大,判断点是否在区域内
var linestring1 = turf.linestring([
[4.9020, 52.3667],
[4.9030, 52.3667],
[4.9040, 52.3667],
[4.9050, 52.3667]
]);
var pt1 = turf.point([4.9040, 52.3667]);
// 在区域内则返回对象,不在返回undefined
var intersection = turf.intersect(pt1, linestring1);
openlayers识别
综合上面的限制,觉得解决方法还不是很完美,想到了一个办法,通过地图坐标,绘制中国地图多边形,再判断坐标点是否在多边形内。
绘制多边形
在官方例子中发现了一个例子,很强大,把各个国家的范围区分出来了,对应的国家的geojson坐标地址,可以这里入口,把中国的区域坐标给取出来,绘制中国区域代码
var countrySource = new ol.source.Vector({
url: './china.geojson',
format: new ol.format.GeoJSON()
});
var countryLayer = new ol.layer.Vector({
source: countrySource
})
// 设置名字,容易获取
countryLayer.set("name", "chinaLayer");
var map = new ol.Map({
target: 'map',
layers: [
osmLayer, countryLayer
],
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
判断点是否在区域内
获取区域的多边形,然后使用intersectsCoordinate接口即可
map.getLayers().forEach(function(layer) {
if (layer.get("name") == 'chinaLayer') {
var source = layer.getSource();
// source是url加载,必須异步判断
source.on("change", function(evt) {
var src = evt.target;
if(src.getState() === 'ready'){
var features = source.getFeatures();
console.log(features[0].getGeometry())
var guangzhouLonLat = [113.3215552569, 23.1082829028];
var guangzhouPoint = ol.proj.fromLonLat(guangzhouLonLat, 'EPSG:3857');
var inChina = features[0].getGeometry().intersectsCoordinate(guangzhouPoint);
console.log(inChina);
}
})
}
})
上面方法是有点麻烦,而且速度不是很快,可以在不需要绘制到地图上来判断吗?又想到一个好办法,直接在新建feature去获取对应的多边形区域来判断,很好很强大
$.get("./countries.geojson", function (data) {
var lonLat = [113.3215552569, 23.1082829028];
// 華盛頓
// lonLat = [-77.0368707000, 38.9071923000];
var feature = (new ol.format.GeoJSON()).readFeatures(data);
var guangzhouLonLat = [113.3215552569, 23.1082829028];
var inChina = feature[0].getGeometry().intersectsCoordinate(guangzhouLonLat);
console.log(inChina) // true
})
参考资料
Finding country name from geolocation
check-if-a-point-falls-within-a-multipolygon-with-python
how-to-check-for-geometry-intersection-point-in-polygon-using-openlayers3