| import * as React from 'react' | 
| import * as PIXI from 'pixi.js'; | 
| import { FormattedMessage, useIntl, useModel } from '@umijs/max'; | 
| import { Layout, Button, Flex, Row, Col, FloatButton, Select, Spin, AutoComplete } from 'antd'; | 
| const { Header, Content } = Layout; | 
| import { | 
|     AppstoreAddOutlined, | 
|     FileAddOutlined, | 
|     CompressOutlined, | 
|     SettingOutlined, | 
|     CloseOutlined | 
| } from '@ant-design/icons'; | 
| import './index.css' | 
| import { createStyles } from 'antd-style'; | 
| import Edit from './components/device'; | 
| import Settings from './components/settings' | 
| import * as Utils from './utils' | 
| import Player from './player'; | 
| import MapSearch from './header/search'; | 
| import MapDrawer from './drawer'; | 
|   | 
| const useStyles = createStyles(({ token }) => { | 
|     let dark = token.colorBgBase === '#000'; | 
|     return { | 
|         dark: dark, | 
|         layout: { | 
|             overflow: 'hidden', | 
|         }, | 
|         header: { | 
|             height: 64, | 
|             paddingInline: 48, | 
|             lineHeight: '64px', | 
|             padding: 0, | 
|         }, | 
|         flex: { | 
|             width: '100%', | 
|             height: '100%', | 
|             padding: '0 30px', | 
|         }, | 
|         content: { | 
|             backgroundColor: '#F8FAFB', | 
|             height: 'calc(100vh - 120px)' | 
|         }, | 
|         select: { | 
|             color: 'red', | 
|             fontWeight: 'bold', | 
|         }, | 
|         headerCol: { | 
|             paddingLeft: '50px' | 
|         } | 
|     }; | 
| }); | 
|   | 
| export const MapModel = Object.freeze({ | 
|     OBSERVER_MODEL: "1", | 
|     MOVABLE_MODEL: "2", | 
|     SETTINGS_MODEL: "3", | 
| }) | 
|   | 
| let player; | 
|   | 
| const Map = () => { | 
|     const intl = useIntl(); | 
|     const { initialState, setInitialState } = useModel('@@initialState'); | 
|     const { styles } = useStyles(); | 
|     const mapRef = React.useRef(); | 
|     const contentRef = React.useRef(); | 
|   | 
|     const [curSprite, setCurSPrite] = React.useState(null); | 
|     const [model, setModel] = React.useState(() => MapModel.OBSERVER_MODEL); | 
|     const [deviceVisible, setDeviceVisible] = React.useState(false); | 
|     const [settingsVisible, setSettingsVisible] = React.useState(false); | 
|     const [windowSize, setWindowSize] = React.useState({ | 
|         width: window.innerWidth, | 
|         height: window.innerHeight, | 
|     }); | 
|     const [app, setApp] = React.useState(null); | 
|     const [mapContainer, setMapContainer] = React.useState(null); | 
|     const [didClickSprite, setDidClickSprite] = React.useState(false); | 
|     const [spriteBySettings, setSpriteBySettings] = React.useState(null); | 
|     const prevSpriteBySettingsRef = React.useRef(); | 
|   | 
|     // init func | 
|     React.useEffect(() => { | 
|         player = new Player(mapRef.current, styles.dark, didClickSprite); | 
|         setApp(player.app); | 
|         setMapContainer(player.mapContainer); | 
|         Utils.syncApp(player.app); | 
|         Utils.syncMapContainer(player.mapContainer); | 
|   | 
|         const handleResize = () => { | 
|             setWindowSize({ | 
|                 width: window.innerWidth, | 
|                 height: window.innerHeight, | 
|             }); | 
|         }; | 
|         window.addEventListener('resize', handleResize); | 
|     }, []); | 
|   | 
|     // resize | 
|     React.useEffect(() => { | 
|         if (!app) { | 
|             return; | 
|         } | 
|         const width = contentRef.current.offsetWidth; | 
|         const height = contentRef.current.offsetHeight; | 
|         app.renderer.resize(width, height); | 
|         if (model !== MapModel.OBSERVER_MODEL) { | 
|             player.hideGridlines(); | 
|             player.showGridlines(); | 
|         } | 
|     }, [app, mapContainer, windowSize]) | 
|   | 
|     // model | 
|     React.useEffect(() => { | 
|         if (!mapContainer) { | 
|             return; | 
|         } | 
|         switch (model) { | 
|             case MapModel.OBSERVER_MODEL: | 
|   | 
|                 player.hideGridlines(); | 
|                 player.hideStarryBackground(); | 
|   | 
|                 player.activateMapEvent(null); | 
|   | 
|                 Utils.removeSelectedEffect(); | 
|                 setDeviceVisible(false); | 
|                 setSettingsVisible(false); | 
|   | 
|                 mapContainer.children.forEach(child => { | 
|                     child.off('pointerup'); | 
|                     child.off('pointermove'); | 
|                     child.off('pointerdown'); | 
|                     child.off('click'); | 
|                 }) | 
|                 break | 
|             case MapModel.MOVABLE_MODEL: | 
|   | 
|                 player.showGridlines(); | 
|                 player.hideStarryBackground(); | 
|   | 
|                 player.activateMapEvent(Utils.MapEvent.SELECTION_BOX); | 
|   | 
|                 Utils.removeSelectedEffect(); | 
|                 setSpriteBySettings(null); | 
|                 setSettingsVisible(false); | 
|   | 
|                 mapContainer.children.forEach(child => { | 
|                     Utils.beMovable(child, setDidClickSprite); | 
|                 }) | 
|                 break | 
|             case MapModel.SETTINGS_MODEL: | 
|   | 
|                 player.showGridlines(); | 
|                 player.showStarryBackground(); | 
|   | 
|                 player.activateMapEvent(null); | 
|   | 
|                 setDeviceVisible(false); | 
|   | 
|                 mapContainer.children.forEach(child => { | 
|                     Utils.beSettings(child, setSpriteBySettings, setDidClickSprite); | 
|                 }) | 
|                 break | 
|             default: | 
|                 break | 
|         } | 
|     }, [model]); | 
|   | 
|     // Add New Device | 
|     const onDrop = (sprite, type, x, y) => { | 
|         const { mapX, mapY } = Utils.getRealPosition(x, y, mapContainer); | 
|         sprite.x = mapX; | 
|         sprite.y = mapY; | 
|   | 
|         Utils.initSprite(sprite, type); | 
|         mapContainer.addChild(sprite); | 
|         Utils.beMovable(sprite, setDidClickSprite); | 
|     }; | 
|   | 
|     // didClickSprite, stop triggers both sprite click and play's selection boxs | 
|     React.useEffect(() => { | 
|         player.updateDidClickSprite(didClickSprite); | 
|     }, [didClickSprite]) | 
|   | 
|     // watch spriteBySettings | 
|     React.useEffect(() => { | 
|         if (!mapContainer) { | 
|             return; | 
|         } | 
|         prevSpriteBySettingsRef.current = spriteBySettings; | 
|         if (spriteBySettings && prevSpriteBySettings !== spriteBySettings) { | 
|             Utils.removeSelectedEffect(); | 
|         } | 
|         if (spriteBySettings) { | 
|             Utils.showSelectedEffect(spriteBySettings) | 
|             setSettingsVisible(true); | 
|         } else { | 
|             Utils.removeSelectedEffect(); | 
|         } | 
|     }, [spriteBySettings]) | 
|     const prevSpriteBySettings = prevSpriteBySettingsRef.current; | 
|   | 
|     const settingsFinish = (values, fn) => { | 
|         fn(); | 
|         // setSettingsVisible(false); | 
|         // setSpriteBySettings(null); | 
|     } | 
|   | 
|     React.useEffect(() => { | 
|         console.log(curSprite); | 
|     }, [curSprite]); | 
|   | 
|     return ( | 
|         <> | 
|             <Layout className={styles.layout}> | 
|                 <Header className={styles.header}> | 
|                     <Row style={{ height: '100%' }}> | 
|                         <Col className={styles.headerCol} span={12} style={{}}> | 
|                             <MapSearch | 
|                                 curSprite={curSprite} | 
|                                 setCurSPrite={setCurSPrite} | 
|                             /> | 
|                         </Col> | 
|                         {/* 3C40C6 */} | 
|                         <Col span={12} style={{ backgroundColor: '#4a69bd' }}> | 
|                             <Flex className={styles.flex} gap={'large'} justify={'flex-end'} align={'center'}> | 
|                                 <span> | 
|                                     {curSprite?.data?.uuid} | 
|                                 </span> | 
|                                 <Select | 
|                                     className='map-header-select' | 
|                                     size={'large'} | 
|                                     defaultValue={MapModel.OBSERVER_MODEL} | 
|                                     style={{ | 
|                                         width: 180, | 
|                                     }} | 
|                                     onChange={setModel} | 
|                                     options={[ | 
|                                         { | 
|                                             value: MapModel.OBSERVER_MODEL, | 
|                                             label: intl.formatMessage({ id: 'map.model.observer', defaultMessage: '观察者模式' }), | 
|                                         }, | 
|                                         { | 
|                                             value: MapModel.MOVABLE_MODEL, | 
|                                             label: intl.formatMessage({ id: 'map.model.editor', defaultMessage: '编辑者模式' }), | 
|                                         }, | 
|                                     ]} | 
|                                 /> | 
|                             </Flex> | 
|                         </Col> | 
|                     </Row> | 
|                 </Header> | 
|                 <Content ref={contentRef} className={styles.content}> | 
|                     <div ref={mapRef} style={{ position: "relative" }} > | 
|                         <FloatButton.Group | 
|                             shape="square" | 
|                             style={{ | 
|                                 left: 35, | 
|                                 bottom: 35 | 
|                             }} | 
|                         > | 
|                             <FloatButton | 
|                                 icon={<CompressOutlined />} | 
|                                 onClick={() => { | 
|                                     Utils.adaptScreen(); | 
|                                 }} | 
|                             /> | 
|                             <FloatButton.BackTop visibilityHeight={0} /> | 
|                         </FloatButton.Group> | 
|   | 
|                         <FloatButton.Group | 
|                             hidden={model === MapModel.OBSERVER_MODEL} | 
|                             style={{ | 
|                                 left: 35, | 
|                                 bottom: window.innerHeight / 2 | 
|                             }} | 
|                             icon={<AppstoreAddOutlined />} | 
|                         > | 
|                             <FloatButton | 
|                                 hidden={model === MapModel.OBSERVER_MODEL} | 
|                                 type={deviceVisible ? 'primary' : 'default'} | 
|                                 tooltip={<div><FormattedMessage id='map.device.add' defaultMessage='添加设备' /></div>} | 
|                                 icon={<FileAddOutlined />} | 
|                                 onClick={() => { | 
|                                     if (deviceVisible) { | 
|                                         setDeviceVisible(false); | 
|                                     } else { | 
|                                         setDeviceVisible(true); | 
|                                         setModel(MapModel.MOVABLE_MODEL); | 
|                                     } | 
|                                 }} | 
|                             /> | 
|                             <FloatButton | 
|                                 hidden={model === MapModel.OBSERVER_MODEL} | 
|                                 type={model === MapModel.SETTINGS_MODEL ? 'primary' : 'default'} | 
|                                 tooltip={<div><FormattedMessage id='map.device.oper' defaultMessage='参数设置' /></div>} | 
|                                 icon={<SettingOutlined />} | 
|                                 onClick={() => { | 
|                                     setModel(model === MapModel.SETTINGS_MODEL ? MapModel.MOVABLE_MODEL : MapModel.SETTINGS_MODEL) | 
|                                 }} | 
|                             /> | 
|                         </FloatButton.Group> | 
|                     </div> | 
|                 </Content> | 
|             </Layout > | 
|   | 
|             <Edit | 
|                 open={deviceVisible} | 
|                 onCancel={() => { | 
|                     setDeviceVisible(false); | 
|                 }} | 
|                 refCurr={mapRef.current} | 
|                 onDrop={onDrop} | 
|             /> | 
|   | 
|             <Settings | 
|                 open={settingsVisible} | 
|                 curSprite={spriteBySettings} | 
|                 onCancel={() => { | 
|                     setSettingsVisible(false); | 
|                     setSpriteBySettings(null); | 
|                 }} | 
|                 setSpriteBySettings={setSpriteBySettings} | 
|                 setDidClickSprite={setDidClickSprite} | 
|                 refCurr={mapRef.current} | 
|                 onSubmit={settingsFinish} | 
|             /> | 
|         </> | 
|     ) | 
| } | 
|   | 
| export default Map; |