react-leaflet的github地址:https://github.com/PaulLeCam/react-leaflet
react-leaflet-markercluster點聚合github地址 :https://github.com/YUzhva/react-leaflet-markercluster
本篇案例github地址:https://github.com/GugaLiz/ant-design-react-ProDemo
一、react-leaflet顯示多個marker點並顯示多行popup
1.注意點:安裝leaflet。 命令:npm install leaflet
![]()
2.裝好環境以后這里有兩個難點,①marker圖標重新引入。②popup多行顯示。
因為之前有踩過vue結合leaflet的坑、所以第一個問題這次跟vue里面重新引用圖標一樣解決了。第二個問題其實也不難、就是要靈活一點去試吧。因為官方文檔沒有寫這種情況,只是很簡單的示例。我先着重貼一下解決方案的代碼、后面有整體代碼結合理解。最后有我自己整理的github鏈接可以方便在實際開發中參考。
效果:

①。解決marker圖標重新引入,第一import Leaflet,第二把leaflet模塊中的markers文件夾復制到src路徑下的asset靜態資源文件夾中,第三重新引入圖標。
②。解決第二問題,第一把每一個marker需要多行顯示的popup的每一行都做成一個obj,這樣在第二步進行處理的時候就可以分開與樣式融合到一起。第二步處理popup
//處理popup的內容
整體代碼參上:
import React, { PureComponent, Fragment } from 'react';
import { render } from 'react-dom';
import { connect } from 'dva';
import { Row, Col, Card, Tooltip, Menu, Dropdown, Icon, Button,Layout } from 'antd';
import styles from './MapTest.less';
import L from 'leaflet';
import { Map, TileLayer,Marker,Popup } from 'react-leaflet';
import "leaflet/dist/leaflet.css";
const {Content} = Layout;
//把圖標重新引入
delete L.Icon.Default.prototype._getIconUrl
L.Icon.Default.imagePath = ''
L.Icon.Default.mergeOptions({
iconRetinaUrl: require('../../assets/markers/marker-icon-2x.png'),
iconUrl: require('../../assets/markers/marker-icon.png'),
shadowUrl: require('../../assets/markers/marker-shadow.png')
})
//處理每一個marker的顯示
const PopupMarker = ({ children,position }) => {
const items = children.map((item) => (<span key={item.key}>{item.string}<br /></span>))
return <Marker position={position}>
<Popup><div>
{items}
</div></Popup>
</Marker>
}
//處理markerlist
const MarkersList = ({markers}) => {
const items = markers.map(({ key,...props}) => (
<PopupMarker key={key} {...props} />
))
return <div>{items}</div>
}
export default class SiteMap extends PureComponent {
render() {
const position = [22.7047, 113.302]; //中心點
//模擬數據
const dataList = [];
for (let i = 0; i < 46; i += 1) {
dataList.push({
id: i,
Province: '',
Name: `site ${i}`,
Lat: 22.7047 + `${i}`,
Lng: 113.302 - `${i}`,
currentValue: Math.floor(Math.random() * 1000),
status: Math.floor(Math.random() * 10) % 2,
purchaseDate: new Date(`2017-07-${Math.floor(i / 2) + 1}`),
create_time: new Date(`2017-07-${Math.floor(i / 2) + 1}`),
progress: Math.ceil(Math.random() * 100),
Province: Math.floor(Math.random() * 10) % 2 ? '省份1' : '省份2',
City: Math.floor(Math.random() * 10) % 2 ? '城市1' : '城市2',
});
}
let cellPoints = [];
dataList.map(item => {
let lng = Number.parseFloat(item.Lng);
let lat = Number.parseFloat(item.Lat);
let name = item.Name;
let city = item.City || '';
let district = item.District || '';
let address = item.Address || '';
let maintainer = item.Maintainer || '';
let popupContent = [{key:city,string:`城市:${city}`},
{key:name,string:`基站名稱:${name}`},
{key:lng,string:`經度:${lng}`},
{key:lat,string:`緯度:${lat}`},
{key:district,string:`地區:${district}`},
{key:address,string:`地址:${address}`},
{key:maintainer,string:`維護人員:${maintainer}`},
]
cellPoints.push({key:name,position:[lat, lng],children:popupContent});
});
const style= {
width: '100%',
height: '600px',
}
return (
<Content>
<div className="ant-card-bordered" style={style}>
<Map center={position} zoom={13} style={{width: '100%', height: '100%'}}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<MarkersList markers={cellPoints} />
</Map>
</div>
</Content>
);
}
}
二、使用react-leaflet-markercluster點聚合顯示坐標點。
1.注意點:按照github上使用方法安裝好。 命令:
npm install react-leaflet-markercluster
npm install leaflet.markercluster leaflet react-leaflet prop-types

2.確保兩個都安裝上就可以使用了、文檔還蠻全的也是案例型、容易使用。我這里也只是簡單引用點聚合。我這里的方式是先定義marker樣式,然后引用,注意這里要在less文件里寫好聚合點樣式噢。
import React, { PureComponent, Fragment } from 'react';
import { render } from 'react-dom';
import { connect } from 'dva';
import { Row, Col, Card, Tooltip, Menu, Dropdown, Icon, Button,Layout } from 'antd';
import styles from './MapTest.less';
import L from 'leaflet';
import { Map, TileLayer } from 'react-leaflet';
import MarkerClusterGroup from 'react-leaflet-markercluster';
import "leaflet/dist/leaflet.css";
const {Content} = Layout;
//把圖標重新引入
delete L.Icon.Default.prototype._getIconUrl
L.Icon.Default.imagePath = ''
L.Icon.Default.mergeOptions({
iconRetinaUrl: require('../../assets/markers/marker-icon-2x.png'),
iconUrl: require('../../assets/markers/marker-icon.png'),
shadowUrl: require('../../assets/markers/marker-shadow.png')
})
// @connect(({ site, loading }) => ({
// site,
// loading: loading.models.site,
// }))
export default class SiteMap extends PureComponent {
// componentDidMount() {
// const { dispatch } = this.props;
// dispatch({
// type: 'site/fetch',
// });
// }
render() {
// const { site:{data}, loading } = this.props;
const position = [22.7047, 113.302];
//const dataList = { data }.data.list;
const dataList = [];
for (let i = 0; i < 46; i += 1) {
dataList.push({
id: i,
Province: '',
Name: `site ${i}`,
Lat: 22.7047 + `${i}`,
Lng: 113.302 - `${i}`,
currentValue: Math.floor(Math.random() * 1000),
status: Math.floor(Math.random() * 10) % 2,
purchaseDate: new Date(`2017-07-${Math.floor(i / 2) + 1}`),
create_time: new Date(`2017-07-${Math.floor(i / 2) + 1}`),
progress: Math.ceil(Math.random() * 100),
Province: Math.floor(Math.random() * 10) % 2 ? '省份1' : '省份2',
City: Math.floor(Math.random() * 10) % 2 ? '城市1' : '城市2',
});
}
let cellPoints = [];
const sytlep = {
width:'100%',
}
dataList.map(item => {
let lng = Number.parseFloat(item.Lng);
let lat = Number.parseFloat(item.Lat);
let name = item.Name;
let city = item.City || '';
let district = item.District || '';
let Address = item.Address || '';
let maintainer = item.Maintainer || '';
let popupDiv = `<div style={stylep}>
<span>城市:${city}</span>
<br />
<span>基站名稱:${name}</span>
<br />
<span>經度:${lng}</span>
<br />
<span>緯度:${lat}</span>
<br />
<span>地區:${district}</span>
<br />
<span>地址:${Address}</span>
<br />
<span>維護人員:${maintainer}</span>
<br />
</div>`
cellPoints.push({position:[lat, lng],popup:popupDiv});
});
const style= {
width: '100%',
height: '600px',
}
//定義聚合點樣式
const createClusterCustomIcon = function (cluster) {
return L.divIcon({
html: `<span>${cluster.getChildCount()}</span>`,
className: styles.markercustom,
iconSize: L.point(40, 40, true)
});
};
return (
<Content>
<div className="ant-card-bordered" style={style}>
<Map className={styles.markercluster} center={position} zoom={13} style={{width: '100%', height: '100%'}}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<MarkerClusterGroup
spiderfyDistanceMultiplier={2}
iconCreateFunction={createClusterCustomIcon}
markers={cellPoints}
/>
</Map>
</div>
</Content>
);
}
}
總結:
這里要注意記得把marker的圖片文件夾放入src/assets里面,不然會跑不起來的。
兩種用法文檔都有比較詳細的代碼可以參考。如果出不來效果多研究研究。
具體項目中的使用可以參考我的github的demo,會持續更新豐富。
