React+antd design pro框架使用原生百度地图api

1,578 阅读3分钟

技术

  • React -----> 用于构建用户界面的 JavaScript 库。
  • 百度地图 JavaScript API ------->在web端使用的百度地图api(支持3D)
  • antd design pro----->开箱即用的React中台前端/设计解决方案。

1. 获取百度地图api

进入百度地图开放平台获取百度地图api,按照步骤完成账号注册和获取密钥

2. 在项目中引入百度地图api

找到src/pages/document.ejs,

<script type="text/javascript" src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=你的密钥"></script>

这是在前端上层html模板中使用

3. 配置webpack

在config.js文件的export中加入

externals: {  BMapGL: 'window.BMapGL' }

引入外部变量,这样react组件就能用import的方式导入百度地图的命名空间,从而使用api里面的所有方法。

import BMapGL  from 'BMapGL';

4. 简单封装一个地图组件

import React, { PureComponent, Fragment } from 'react';
import BMapGL  from 'BMapGL'; // eslint-disable-line
import PropTypes from "prop-types";


export default class BaiduMap extends PureComponent {

  static propTypes = {
    mapProps: PropTypes.object,
    style: PropTypes.object,
    getMapInstance: PropTypes.func,
  };

  static defaultProps = {
    mapProps: {
      lng:116.280190,
      lat:40.049191,
      zoom:17,
      minZoom:5,
      maxZoom:20,
      enableScrollWheelZoom:true,
      enableDragging:true,
      heading:0,
      tilt:0,
      style:null,
      controls:[],
      markers:[],
      infoWindows:[]
    },
    style:{
      width:'100%',
      height:'100%'
    },
    getMapInstance:null
  };

  constructor(props) {
    super(props);
    this.state = {

    }
  }

  componentDidMount(){
    const { mapProps:{
        lng,
        lat,
        zoom,
        minZoom,
        maxZoom,
        enableScrollWheelZoom,
        enableDragging,
        heading,
        tilt,
        style,
        controls,
        markers,
        infoWindows
      },
      getMapInstance
    }=this.props;
    const map = new BMapGL.Map("container");    // 创建Map实例
    map.centerAndZoom(new BMapGL.Point(lng, lat), zoom);  // 初始化地图,设置中心点坐标和地图级别
    map.setMinZoom(minZoom);
    map.setMaxZoom(maxZoom);
    if(enableScrollWheelZoom){
      map.enableScrollWheelZoom();     // 开启鼠标滚轮缩放
    }
    if(!enableDragging){
      map.disableDragging();     // 禁用地图拖拽
    }
    map.setHeading(heading);
    map.setTilt(tilt);
    if(style!==null){
      if(style.styleId){
        map.setMapStyleV2({styleId: style.styleId});
      }else if(style.styleJson){
        const styleJson=require(`./Style/mapStyle_${style.styleJson}`) // eslint-disable-line
        if(styleJson!==null){
          map.setMapStyleV2({styleJson});
        }
      }
    }

    // 渲染控件
    controls.forEach(item=>{
      const controltype=item.type;
      let control=null;
      let opt={};
      if(item.option){
        const [width,height]=item.option.offset;
        opt={
          // 控件的停靠位置
          anchor: item.option.anchor,
          // 控件基于停靠位置的偏移量(可选)
          offset: new BMapGL.Size(width, height)
        }
      }
      switch (controltype) {
        case 'scale':
          control=new BMapGL.ScaleControl(opt);
          break;
        case 'zoom':
          control=new BMapGL.ZoomControl(opt);
          break;
        case 'location':
          control=new BMapGL.LocationControl(opt);
          break;
        case 'cityList':
          control=new BMapGL.CityListControl(opt);
          break;
        case '3D':
          control=new BMapGL.NavigationControl3D(opt);
          break;
        default:;
      }
      if(control!==null){
        map.addControl(control);
      }
    })

    // 渲染点覆盖物
    markers.forEach(item=>{
      if(item.position&&item.position.length===2){
        const position=new BMapGL.Point(item.position[0], item.position[1])
        const opt={};
        if(item.option){
          if(item.option.offset&&item.option.offset.length===2){
            opt.offset=new BMapGL.Size(item.option.offset[0],item.option.offset[1]);
          }
          if(item.option.icon&&item.option.icon.url&&item.option.icon.size){
            opt.icon=new BMapGL.Icon(item.option.icon.url, new BMapGL.Size(item.option.icon.size[0], item.option.icon.size[1]));
          }
          if(item.title){
            opt.title=item.option.title;
          }
        }
        const marker = new BMapGL.Marker(position,opt);
        item.events.forEach(event=>{
          marker.addEventListener(event.type,event.eventFunc);
        })
        map.addOverlay(marker);
      }
    })

    // 渲染信息窗口
    infoWindows.forEach(item=>{
      if(item.position&&item.position.length===2){
        const position=new BMapGL.Point(item.position[0], item.position[1])
        let opts={};
        if(item.option){
          opts=item.option;
        }
        const infoWindow=new BMapGL.InfoWindow(item.content,opts)
        map.openInfoWindow(infoWindow, position);
      }
    })

    getMapInstance(map)
  }

  render() {
    const { style }=this.props;
    return (
      <Fragment>
        <div style={style} id="container" />
      </Fragment>
    );
  }
}

通过props.getMapInstance将地图实例返回给父组件,以便在地图组件外也可以进行地图操作。

5. 调用地图组件

import React, { PureComponent, Fragment } from 'react';
import car from '@/assets/car5.png';
import {Button, Row} from "antd";
import BaiduMap from "@/components/Aardvark/BaiduMap";


export default class Bmap extends PureComponent {

  state={
    mapInstance:null
  }

  getMapInstance=(instance)=>{
    this.setState({
      mapInstance:instance
    })
  }

  setZoomIn=()=>{
    const {mapInstance}=this.state;
    mapInstance.zoomIn()
  }

  setZoomOut=()=>{
    const {mapInstance}=this.state;
    mapInstance.zoomOut()
  }

  render() {
    const mapProps={
      lng:116.280190, // 经度
      lat:40.049191, // 纬度
      zoom:20, // 级别
      minZoom:5, // 最小级别
      maxZoom:25, // 最小级别
      enableScrollWheelZoom:true, // 地图可被鼠标滚轮缩放
      enableDragging:true, // 地图拖拽
      heading:60, // 旋转角度
      tilt:70, // 俯角
      style:{
        styleId:'6b5ed52e4b01d6674be71c30adabaaf4',
        styleJson:'blue'
      }, // 地图样式
      controls:[
        {
          type:'scale',
          option:{
            anchor:'BMAP_ANCHOR_BOTTOM_LEFT',
            offset: [60,30]
          }
        },
        {
          type:'zoom',
        },
        {
          type:'location',
        },
        {
          type:'cityList',
        },
        {
          type:'3D',
        },
      ],
      markers:[
        {
          position: [116.280190, 40.049191],
          option: {
            offset: [20, 20],
            icon: {
              url: car,
              size: [52, 26]
            },
            title: '文本标注'
          },
          events: [
            {
              type:'click',
              eventFunc:()=> {
                console.log('marker被点击')
              },
            }
          ]
        }
      ],
      infoWindows:[
        {
          position:[116.280195, 40.049198],
          option:{
            width: 600,
            height: 300,
            title: '故宫博物院'
          },
          content:`<h4 style='margin:0 0 5px 0;'>天安门</h4>
            <img style='float:right;margin:0 4px 22px' id='imgDemo' src='../img/tianAnMen.jpg' width='139' height='104'/>
            <p style='margin:0;line-height:1.5;font-size:13px;text-indent:2em'>
            天安门坐落在中国北京市中心,故宫的南侧,与天安门广场隔长安街相望,是清朝皇城的大门...
            </p></div>`
        }
      ]
    }

    return (
      <Fragment>
        <Row>
          <Button style={{zIndex:99}} onClick={this.setZoomIn}>增加zoom</Button>
          <Button style={{zIndex:99}} onClick={this.setZoomOut}>减小zoom</Button>
        </Row>
        <Row>
          <div style={{width:'100%',height:800}}>
            <BaiduMap mapProps={mapProps} getMapInstance={this.getMapInstance} style={{width:'100%',height:'100%'}} />
          </div>
        </Row>
      </Fragment>
    );
  }
}