Skip to main content

第一节:初始化地图,渲染页面组件

云平台和本地开发的区别

如果您是尝试QE功能,建议您直接在云平台开始根据教程来编码,要注意的是需要在您自己的空间里面创建新项目并保存,否则页面刷新后您的代码将会丢失。

您也可以参考快速入门中的方法,在本地进行编码,这时候本教程中的入口代码对应的是您webpack的入口文件,为了方便演示,我们所有的代码都在这个函数中编写,实际应用中,您应该进行UI组件和业务逻辑代码的拆分。

如果您使用了本地开发环境,请先安装antd,本示例使用antd作为UI框架。

初始化QE引擎状态

QE二维部分依赖Leaflet,因此我们需要先import 在QE中创建地图之前调用init方法初始化各类状态:init("your-token"),我们把这句话加到系统的入口代码:

import L from "leaflet"
import { init} from "quickearth";

//以下token为QE的测试token,可能随时失效
init("f17d186a2e692c9f6f2e79e48b270012");

后续还需要不断的往quickearth的import中添加各种其他的方法和类,不再一一说明,需自行添加。

创建地图

接下来,我们在系统的入口代码里面,直接加入地图创建的代码:

const map = new LMap("map", { crs: L.CRS.EPSG3857, fadeAnimation: false, zoomControl: false }).setView([35, 110], 4);
const defaultTileName = predefinedImageTiles.geoQNormal;
let tileLayer = createTileLayer(defaultTileName);
map.addLayer(tileLayer);

这里,我们使用的是LMap,而不是Leaflet的L.Map,LMap是继承自Leaflet原生地图,所以拥有所有原生地图的功能,并且额外增加了如地图工具等额外的服务,具体您可以参考API中的LMap。

createTileLayer方法是QE提供的快速创建在线切片图层的方法,QE内置了一些测试的在线地图地址,但是请务必注意,在正式使用过程中仅使用具有审图号的地图。

此时,我们已经拥有一个干净的地图了: 创建地图.jpg

加载默认资源

QE内置了一个资源管理器resourceService,用于管理各类全局共享的资源,如果有一些图片或者样式等,后续会大量使用到,我们可以在数据图层加载之前提前进行加载。

推荐的方式是使用一个资源配置文件,如我们云平台中默认的资源文件是 http://qecloud.91weather.com/public/demos/styles/demo.config.json,该文件的具体格式,您可以参考核心概念中的资源管理器章节。

从资源配置文件加载资源的方式如下:

resourceService.loadResourceFromConfigPath("demos/styles/demo.config.json")

loadResourceFromConfigPath是一个异步方法,一般情况下如果资源文件不是特别多,我们就等待资源文件加载完后开始渲染React组件,如果资源较多,建议您在需要使用的时候实时加载并通过addResource方法添加到资源管理器(如果不需要保存修改状态,则可以每次使用时候请求),这里我们等待资源加载完成之后再执行其他动作,因此我们构建一个async load函数来简化异步加载,上面的代码修改如下:

const load = async () => {
    await resourceService.loadResourceFromConfigPath("demos/styles/demo.config.json")
}
load();

这样,我们就可以在资源加载完成后开始我们的业务代码,这时候就可以不用考虑使用样式之前还要先加载样式的问题了。

创建系统根组件

本演示系统仅使用一个跟组件渲染整个页面,实际应用应根据业务场景合理拆分!

在使用React之前,我们需要在文件头import React相关的内容:

import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";

在这里,我们使用React函数式组件:

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

    return (
        <div>
            
        </div>

    )
}

然后在我们load函数中加入渲染代码:

const load = async () => {
    await resourceService.loadResourceFromConfigPath("demos/styles/demo.config.json");
    ReactDOM.render(<AviationApp
    />, document.getElementById("plugins"));
}

在这里,我们把组件挂载到了id为plugins的dom中,这是在index.html中进行定义的,您也可以自行修改。

至此,我们渲染了一个空组件,这个正是我们即将存放图层菜单和地图工具的地方。

加入占位的图层菜单和地图工具组

在跟组件中,我们目前返回的渲染内容是一个空div标签,而我们实际需要的是一个图层菜单和地图工具组。

图层菜单我们使用了一个自行封装的MenuList组件,可以支持通过配置数据源来生成动态菜单,如果您是在云平台使用,您可以直接引入,否则您需要自行封装或者等待我们将这个组件开源。

工具组我们使用antd的radio组件。

改造后的根组件如下:

...
import { MenuList } from "menu-list"
//@ts-ignore
import { Radio } from "antd";
...
const AviationApp: React.FC = () => {

    return (
        <div>
            <div style={{ position: "fixed", right: "0px", top: "0px", width: "200px", zIndex: 999999 }}>
                <MenuList
                    dataSource={[{id:"test",name:"测试"}]}
                    selectedItemIds={["test"]}
                    mode="inline"
                    theme="dark"
                />
            </div>
            <Radio.Group
                style={{ position: "fixed", zIndex: "999999", left: "0px", bottom: "30px", width: "110px",backgroundColor: "rgb(3,21,39)"  }}
            >
                <Radio value={"test_radio"} style={{ color: "rgb(170,170,170)" }}>工具1</Radio>
            </Radio.Group>
        </div>

    )
}
出于加载性能考虑,我们没有在云平台加入antd的definition文件,因此需要使用@ts-ignore指令来取消ts的报错提示,如果您是在本地开发,无需加入。

可以看到,我们讲MenuList固定在了屏幕的右上角,由于demo的布局简单,我们直接使用了fixed布局。

MenuList的dataSource是一个IMenuItem的数组,IMenuItem类型如下:

export interface IMenuItem {
  	//表示该菜单的子菜单列表
    childs?: IMenuItem[];
  	//菜单的显示名称
    name: string;
  	//菜单的唯一Id
    id: string;
  	//菜单所属的分组名称,支持同一个菜单内的分组
    group?: string;
    //菜单的图标
    icon?: React.ReactNode;
  	//用户自定义数据,在菜单被选中或者取消选中(仅multiple模式下)的时候可以获取自定义数据
    userData?: any;
}

这里我们直接传入了一个测试的菜单,并且设置菜单为暗色模式,设定我们的测试菜单为默认选中,菜单与我们设计的各类图层的结合,我们将在第二节讲解。

在地图工具部分,我们传入了一个测试的按钮,具体我们将在第三节讲解。

到目前为止,我们的页面已经具备了图层菜单和地图工具的样子了,我们可以继续下一节了!

本节的完整代码及效果