|
@@ -1,12 +1,19 @@
|
|
|
-import React from 'react'
|
|
|
+import React, { createRef, RefObject } from 'react'
|
|
|
import { Color } from "csstype"
|
|
|
import * as Cesium from 'cesium'
|
|
|
import createMVTWithStyle from './mvt'
|
|
|
import style from './style.module.css'
|
|
|
+import { AuxMenus, Menus } from '../auxMenu'
|
|
|
+import { Hot, Hots } from '../../store/hots'
|
|
|
+import { AddHot } from '../../page/hot/add'
|
|
|
+import { ShowHot } from '../../page/hot/show'
|
|
|
+import { toReal, toScreen, Pos2D } from './help'
|
|
|
+
|
|
|
|
|
|
declare global {
|
|
|
interface Window { CESIUM_BASE_URL: any; ol: any }
|
|
|
}
|
|
|
+// Cesium.defineProperties
|
|
|
|
|
|
window.CESIUM_BASE_URL = './'
|
|
|
|
|
@@ -19,6 +26,7 @@ export interface LayerStyle {
|
|
|
}
|
|
|
|
|
|
interface Props extends LayerStyle {
|
|
|
+ hots: Hots
|
|
|
url: string,
|
|
|
lng: number,
|
|
|
lat: number,
|
|
@@ -27,7 +35,12 @@ interface Props extends LayerStyle {
|
|
|
}
|
|
|
|
|
|
interface State {
|
|
|
- viewer: any
|
|
|
+ viewer: any,
|
|
|
+ height: number,
|
|
|
+ mouseEvent: React.MouseEvent | null,
|
|
|
+ menus: Menus<string>,
|
|
|
+ hotPos: Hot['pos'] | null,
|
|
|
+ hotScreens: Pos2D[]
|
|
|
}
|
|
|
|
|
|
function createStyle (style: LayerStyle) {
|
|
@@ -46,14 +59,24 @@ function createStyle (style: LayerStyle) {
|
|
|
|
|
|
class VectorView extends React.Component<Props, State> {
|
|
|
clipLayer: any
|
|
|
+ domRef: RefObject<HTMLDivElement>
|
|
|
+ downHandler: () => void
|
|
|
|
|
|
constructor(props: Props) {
|
|
|
super(props)
|
|
|
- this.state = { viewer: null }
|
|
|
+ this.state = {
|
|
|
+ hotScreens: [],
|
|
|
+ hotPos: null,
|
|
|
+ viewer: null,
|
|
|
+ height: 600,
|
|
|
+ mouseEvent: null,
|
|
|
+ menus: [{label: '添加热点', value: 'add-hot'}]
|
|
|
+ }
|
|
|
+ this.domRef = createRef()
|
|
|
}
|
|
|
|
|
|
- componentDidUpdate () {
|
|
|
- if (!this.state.viewer) return;
|
|
|
+ componentDidUpdate (prevProps: Props) {
|
|
|
+ if (!this.state.viewer || prevProps.url === this.props.url) return;
|
|
|
if (this.clipLayer) {
|
|
|
this.state.viewer.imageryLayers.remove(this.clipLayer, true)
|
|
|
}
|
|
@@ -65,8 +88,8 @@ class VectorView extends React.Component<Props, State> {
|
|
|
}) as any;
|
|
|
|
|
|
this.clipLayer = this.state.viewer.imageryLayers.addImageryProvider(layer);
|
|
|
+ this.updateScreens()
|
|
|
}
|
|
|
-
|
|
|
componentDidMount () {
|
|
|
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0OGQ5Y2FiZS1iNzlmLTQyNGYtYjRkMy05ODYwY2QxZjYwYTciLCJpZCI6MjE0MTQsInNjb3BlcyI6WyJhc3IiLCJnYyJdLCJpYXQiOjE1Nzk1MzIwNjZ9.gcE0m9nus9WyfTvUw75j7-Mb9cuIFJnr7XHOVyTdTEg'
|
|
|
let viewer = new Cesium.Viewer('cesiumContainer', {
|
|
@@ -83,7 +106,30 @@ class VectorView extends React.Component<Props, State> {
|
|
|
destination: Cesium.Cartesian3.fromDegrees(this.props.lng, this.props.lat, this.props.height)
|
|
|
});
|
|
|
viewer.scene.globe.baseColor = new Cesium.Color(1.0, 1.0, 1.0, 1.0);
|
|
|
- this.setState({ viewer })
|
|
|
+ this.setState({
|
|
|
+ viewer,
|
|
|
+ height: this.domRef.current?.parentElement?.offsetHeight as number - 48
|
|
|
+ })
|
|
|
+ const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
|
|
|
+ const moveHandler = this.updateScreens.bind(this)
|
|
|
+
|
|
|
+
|
|
|
+ // 鼠标左键点击事件
|
|
|
+ handler.setInputAction((event) => {
|
|
|
+ // 鼠标移动事件
|
|
|
+ handler.setInputAction(moveHandler, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
|
|
+ handler.setInputAction(() => {
|
|
|
+ handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
|
|
+ handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP);
|
|
|
+ }, Cesium.ScreenSpaceEventType.LEFT_UP);
|
|
|
+ }, Cesium.ScreenSpaceEventType.LEFT_DOWN);
|
|
|
+ handler.setInputAction(moveHandler, Cesium.ScreenSpaceEventType.WHEEL)
|
|
|
+ moveHandler()
|
|
|
+ }
|
|
|
+
|
|
|
+ updateScreens() {
|
|
|
+ const screens = this.props.hots.map(item => toScreen(this.state.viewer, item.pos))
|
|
|
+ this.setState({ hotScreens: screens })
|
|
|
}
|
|
|
|
|
|
componentWillUnmount() {
|
|
@@ -94,7 +140,38 @@ class VectorView extends React.Component<Props, State> {
|
|
|
}
|
|
|
|
|
|
render() {
|
|
|
- return <div id="cesiumContainer" className={style.layer}></div>
|
|
|
+ const hotEles = this.props.hots.map((hot, i) => {
|
|
|
+ if (this.state.hotScreens[i]) {
|
|
|
+ return <ShowHot {...hot} key={hot.id} left={this.state.hotScreens[i].x} top={this.state.hotScreens[i].y} />
|
|
|
+ } else {
|
|
|
+ return null
|
|
|
+ }
|
|
|
+ })
|
|
|
+ if (this.state.hotScreens.length !== this.props.hots.length) {
|
|
|
+ this.updateScreens()
|
|
|
+ }
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div
|
|
|
+ className={style.layerParent}
|
|
|
+ onAuxClick={ev => {
|
|
|
+ ev.persist()
|
|
|
+ this.setState({ mouseEvent: ev })
|
|
|
+ }}
|
|
|
+ style={{height: this.state.height + 'px'}}
|
|
|
+ ref={this.domRef}
|
|
|
+ >
|
|
|
+ <div id="cesiumContainer" className={style.layer}></div>
|
|
|
+ <AuxMenus
|
|
|
+ onExit={() => this.setState({ mouseEvent: null })}
|
|
|
+ menus={this.state.menus}
|
|
|
+ event={this.state.mouseEvent}
|
|
|
+ onSelect={(_, pos) => this.setState({ hotPos: toReal(this.state.viewer, pos) })}
|
|
|
+ />
|
|
|
+ {this.state.hotPos && <AddHot pos={this.state.hotPos} onClose={() => this.setState({hotPos: null})} />}
|
|
|
+ {hotEles}
|
|
|
+ </div>
|
|
|
+ )
|
|
|
}
|
|
|
}
|
|
|
|