Skip to main content

在React中使用(内含实战)

React是一个优秀的前端开发框架,即使您只是开发一些简单的个人页面,也非常推荐您使用React进行开发,在QuickEarth项目中启用TypeScript与普通项目无异,如果您还没有使用经验,您可以先学习React相关知识:

https://zh-hans.reactjs.org/docs/getting-started.html

本教程最终效果

使用环境

本章节假定使用的是TypeScript进行开发,JS可按照逻辑进行类比。

在React项目中初始化地图

QE地图的初始化有多种方式,可以直接将Dom放在index中,然后在合适的地方初始化,也可以使用组件的方式进行初始化,下面分别进行介绍。

不借助React组件进行初始化

由于QE地图只需要一个基础容器组件即可初始化,我们将承载地图的容器放到index.html中。这种方式适合比较简单的单页地图,不需要进行复杂路由,React组件负责渲染地图之外的其他地方,而地图使用原始的方式进行初始化,好处是方便快速,清晰简单,缺点是不适合复杂应用。

QuickEarth云平台中大多数项目使用这种方式进行初始化。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="theme-color" content="#000000">
  <meta charset="utf-8" />
  <meta HTTP-EQUIV="Pragma" CONTENT="no-cache">
  <meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
  <meta HTTP-EQUIV="Expires" CONTENT="0">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <title>QuickEarth-Preview</title>
</head>
<body>
  <noscript>
    You need to enable JavaScript to run this app.
  </noscript>
  <!--for 2d -->
  <link rel="stylesheet" type="text/css" href="public/lib/node_modules/leaflet/dist/leaflet.css" />
  <link rel="stylesheet" type="text/css" href="public/lib/node_modules/antd/dist/antd.min.css" />
  <link rel="stylesheet" href="public/config/styles/fonts/fonts.css" />
  <!--your custom libs-->
  <!--systemjs-->
  <!--项目内容开始-->
  <div id="map" style="position:absolute;left:0px;right:0px;bottom:0px;top:0px;"></div>
  <div id="plugins"></div>
</body>
</html>
import L from "leaflet"
import { init, LMap,createTileLayer, predefinedImageTiles,consts } from "quickearth";

init("f17d186a2e692c9f6f2e79e48b270012");
const map = new LMap("map", { crs: L.CRS.EPSG3857, fadeAnimation: false, zoomControl: false }).setView([35, 110], 3);
const tileLayer = createTileLayer(predefinedImageTiles.windy, { pane: consts.customPanes.topmap.name });
map.addLayer(tileLayer);

在初始化完地图之后可以继续初始化React组件,也可以选择在React组件

const App: React.FC = () => {
    return (
        <div style={{
            position: "fixed",
            top: "0px",
            width: "100px",
            height: "20px",
            right: "0px",
            backgroundColor:"rebeccapurple",
            zIndex: "999999"
        }}>
        </div>
    );
};
ReactDOM.render(<App />, document.getElementById("root"));
效果如下
使用React Class Component创建地图

当开发较为复杂的应用时,地图可能需要随着组件的生命周期进行创建和删除,这时候就需要对地图的生命周期进行管理。

我们对上面一个示例进行改造,在同一个应用中显示组件式方式创建的地图。

我们在此同时考虑下一小节使用函数式组件也需要创建地图,所以我们把页面分为上中下三个部分,index.html改造如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="theme-color" content="#000000">
    <meta charset="utf-8" />
    <meta HTTP-EQUIV="Pragma" CONTENT="no-cache">
    <meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
    <meta HTTP-EQUIV="Expires" CONTENT="0">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>QuickEarth-Preview</title>
</head>
<body>
    <noscript>
        You need to enable JavaScript to run this app.
    </noscript>
    <!--for 2d -->
    <link rel="stylesheet" type="text/css" href="public/lib/node_modules/leaflet/dist/leaflet.css" />
    <link rel="stylesheet" type="text/css" href="public/lib/node_modules/antd/dist/antd.min.css" />
    <link rel="stylesheet" href="public/config/styles/fonts/fonts.css" />
    <!--your custom libs-->
    <!--项目内容开始-->
    <div id="root_fc" style="position:absolute;left:0px;right:0px;height:33%;top:33%;"></div>
    <div id="root_class" style="position:absolute;left:0px;right:0px;height:34%;top:66%;"></div>
    <div id="map" style="position:absolute;left:0px;right:0px;top:0px;height:33%;"></div>    
    <div id="plugins"></div>
</body>
</html>

同时加入一个React地图组件:

class ClassicApp extends React.Component {

    private map: LMap;

    public render() {
        return (
        <div id="map3" style={{"position":"absolute","left":"0px","right":"0px","top":"0px","bottom":"0px"}}></div>
        );
    }

    public componentDidMount() {
        const map = this.map = new LMap("map3", { crs: L.CRS.EPSG3857, fadeAnimation: false, zoomControl: false }).setView([35, 110], 3);
        const tileLayer = createTileLayer(predefinedImageTiles.tdtTerrain, { pane: consts.customPanes.topmap.name });
        map.addLayer(tileLayer);
    }

    public componentWillUnmount() {
        this.map.remove();
    }

}

然后将上一节中的直接创建地图改造为一个创建函数:

function createRawMap() {
    const map = new LMap("map", { crs: L.CRS.EPSG3857, fadeAnimation: false, zoomControl: false }).setView([35, 110], 3);
    const tileLayer = createTileLayer(predefinedImageTiles.tdtNormal, { pane: consts.customPanes.topmap.name });
    map.addLayer(tileLayer);
}

最后,启动组件渲染:

//这个方法只需要全局调用一次,放到外部
init("f17d186a2e692c9f6f2e79e48b270012");
resourceService.loadResourceFromConfigPath("demos/styles/demo.config.json").then(res => {
    createRawMap();
    ReactDOM.render(<ClassicApp />, document.getElementById("root_class"));
});
在函数式组件中创建地图

函数式组件的生命周期由useEffect函数控制,因此只要在该函数中实现地图的创建和卸载即可,组件代码如下,这个示例我们使用三维地图:

const App: React.FC = () => {

    useEffect(() => {
        Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5NjE0YzZiNS0wNjJiLTQ5NjEtYmMyZC01YWYzZjk1NmYzMzYiLCJpZCI6OTgxOCwic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTU1NDk5MTkxNn0.RMgKv7MDKkXaV0df21IBBqikp2abPoUYeAPB42fHJes";
        const viewer = new CView("map2", {
            defaultTiles: [predefinedImageTiles.tdtSatellite, predefinedImageTiles.tdtSatelliteAnnotation],
            showGroundAtmosphere: false,
            scene3DOnly: true
        });
        return () => { viewer.container.remove(); viewer.destroy(); }
    }, []);

    return (
        <div id="map2" style={{ "position": "absolute", "left": "0px", "right": "0px", "top": "0px", "bottom": "0px" }}></div>
    );
};

接着在启动函数中进行组件渲染:

//这个方法只需要全局调用一次,放到外部
init("f17d186a2e692c9f6f2e79e48b270012");
resourceService.loadResourceFromConfigPath("demos/styles/demo.config.json").then(res => {
    createRawMap();
    ReactDOM.render(<App />, document.getElementById("root_fc"));
    ReactDOM.render(<ClassicApp />, document.getElementById("root_class"));
});

看起来是QE

到此为止,看起来我们是在做React中使用Leaflet的教程,让我们添加一些气象数据吧!

let provider: IFeaturesProvider;
async function createStationLayer(ctor) {
    if (!provider) {
        provider = new CimissStationFeatureProvider(await getJSON("public/demos/data/autostation011.json"));
    }
    const layer = new ctor()
        .setDataSource(provider)
        .setDrawOptions({
            point: {
                size: 3,
                color: "color-temp#res?field=TEM",
            }
        });
    return layer;
}
ctor是一个构造器,在二维我们使用的时LGeoJSONLayer,三维是CGeoJSONLayer。

完整代码