phpIPAM使用leaflet.js加载并渲染地图,默认使用openstreetmap瓦片地图,由于众所周知的原因在国内无法加载openstreetmap底图。
经度娘了解尝试将openstreetmap地图切换为百度瓦片地图,过程如下:
一、准备
下载leaflet.ChineseTmsProviders.js到目录phpipam/js
cd /opt/phpiamp/js
wget https://jsdelivr.b-cdn.net/gh/htoooth/Leaflet.ChineseTmsProviders@master/src/leaflet.ChineseTmsProviders.js
二、使用百度API获取坐标
第一步
修改nominatim表的url字段,将openstreetmap API更换为百度地图API
http://api.map.baidu.com/geocoding/v3/?output=json&ak='Your baidu api key!'&address=
image.png
第二步
修改 phpipam/functions/classes/class.OpenStreetMap.php -> get_latlng_from_address()函数
/**
* Perform Geocoding lookup
*
* @param string $address
* @return array
*/
public function get_latlng_from_address($address) {
$results = ['lat' => null, 'lng' => null, 'error' => null];
if (!is_string($address) || is_blank($address)) {
$results['error'] = _('invalid address');
return $results;
}
if (Config::ValueOf('offline_mode')) {
$result['error'] = _('Internet access disabled in config.php');
return $result;
}
try {
// Obtain exclusive MySQL row lock
$Lock = new LockForUpdate($this->Database, 'nominatim', 1);
$elapsed = -microtime(true);
// Check cached results from the last 24h
$cached_result = $this->search_geo_cache($address, true);
if ($cached_result) {
$json = pf_json_decode($cached_result->lat_lng, true);
if (is_array($json)) {
return $json;
}
}
$url = $Lock->locked_row->url;
//$url = $url . "?format=json&q=" . rawurlencode($address);
//直接读取nominatim.url
$url = $url . rawurlencode($address);
$headers = [
'User-Agent: phpIPAM/' . VERSION_VISIBLE . ' (Open source IP address management)',
'Referer: ' . $this->createURL() . create_link()
];
// fetch geocoding data with proxy settings from config.php
$lookup = $this->curl_fetch_url($url, $headers);
if ($lookup['result_code'] != 200) {
// Lookup failed - Check cache again with no time limit.
$cached_result = $this->search_geo_cache($address, false);
if ($cached_result) {
$json = pf_json_decode($cached_result->lat_lng, true);
if (is_array($json)) {
return $json;
}
}
throw new \Exception($lookup['error_msg']);
}
$geo = pf_json_decode($lookup['result'], true);
if (!is_array($geo)) {
throw new \Exception(_('Invalid json response from nominatim'));
}
// if (isset($geo['0']['lat']) && isset($geo['0']['lon'])) {
// $results['lat'] = $geo['0']['lat'];
// $results['lng'] = $geo['0']['lon'];
// }
//百度地图API格式数据
if (isset($geo['result']['location']['lat']) && isset($geo['result']['location']['lng'])) {
$results['lat'] = $geo['result']['location']['lat'];
$results['lng'] = $geo['result']['location']['lng'];
}
$this->update_geo_cache($address, json_encode($results));
} catch (\Exception $e) {
$results = ['lat' => null, 'lng' => null, 'error' => $e->getMessage()];
}
// Ensure we hold the exclusive database lock for a minimum of 1 second
// (< 1 requests/s across all load-balanced instances of this app)
$elapsed += microtime(true);
if ($elapsed < 0) {
time_nanosleep(0, 1000000000);
} elseif ($elapsed < 1) {
time_nanosleep(0, 1000000000 * (1 - $elapsed));
}
return $results;
}
三、调用百度瓦片地图
第一步
修改phpipam/index.php,找到<script src="js/leaflet.fullscreen.min.js"></script>,在下面插入
<!--引入proj4,百度地图用-->
<script src="https://cdn.bootcss.com/proj4js/2.4.3/proj4.js"></script>
<script src="https://cdn.bootcss.com/proj4leaflet/1.0.1/proj4leaflet.min.js"></script>
<!-- 引入互联网地图插件 -->
<script src="js/leaflet.ChineseTmsProviders.js"></script>
第二步
修改 phpipam/functions/classes/class.OpenStreetMap.php -> map()函数
/**
* Output OpenStreetMap HTML/JS
*
* @param null|int $height
* @return void
*/
public function map($height = null)
{
if (sizeof($this->geodata) == 0) {
$this->Result->show("info", _("No Locations with coordinates configured"), false);
return;
}
?>
<div style="width:100%; height:<?php print isset($height) ? $height : "600px" ?>;" id="map_overlay">
<!--百度地图 div-->
<div id="map" style="width:100%; height:100%;"></div>
</div>
<script>
function osm_style(feature) {
return feature.properties && feature.properties.style;
}
function osm_onEachFeature(feature, layer) {
if (feature.properties && feature.properties.popupContent) {
layer.bindPopup(feature.properties.popupContent);
}
}
function osm_point_to_circle(feature, latlng) {
return L.circleMarker(latlng, {
radius: 8,
fillColor: "#ff7800",
color: "#000",
weight: 1,
opacity: 1,
fillOpacity: 0.8
});
}
var geodata = <?php print json_encode($this->geodata); ?>;
var polydata = <?php print json_encode($this->polydata); ?>;
// var mapOptions = {
// preferCanvas: true,
// attributionControl: true,
// zoom: -1,
// fullscreenControl: true,
// }
var mapOptions = {
crs: L.CRS.Baidu,
fullscreenControl: true,
zoom: 17,
layers:[]
}
var geoJSONOptions = {
style: osm_style,
onEachFeature: osm_onEachFeature,
pointToLayer: osm_point_to_circle,
}
// var layerOptions = {
// attribution: 'Map data © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
// }
// Creating a map object
// var map = new L.map('osmap', mapOptions);
var map = L.map('map',mapOptions);
// Add circuit lines
for (var key in polydata) {
var fmt = key.split('::::');
if (fmt[1] == "Solid") {
L.polyline(polydata[key], {
'color': fmt[0]
}).addTo(map);
} else {
L.polyline(polydata[key], {
'color': fmt[0],
dashArray: '20, 10'
}).addTo(map);
}
};
// Add location markers
geoJSON = L.geoJSON(geodata, geoJSONOptions).addTo(map);
map.fitBounds(geoJSON.getBounds());
// Add Tile layer
// var layer = new L.TileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', layerOptions);
var layer = L.tileLayer.chinaProvider('Baidu.Normal.Map').addTo(map);
map.addLayer(layer);
</script>
<?php
}
参考:
gisarmory/Leaflet.InternetMapCorrection: 互联网地图纠偏 (github.com)