10 changed files with 580 additions and 100 deletions
@ -0,0 +1,470 @@ |
|||||
|
import React, { useEffect, useState } from 'react'; |
||||
|
import { connect } from 'react-redux'; |
||||
|
import { render } from 'react-dom'; |
||||
|
import { data as heatmapData } from './data' |
||||
|
import { SHUI_ZHAN } from '../constants/water'; |
||||
|
import './gis.less' |
||||
|
const MAPDOMID = 'fs-amap-container1'; |
||||
|
let map = null; |
||||
|
let heatmap = null; |
||||
|
let loca = null; |
||||
|
let gridLayer = null; |
||||
|
let interval = null; |
||||
|
const MARKER_IMG_NAME = { |
||||
|
markergreen: '回迁房', |
||||
|
markerblue: '城中村', |
||||
|
markeryellow: '廉租房', |
||||
|
} |
||||
|
function Map(props) { |
||||
|
const { trendData, waterLevelAlarms } = props; |
||||
|
const [delay, setDelay] = useState(true) |
||||
|
const [tab, setTab] = useState('overview') |
||||
|
|
||||
|
// 地图初始化
|
||||
|
const loadMap = () => { |
||||
|
// 图片图层 实现瓦片地图中国地图样式 bounds 第一个点为左下角 第二个点为右上角
|
||||
|
const imageLayer = new AMap.ImageLayer({ |
||||
|
url: '/assets/images/map1.svg', |
||||
|
bounds: new AMap.Bounds( |
||||
|
[115.800221, 28.225659], |
||||
|
[116.334849, 28.973298], |
||||
|
), |
||||
|
zooms: [3, 14], |
||||
|
}); |
||||
|
|
||||
|
map = new AMap.Map(MAPDOMID, { |
||||
|
center: [116.054664, 28.538966], |
||||
|
zoomEnable: true, |
||||
|
dragEnable: true, |
||||
|
viewMode: '3D', |
||||
|
pitch: 22.9, |
||||
|
labelzIndex: 130, |
||||
|
zoom: 10.3, |
||||
|
cursor: 'pointer', |
||||
|
mapStyle: 'amap://styles/300b147a96946a4f1c1b1b8eb1f92f76', |
||||
|
layers: [ |
||||
|
AMap.createDefaultLayer(), |
||||
|
imageLayer, |
||||
|
], |
||||
|
}); |
||||
|
|
||||
|
map.on('complete', () => { |
||||
|
setTimeout(() => { |
||||
|
setDelay(false) |
||||
|
map && renderMarkers() |
||||
|
map && renderAlarms() |
||||
|
}, 1500); |
||||
|
}); |
||||
|
|
||||
|
map.on('click', (e) => { |
||||
|
if (!e && !e.lnglat) { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
const zoom = map.getZoom(); |
||||
|
const pitch = map.getPitch(); |
||||
|
const center = map.getCenter(); |
||||
|
const Rotation = map.getRotation(); |
||||
|
console.log('zoom' + zoom) |
||||
|
console.log('pitch' + pitch) |
||||
|
console.log('center' + center) |
||||
|
console.log('Rotation' + Rotation) |
||||
|
console.log('e.lnglat' + e.lnglat) |
||||
|
}) |
||||
|
|
||||
|
loca = new Loca.Container({ map: map }) |
||||
|
// { map && renderMarkers() }
|
||||
|
// { map && renderAlarms() }
|
||||
|
// setTimeout(() => {
|
||||
|
// renderLayer()
|
||||
|
// createText()
|
||||
|
// }, 1000);
|
||||
|
}; |
||||
|
|
||||
|
const createText = () => { |
||||
|
var text = new AMap.Text({ |
||||
|
text: '南昌县', |
||||
|
anchor: 'center', // 设置文本标记锚点
|
||||
|
draggable: false, |
||||
|
// cursor: 'pointer',
|
||||
|
zooms: [3, 11], |
||||
|
style: { |
||||
|
'padding': '.75rem 1.25rem', |
||||
|
'margin-bottom': '1rem', |
||||
|
'border-radius': '.25rem', |
||||
|
'background-color': 'rgba(238,77,90,0.001)', |
||||
|
'width': '8rem', |
||||
|
'border-width': 0, |
||||
|
//'box-shadow': '0 2px 6px 0 rgba(255, 255, 255, .1)',
|
||||
|
'text-align': 'center', |
||||
|
'font-size': '14px', |
||||
|
'color': '#AFEFFF', |
||||
|
'opacity': 1, |
||||
|
// 'font-weight': 'bold'
|
||||
|
}, |
||||
|
position: [115.934664, 28.538966] |
||||
|
}); |
||||
|
text.setMap(map); |
||||
|
|
||||
|
} |
||||
|
const drawBounds = () => { |
||||
|
let district = null; |
||||
|
let polygons = []; |
||||
|
//加载行政区划插件
|
||||
|
if (!district) { |
||||
|
//实例化DistrictSearch
|
||||
|
let opts = { |
||||
|
subdistrict: 0, //获取边界不需要返回下级行政区
|
||||
|
extensions: 'all', //返回行政区边界坐标组等具体信息
|
||||
|
level: 'district' //查询行政级别为 市
|
||||
|
}; |
||||
|
district = new AMap.DistrictSearch(opts); |
||||
|
} |
||||
|
//行政区查询
|
||||
|
district.setLevel('district') |
||||
|
district.search('南昌县', function (status, result) { |
||||
|
map.remove(polygons)//清除上次结果
|
||||
|
polygons = []; |
||||
|
let bounds = result.districtList[0].boundaries; |
||||
|
if (bounds) { |
||||
|
for (let i = 0, l = bounds.length; i < l; i++) { |
||||
|
//生成行政区划polygon
|
||||
|
let polygon = new AMap.Polygon({ |
||||
|
strokeWeight: 1, |
||||
|
path: bounds[i], |
||||
|
fillOpacity: 0.4, |
||||
|
fillColor: '#1F2F4D', |
||||
|
strokeColor: '#DE7B35', |
||||
|
fillOpacity: 0.35, //填充透明度
|
||||
|
}); |
||||
|
polygons.push(polygon); |
||||
|
} |
||||
|
} |
||||
|
map.add(polygons) |
||||
|
// map.setFitView(polygons);//视口自适应
|
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 初始化GIS 组件销毁清空定时器
|
||||
|
useEffect(() => { |
||||
|
loadMap(); |
||||
|
}, [trendData, waterLevelAlarms]); |
||||
|
|
||||
|
const renderMarkers = () => { |
||||
|
map.clearMap(); |
||||
|
map.setZoom(10.3) |
||||
|
map.setCenter([116.054664, 28.538966]) |
||||
|
map.setPitch(22.9) |
||||
|
map.setRotation(1.7000) |
||||
|
if (loca && heatmap) loca.remove(heatmap) |
||||
|
|
||||
|
//初始层级 zoom14以下显示聚合点
|
||||
|
// const data = [
|
||||
|
// { lng: 116.117906, lat: 28.678096, type: 'home', name: '泵站1', kind: 'markergreen' },
|
||||
|
// { lng: 116.195238, lat: 28.842114, type: 'home', name: '泵站2', kind: 'markerblue' },
|
||||
|
// { lng: 116.037227, lat: 28.558811, type: 'home', name: '泵站3', kind: 'markeryellow' },
|
||||
|
// { lng: 115.925856, lat: 28.558811, type: 'home', name: '泵站4', kind: 'markergreen' },
|
||||
|
// { lng: 115.989847, lat: 28.484411, type: 'home', name: '泵站5', kind: 'markergreen' },
|
||||
|
// ]
|
||||
|
|
||||
|
//初始点位显示
|
||||
|
SHUI_ZHAN.map((x, index) => { |
||||
|
var marker = new AMap.Marker({ |
||||
|
position: new AMap.LngLat(x.location[0], x.location[1]), |
||||
|
// 将一张图片的地址设置为 icon
|
||||
|
icon: '/assets/images/homepage/water/_monitor.png', |
||||
|
// 设置了 icon 以后,设置 icon 的偏移量,以 icon 的 [center bottom] 为原点
|
||||
|
offset: new AMap.Pixel(-13, -30), |
||||
|
zooms: [3, 14], |
||||
|
}); |
||||
|
marker.setTitle(x.name); |
||||
|
map.add(marker); |
||||
|
let infowindow = new AMap.InfoWindow({ |
||||
|
isCustom: true, //使用自定义窗体
|
||||
|
content: `<div id="map-content" class="water-gis-infowindow">
|
||||
|
<div style="height:${360}px;" id="contentid${x.name}"></div></div>`, |
||||
|
offset: new AMap.Pixel(153, 260) |
||||
|
}); |
||||
|
|
||||
|
marker.on('click', () => { |
||||
|
let position = marker.getPosition ? marker.getPosition() : marker.getCenter(); |
||||
|
infowindow.open(map, position); |
||||
|
map.setCenter(position) |
||||
|
setTimeout(() => { |
||||
|
if (document.getElementById(`contentid${x.name}`)) { |
||||
|
render(<div> |
||||
|
<div className='gis_exit' onClick={() => { |
||||
|
map.setCenter([115.922069, 28.554867]) |
||||
|
map.clearInfoWindow(); |
||||
|
}} /> |
||||
|
<div className='gis_item'> |
||||
|
<span className='gis_title'>泵站名称:</span> |
||||
|
<span className='gis_text'>{x.name}</span> |
||||
|
</div> |
||||
|
<div className='gis_item'> |
||||
|
<span className='gis_title'>1#提升泵:</span> |
||||
|
<div className='gis_text_on'> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div className='gis_item'> |
||||
|
<span className='gis_title'>2#提升泵:</span> |
||||
|
<div className='gis_text_on'> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div className='gis_item'> |
||||
|
<span className='gis_title'>3#提升泵:</span> |
||||
|
<div className='gis_text_off'> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div>, |
||||
|
document.getElementById(`contentid${x.name}`)); |
||||
|
} |
||||
|
}, 50) |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
|
||||
|
if (tab == 'device') { |
||||
|
const data = [ |
||||
|
{ lng: 115.921895, lat: 28.556351, type: 'device', name: '廉租房1', kind: 'devicemarker' }, |
||||
|
{ lng: 115.920839, lat: 28.555323, type: 'device', name: '廉租房2', kind: 'devicemarker' }, |
||||
|
{ lng: 115.918329, lat: 28.55445, type: 'device', name: '廉租房3', kind: 'devicemarker' }, |
||||
|
{ lng: 115.919309, lat: 28.553166, type: 'device', name: '廉租房1', kind: 'devicemarker' }, |
||||
|
{ lng: 115.921585, lat: 28.553925, type: 'device', name: '廉租房2', kind: 'devicemarker' }, |
||||
|
{ lng: 115.92565, lat: 28.556996, type: 'device', name: '廉租房3', kind: 'devicemarker' }, |
||||
|
{ lng: 115.922671, lat: 28.558769, type: 'device', name: '廉租房1', kind: 'devicemarker' }, |
||||
|
] |
||||
|
|
||||
|
data.filter(s => s.type == tab).map((x, index) => { |
||||
|
var marker = new AMap.Marker({ |
||||
|
position: new AMap.LngLat(x.lng, x.lat), |
||||
|
// 将一张图片的地址设置为 icon
|
||||
|
icon: '/assets/images/homepage/communtity/' + x.kind + '.png', |
||||
|
// 设置了 icon 以后,设置 icon 的偏移量,以 icon 的 [center bottom] 为原点
|
||||
|
offset: new AMap.Pixel(-13, -30), |
||||
|
zooms: [15, 19], |
||||
|
}); |
||||
|
marker.setTitle(x.name); |
||||
|
map.add(marker); |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
const renderAlarms = () => { |
||||
|
if (tab == 'person' || !waterLevelAlarms.length || !trendData.length) { |
||||
|
return; |
||||
|
} |
||||
|
const alarms = waterLevelAlarms.map(a => { |
||||
|
let alarm = { |
||||
|
lng: a.lng, |
||||
|
lat: a.lat, |
||||
|
// type: 'device',
|
||||
|
name: a.alarms[0]?.source.name, |
||||
|
kind: 'markeralarm' |
||||
|
}; |
||||
|
for (const t of trendData) { |
||||
|
if (t?.id == a.alarms[0]?.source.id) { |
||||
|
alarm.waterLevel = t.waterLevel; |
||||
|
alarm.alert = t.alert; |
||||
|
} |
||||
|
} |
||||
|
return alarm; |
||||
|
}) |
||||
|
alarms.map((x, index) => { |
||||
|
var marker = new AMap.Marker({ |
||||
|
position: new AMap.LngLat(x.lng, x.lat), |
||||
|
// 将一张图片的地址设置为 icon
|
||||
|
icon: '/assets/images/homepage/communtity/' + x.kind + '.png', |
||||
|
// 设置了 icon 以后,设置 icon 的偏移量,以 icon 的 [center bottom] 为原点
|
||||
|
offset: new AMap.Pixel(-13, -30), |
||||
|
zooms: [3, 14], |
||||
|
zIndex: 13, |
||||
|
}); |
||||
|
marker.setTitle(x.name); |
||||
|
map.add(marker); |
||||
|
|
||||
|
let infowindow = new AMap.InfoWindow({ |
||||
|
isCustom: true, //使用自定义窗体
|
||||
|
content: `<div id="map-content" class="gis-infowindow-alarm">
|
||||
|
<div style="height:${360}px;" id="alarmcontentid${x.name}"></div></div>`, |
||||
|
offset: new AMap.Pixel(233, 260) |
||||
|
}); |
||||
|
|
||||
|
let alarmOk = new AMap.InfoWindow({ |
||||
|
isCustom: true, //使用自定义窗体
|
||||
|
// content: `<div id="map-content" class="gis-infowindow gis-infowindow-alarm">
|
||||
|
// <div style="height:${360}px;" id="contentid${x.name}"></div></div>`,
|
||||
|
offset: new AMap.Pixel(233, 440) |
||||
|
}); |
||||
|
|
||||
|
marker.on('click', () => { |
||||
|
let position = marker.getPosition ? marker.getPosition() : marker.getCenter(); |
||||
|
infowindow.open(map, position); |
||||
|
// map.setCenter(position)
|
||||
|
setTimeout(() => { |
||||
|
if (document.getElementById(`alarmcontentid${x.name}`)) { |
||||
|
render(<div> |
||||
|
<div className='gis_exit' onClick={() => { |
||||
|
map.setCenter([115.922069, 28.554867]) |
||||
|
map.clearInfoWindow(); |
||||
|
}} /> |
||||
|
<div className='gis_item'> |
||||
|
<span className='gis_title'>点位名称</span> |
||||
|
<span className='gis_text'>{x.name}</span> |
||||
|
</div> |
||||
|
<div className='gis_item'> |
||||
|
<span className='gis_title'>实时水位</span> |
||||
|
<span className='gis_text'>{x.waterLevel}m</span> |
||||
|
</div> |
||||
|
<div className='gis_item'> |
||||
|
<span className='gis_title'>预警水位</span> |
||||
|
<span className='gis_text'>{x.alert}m</span> |
||||
|
</div> |
||||
|
<div className='gis_item'> |
||||
|
<span className='gis_title'>近1h雨量</span> |
||||
|
<span className='gis_text'>1.5mm</span> |
||||
|
</div> |
||||
|
<div className='gis_item'> |
||||
|
<span className='gis_title'>告警</span> |
||||
|
<span className='gis_text'>高风险</span> |
||||
|
</div> |
||||
|
|
||||
|
</div>, |
||||
|
document.getElementById(`alarmcontentid${x.name}`)); |
||||
|
} |
||||
|
}, 50) |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
const renderLeftTop = () => { |
||||
|
return <div className='water_gis_home_left'> |
||||
|
{[{ name: '高风险区域', key: 'high', data: 3 }, |
||||
|
{ name: '中风险区域', key: 'middle', data: 13 }, |
||||
|
{ name: '低风险区域', key: 'low', data: 13 }].map(s => { |
||||
|
return <div className='left_item'> |
||||
|
<div className='gis_item_left'> |
||||
|
<div className={`${s.key}_risk`} /> |
||||
|
</div> |
||||
|
<div className='gis_item_right'> |
||||
|
<div>{s.name}</div> |
||||
|
<div><span className={`${s.key}_text`}>{s.data}</span>/21</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
})} |
||||
|
|
||||
|
</div> |
||||
|
} |
||||
|
|
||||
|
const renderRightBottom = () => { |
||||
|
return tab == 'overview' ? |
||||
|
<div className='water_home_right'> |
||||
|
<div className='_right_row1'> |
||||
|
<div className='_monitor' /><span className='monitor_text'>监测点</span></div> |
||||
|
<div className='_right_row2'> |
||||
|
<span className='column1'>预警阈值参照表</span> |
||||
|
<div className='column2'> |
||||
|
<div className='flex-row flex-content-around'><span>三级告警</span><span>二级告警</span><span>一级告警</span></div> |
||||
|
<div className='flex-row flex-content-around'> |
||||
|
<div className='level3'></div> |
||||
|
<div className='level2'></div> |
||||
|
<div className='level1'></div> |
||||
|
</div> |
||||
|
{/* <div className='flex-row flex-content-around'> |
||||
|
<span>0m</span> |
||||
|
<span>5m</span> |
||||
|
<span>10m</span> |
||||
|
<span>15m</span> |
||||
|
<span>20m</span> |
||||
|
<span>25m</span> |
||||
|
<span>30m</span> |
||||
|
</div> */} |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> : |
||||
|
<div className='water_home_right_back' onClick={() => { |
||||
|
setTab('overview') |
||||
|
props.changeTab('overview') |
||||
|
}}> |
||||
|
<div className='_back_icon' /> 返回实时监测 |
||||
|
</div> |
||||
|
} |
||||
|
|
||||
|
const renderWaterwarningbg = () => { |
||||
|
return <div className='waterwarningbg'> |
||||
|
<div className='_alarm_column1'> |
||||
|
<div>城区沿江水涝<div className='_state'>未启动</div></div> |
||||
|
<div style={{ color: 'rgba(76, 161, 255, 1)', fontSize: 14 }}>[自然灾害事故]</div> |
||||
|
</div> |
||||
|
<div className='_alarm_column2'> |
||||
|
<div style={{ textAlign: 'right', color: 'rgba(76, 161, 255, 1)' }}>2023-02-12 16:42:34</div> |
||||
|
<div className='_text_info'> |
||||
|
6月11日上午11点左右,低洼堤坝出现江水倒灌灾,需要进行救援。6月11日上午11点左右,低洼堤坝出现江水倒灌灾,需要进行救援。 |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
} |
||||
|
|
||||
|
const tabs = tab == 'overview' ? [ |
||||
|
{ name: '实时监测', tab: 'overview' }, |
||||
|
{ name: '应急抢险', tab: 'emergency' } |
||||
|
] : [ |
||||
|
{ name: '应急物资', tab: 'yjwz', className: 'emergency_button' }, |
||||
|
{ name: '消防救援', tab: 'xfjy', className: 'emergency_button' }, |
||||
|
{ name: '人民武装部', tab: 'rmwzb', className: 'emergency_button' }, |
||||
|
{ name: '医疗救援', tab: 'yljy', className: 'emergency_button' }, |
||||
|
{ name: '应急避难场所', tab: 'yjbns', className: 'emergency_button' }, |
||||
|
] |
||||
|
|
||||
|
return ( |
||||
|
<> |
||||
|
{/* 延缓加载遮罩 */} |
||||
|
{delay && <div id='delaydiv' style={{ |
||||
|
width: '100%', height: '100%', left: 0, top: 0, zIndex: 1000, background: '#000000', position: 'absolute', |
||||
|
display: 'flex', alignItems: 'center', justifyContent: 'center' |
||||
|
}}> |
||||
|
</div>} |
||||
|
|
||||
|
{/* 地图容器 */} |
||||
|
<div className="gis" id={MAPDOMID} /> |
||||
|
|
||||
|
|
||||
|
{/* 底部按钮 */} |
||||
|
{!delay && tabs.map((s, index) => { |
||||
|
return <> |
||||
|
<div className={s.className ? `${s.className} ${s.className}${index + 1}` : 'water-gis-button' + (index + 1)} |
||||
|
onClick={() => { |
||||
|
setTab(s.tab) |
||||
|
s.className ? props.changeEmengencyTab(s.tab) : props.changeTab(s.tab) |
||||
|
}} |
||||
|
> |
||||
|
<div className={ |
||||
|
s.className ? `button_${s.tab} ${tab == s.tab ? 'button_' + s.tab + '_select' : ''}` : |
||||
|
`button_img ${tab == s.tab ? 'button_img_select' : ''}`} /> |
||||
|
<div>{s.name}</div> |
||||
|
{s.className && <div className='dotbg'>{emergencyList[s.tab]?.length}</div>} |
||||
|
</div> |
||||
|
{/* { |
||||
|
tab !== 'overview' && <> <div className='icon_left'></div> |
||||
|
<div className='icon_right'></div></> |
||||
|
} */} |
||||
|
</> |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
{/* 左上角图例 */} |
||||
|
{tab == 'overview' && renderLeftTop()} |
||||
|
{tab == 'emergency' && renderWaterwarningbg()} |
||||
|
{renderRightBottom()} |
||||
|
{/* 四周遮罩 */} |
||||
|
<div className='gis-left'></div> |
||||
|
<div className='gis-right'></div> |
||||
|
<div className='gis-top'></div> |
||||
|
<div className='gis-bottom'></div> |
||||
|
</> |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
export default connect()(Map); |
@ -0,0 +1,23 @@ |
|||||
|
function getName(name) { |
||||
|
let newStr |
||||
|
if (name.length === 2) { |
||||
|
newStr = name.substr(0, 1) + '*' |
||||
|
} else if (name.length > 2) { |
||||
|
let char = '' |
||||
|
for (let i = 0, len = name.length - 2; i < len; i++) { |
||||
|
char += '*' |
||||
|
} |
||||
|
newStr = name.substr(0, 1) + char + name.substr(-1, 1) |
||||
|
} else { |
||||
|
newStr = name |
||||
|
} |
||||
|
return newStr |
||||
|
} |
||||
|
|
||||
|
function getPhone(tel) { |
||||
|
if (!tel) return tel; |
||||
|
const phone = tel.replace(tel.substring(3, 7), '****') |
||||
|
return phone |
||||
|
} |
||||
|
|
||||
|
export { getName, getPhone } |
Loading…
Reference in new issue