react-leaflet的github地址:https://github.com/PaulLeCam/react-leafletcss
react-leaflet-markercluster點聚合github地址 :https://github.com/YUzhva/react-leaflet-markerclusterhtml
本篇案例github地址:https://github.com/GugaLiz/ant-design-react-ProDemovue
1、react-leaflet顯示多個marker點並顯示多行popupreact
1.注意點:安裝leaflet。 命令:npm install leafletgit
2.裝好環境之後這裏有兩個難點,①marker圖標從新引入。②popup多行顯示。github
由於以前有踩過vue結合leaflet的坑、因此第一個問題此次跟vue裏面從新引用圖標同樣解決了。第二個問題其實也不難、就是要靈活一點去試吧。由於官方文檔沒有寫這種狀況,只是很簡單的示例。我先着重貼一下解決方案的代碼、後面有總體代碼結合理解。最後有我本身整理的github連接能夠方便在實際開發中參考。npm
效果:antd
①。解決marker圖標從新引入,第一import Leaflet,第二把leaflet模塊中的markers文件夾複製到src路徑下的asset靜態資源文件夾中,第三從新引入圖標。less
②。解決第二問題,第一把每個marker須要多行顯示的popup的每一行都作成一個obj,這樣在第二步進行處理的時候就能夠分開與樣式融合到一塊兒。第二步處理popupdom
//處理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> ); } }
2、使用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,會持續更新豐富。