Cesium调用高德地图服务实现搜索地点定位详解

一、需求分析

需要做一个类似于高德地图的搜索可以参考高德地图,用户输入地点,下拉列表自动弹出少量的相应地点,点击内容地点可以直接选择定位并且添加Cesium的广告牌(图标)和标注,点击标注可以弹出详细信息,点击搜索则通过输入地点查找出全部内容并且显示图片,搜索到的内容因为较多,所以内容增加分页功能。

二、后台接口SpringBoot+高德地图Web服务

高德服务地址:https://lbs.amap.com/api/webservice/summary/

用的高德搜索POI输入提示

Controller

	/**
	 * 查询输入位置数据
	 * @param id
	 * @return
	 * @author ygc
	 * @throws IOException 
	 */
	@RequestMapping("/queryInputPositionData")
	@SecurityParameter
	@ResponseBody
	@Transactional(propagation=Propagation.SUPPORTS)
	public Result  queryInputPositionData(@RequestBody RequestInfo requestInfo,HttpServletResponse response) throws IOException {	
		response.setContentType("text/html;charset=UTF-8");   
	    response.setHeader("Content-type", "application/json;charset=UTF-8");
	    if(RedisPool.checkToken(requestInfo.getToken())==false){
	    	return RedisTool.msgResult();
	    }
		Map<?, ?> map= (Map<?, ?>) requestInfo.getData();
		String position=(String)map.get("position");
		Result temp=sysuserService.queryInputPositionDataByPosition(position,requestInfo.getUid());
		return temp; 
	}
	/**
	 * 查询输入搜索数据
	 * @param id
	 * @return
	 * @author ygc
	 * @throws IOException 
	 */
	@RequestMapping("/querySearchPositionData")
	@SecurityParameter
	@ResponseBody
	@Transactional(propagation=Propagation.SUPPORTS)
	public Result  querySearchPositionData(@RequestBody RequestInfo requestInfo,HttpServletResponse response) throws IOException {	
		response.setContentType("text/html;charset=UTF-8");   
	    response.setHeader("Content-type", "application/json;charset=UTF-8");
	    if(RedisPool.checkToken(requestInfo.getToken())==false){
	    	return RedisTool.msgResult();
	    }
		Map<?, ?> map= (Map<?, ?>) requestInfo.getData();
		String position=(String)map.get("position");
		Integer currentPage=(Integer)map.get("currentPage");
		Result temp=sysuserService.querySearchPositionDataByPosition(position,requestInfo.getUid(),currentPage);
		return temp; 
	}

Service

	public Result queryInputPositionDataByPosition(String position, String uid) {
		   String key="68c16866958532b7b092f23a52ff6862";
		   BufferedReader in = null;  
	        String url="https://restapi.amap.com/v3/assistant/inputtips?output=json&keywords="+position+"&key="+key;
	        try {  
			URL Url = new URL(url); 
	            // 打开和URL之间的连接  
	            URLConnection connection = Url.openConnection();  
	            // 设置通用的请求属性  
	            connection.setConnectTimeout(5000);  
	            connection.setReadTimeout(5000);  
	            // 建立实际的连接  
	            connection.connect();  
	            // 定义 BufferedReader输入流来读取URL的响应  
	            in = new BufferedReader(new InputStreamReader(connection.getInputStream()));  
	            StringBuffer sb = new StringBuffer();  
	            String line;  
	            while ((line = in.readLine()) != null) {  
	                sb.append(line);  
	            }  
	    		JSONObject userJson = JSONObject.parseObject(sb.toString());
				com.alibaba.fastjson.JSONArray tips = userJson.getJSONArray("tips");


//	    		String tips = (String) userJson.get("tips");
//	            System.out.println(sb.toString()); 
	     	    Result result=new Result();
	            result.setUid(uid);
	            result.setCode(200); 
			    result.setData(tips);   
			    result.setResult("成功"); 
			    result.setMessage("查询输入位置数据"); 
			    return result;
	        } catch (Exception e1) { 
	        	e1.printStackTrace();
	        	throw new RuntimeException(e1);	  
	        }  
	        // 使用finally块来关闭输入流  
	        finally {  
	            try {  
	                if (in != null) {  
	                    in.close();  
	                }  
	            } catch (Exception e2) {  
	                e2.printStackTrace();  
	            }  
	        }

	}

	public Result querySearchPositionDataByPosition(String position, String uid, Integer currentPage) {
		   String key="68c16866958532b7b092f23a52ff6862";
		   BufferedReader in = null;  
		   int pageSize=10;
		   String url="https://restapi.amap.com/v3/place/text?keywords="+position+"&output=json&offset="+pageSize+"&page="+currentPage+"&key="+key+"&extensions=all";
//	        String url="https://restapi.amap.com/v3/assistant/inputtips?output=json&keywords="+position+"&key="+key;
	        try {  
			URL Url = new URL(url); 
	            // 打开和URL之间的连接  
	            URLConnection connection = Url.openConnection();  
	            // 设置通用的请求属性  
	            connection.setConnectTimeout(5000);  
	            connection.setReadTimeout(5000);  
	            // 建立实际的连接  
	            connection.connect();  
	            // 定义 BufferedReader输入流来读取URL的响应  
	            in = new BufferedReader(new InputStreamReader(connection.getInputStream()));  
	            StringBuffer sb = new StringBuffer();  
	            String line;  
	            while ((line = in.readLine()) != null) {  
	                sb.append(line);  
	            }  
	    		JSONObject userJson = JSONObject.parseObject(sb.toString());
	    		System.out.println(userJson);
	    		JSONObject json=new JSONObject();
	    		if(currentPage==1) {
		    		Integer resultCount=Integer.valueOf(userJson.get("count").toString());
					int pageCount=(resultCount%pageSize==0)?resultCount/pageSize:(resultCount/pageSize+1);	
		    		System.out.println("resultCount:"+resultCount);
					System.out.println("pageCount:"+pageCount);
					json.put("pageCount", pageCount);
					json.put("resultCount",resultCount);
	    		}
				com.alibaba.fastjson.JSONArray pois = userJson.getJSONArray("pois");
				System.out.println("pageIndex:"+currentPage);
//	    		String tips = (String) userJson.get("tips");
//	            System.out.println(sb.toString()); 
			
				json.put("pageIndex", currentPage);
				json.put("pageSize", pageSize);
//				pois.add(json);
//				System.out.println(pois);
	     	    Result result=new Result();
	            result.setUid(uid);
	            result.setCode(200); 
			    result.setData(pois);   
			    result.setResult(json.toString()); 
			    result.setMessage("查询输入位置数据"); 
			    return result;
	        } catch (Exception e1) { 
	        	e1.printStackTrace();
	        	throw new RuntimeException(e1);	  
	        }  
	        // 使用finally块来关闭输入流  
	        finally {  
	            try {  
	                if (in != null) {  
	                    in.close();  
	                }  
	            } catch (Exception e2) {  
	                e2.printStackTrace();  
	            }  
	        }

	}

三、前端实现React+Antd+Dva+Cesium

Html+antd用的AutoComplete自动完成插件

import React, {Component} from "react";
import { Menu, Dropdown,Divider,Button } from 'antd';
import { DownOutlined } from '@ant-design/icons';
import DataSource from '@/assets/svg/DataSource.js'
import Measure from '@/assets/svg/Measure.js'
import Plot from '@/assets/svg/Plot.js'
import Remove from '@/assets/svg/Remove.js'
import { Input, AutoComplete,Icon,Select,Pagination  } from 'antd';
import { SelectProps } from 'antd/es/select';
import styles from '@/components/search/SearchPosition.css';
import config from '../../../public/config';
import { connect } from 'react-redux';
import * as Cesium from 'cesium';
import { removesDuplicates } from '@/components/utils/CommonTool';
const { Option, OptGroup } = AutoComplete;
/**
 * @author 于公成
 * @date 2020/6/30
 * @Description: 搜索位置
 */
let flag=this
class SearchPosition extends  React.Component{

  constructor(props) {
    super(props);

    this.state = {
      dataSource:[],
      data:{
        position:undefined
      },
      status:false,
      pageIndex:1,
      pageCount:1,
      resultCount:undefined
    };

  }

  componentDidMount(){

  }
  renderOption=(item)=>{
    let str=[];
    if(item.phones!=null){
      for(let i=0;i<item.phones.length;i++){
        if(item.phones[i]!=null){
            str.push(<img style={
   
   {width:'70px',height:'70px'}} src={item.phones[i].url}/>);
        }
      }
      return (

          <Option  key={item.name+item.id} position={item.location} text={item.name}>
            <div className="global-search-item">
            <span style={
   
   {color:'#999999',fontSize:'3px',float:'right'}}>{str.map((item)=>
                <span>
              {item}
            </span>
            )}</span>{item.name}<br/>{item.district}
            </div>
          </Option>

      );
    }else{
      return (
        <Option key={item.name+item.id} position={item.location} text={item.name}>
          <div className="global-search-item">
            {item.name}<br/><span style={
   
   {color:'#999999',fontSize:'3px'}}>{item.district}{str}</span>
          </div>
        </Option>


      );

    }

  }
   onSelect=(value,option)=> {
      let flag=this;
      let position=option.props.position;
      let lon=position.split(",")[0];
      let lat=position.split(",")[1];
      let viewer=  this.props.viewer.ceViewer;
     viewer.entities.removeById(1)
     viewer.entities.add({
       id:1,
       name : 'test',
       position : Cesium.Cartesian3.fromDegrees(Number(lon),Number(lat), 0),
       color : Cesium.Color.fromCssColorString('#000000'),

       //圆
      //  ellipse: {
      //    semiMinorAxis: 50,
      //    semiMajorAxis: 50,
      //    height: 10,
      //    outlineColor: Cesium.Color.RED,
      //    zIndex:0,
      //    //rotation : Cesium.Math.toRadians(45),//旋转角
      //    material: new Cesium.ImageMaterialProperty({
      //      image: '../img/标记.png\',',
      //      // //指定图像在每个方向上重复的次数,默认为Cesium.Cartesian2(1.0, 1.0),{Cartesian2}类型
      //      // repeat: Cesium.Cartesian2(1.0, 1.0),
      //      // // 默认为false,当图像具有透明性时设置为true(例如,当png具有透明部分时)
      //      // transparent: true,
      //      // color: Cesium.Color.WHITE.withAlpha(0.5),  //透明度0.5
      //    })
      //  },
       //点样式
       // point : {
       //   pixelSize : 25,
       //   color : Cesium.Color.RED,
       //   outlineColor : Cesium.Color.WHITE,
       //   // outlineWidth : 5
       // },
       //立广告牌
       billboard :{
         image:'../img/标记.png',
           show : true, // default
           width : 50, // default: undefined
           height : 50 // default: undefined
       },
       //字体标签样式
       label : {
         // text : option.props.text,
         text : option.props.text,
         font : '14pt',
         // color : Cesium.Color.BLUE,
         style: Cesium.LabelStyle.FILL_AND_OUTLINE,
         outlineWidth : 200,
         //垂直位置
         // verticalOrigin : Cesium.VerticalOrigin.BUTTON,
         //中心位置
         // pixelOffset : new Cesium.Cartesian2(0,0),
         eyeOffset: new Cesium.Cartesian3(0, 0, -10),

       }
     });


     // viewer. entities.removeById(1)
     // let pinBuilder = new Cesium.PinBuilder();
     // let bluePin = viewer.entities.add({
     //   id:'1',
     //   name: "test",
     //   position: Cesium.Cartesian3.fromDegrees(Number(lon),Number(lat), 0),
     //   billboard: {
     //     image:'../img/标记.png',
     //     // image: pinBuilder.fromColor(Cesium.Color.ROYALBLUE, 48).toDataURL(),
     //     verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
     //   },
     // });
     // Cesium.when.all(
     //   [bluePin],
     //   (pins)=> {
     //     viewer.zoomTo(pins);
     //   }
     // );
     // let loactionEntity;
     // if(loactionEntity)
     // viewer.entities.remove(loactionEntity);
     //  loactionEntity = new Cesium.Entity({
     //   id : 'flyTmp',
     //   position : Cesium.Cartesian3.fromDegrees(Number(lon),Number(lat), 2000.0),
     //   point : {
     //     pixelSize : 10,
     //     color : Cesium.Color.WHITE.withAlpha(0.9),
     //     outlineColor : Cesium.Color.WHITE.withAlpha(0.9),
     //     outlineWidth : 1
     //   }
     // });
     // viewer.entities.add(loactionEntity);
     // viewer.camera.flyTo(loactionEntity,{

     viewer.camera.flyTo({
     // viewer.flyTo(loactionEntity,{
        destination : Cesium.Cartesian3.fromDegrees(Number(lon),Number(lat), 5000.0),
        // orientation : {
        //   heading : Cesium.Math.toRadians(0.0),
        //   pitch : Cesium.Math.toRadians(-25.0),
        //   roll : 0.0
        // }
      });
    //添加点击事件
     let handler =new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
     handler.setInputAction(function (movement) {
       let pick = viewer.scene.pick(movement.position);
       // if (Cesium.defined(pick) && (pick.id.id === cid)) {
       if (Cesium.defined(pick)) {
         // window.open('www.baidu.com');
         flag.markWin(null,position);
       }
     }, Cesium.ScreenSpaceEventType.LEFT_CLICK);



    // console.log('onSelect', value,option);
    //  let position=option.props.position;
    //  let lon=position.split(",")[0];
    //  let lat=position.split(",")[1];
    //  let viewer=  this.props.viewer.ceViewer;
    //  viewer.camera.flyTo({
    //    destination : Cesium.Cartesian3.fromDegrees(Number(lon),Number(lat), 5000.0),
    //    // orientation : {
    //    //   heading : Cesium.Math.toRadians(0.0),
    //    //   pitch : Cesium.Math.toRadians(-25.0),
    //    //   roll : 0.0
    //    // }
    //  });

  }
  markWin=(e,position)=>{
    alert("当前坐标:"+position)
  }
  //查询输入位置
  handleSearch=(position)=> {
    let data=this.state.data;
    data.position=position
    this.setState({
      data:data
    });
    this.props.dispatch(
      {
        type:"query/querySecret",
        payload: {
          url:config.dataUrl+ "/userinfo/queryInputPositionData",
          data: {
            position:position
          }
        },
        callback:(result)=>{
          if(result.code==200){
            let list=[];
            // let list2=removesDuplicates(result.data,result.data.name);
            result.data.map((item)=>{
              if(item.location[0]!=null ){
                list.push(
                  {
                    name:item.name,
                    address:item.address,
                    location:item.location,
                    district:item.district,
                    id:item.id
                  }
                );
              }
            })
             let position=this.state.data.position;
            this.setState({
              dataSource:list,
              status:false,

            });
          }
        }
      }
    )

  };

  //点击搜索地点
  SearchPosition=(query)=>{

    let data=this.state.data;
    let position=data.position
    console.log(query)
    this.props.dispatch(
      {
        type:"query/querySecret",
        payload: {
          url:config.dataUrl+ "/userinfo/querySearchPositionData",
          data: {
            position:position,
            currentPage:1
          }
        },
        callback:(result)=>{
          if(result.code==200){

            let list=[];
            // let list2=removesDuplicates(result.data,result.data.name);
            result.data.map((item)=>{
              if(item.location[0]!=null ){
                list.push(
                  {
                    name:item.name,
                    address:item.address,
                    location:item.location,
                    district:item.cityname+item.adname,
                    id:item.id,
                    phones:item.photos
                  }
                );
              }
            })
            let position=this.state.data.position;
            let pageData=JSON.parse(result.result);
            this.setState({
              dataSource:list,
              status:true,
              pageIndex:1,
              pageCount:pageData.pageCount,
              resultCount:pageData.resultCount
            });
          }
        }
      }
    )

  }
  InputText=(info)=>{
      console.log(info)
  }
  onChange=(info)=>{
    console.log(info)
  }
  changePage=(type,info)=>{
    let data=this.state.data;
    let position=data.position

    let flag=this;
    let page=this.state.pageIndex;
    if(type=="indexPage"){

      this.props.dispatch(
        {
          type:"query/querySecret",
          payload: {
            url:config.dataUrl+ "/userinfo/querySearchPositionData",
            data: {
              position:position,
              currentPage:1
            }
          },
          callback:(result)=>{
            if(result.code==200){
              let list=[];
              // let list2=removesDuplicates(result.data,result.data.name);
              result.data.map((item)=>{
                if(item.location[0]!=null ){
                  list.push(
                    {
                      name:item.name,
                      address:item.address,
                      location:item.location,
                      district:item.cityname+item.adname,
                      id:item.id,
                      phones:item.photos
                    }
                  );
                }
              })
              let position=this.state.data.position;
              this.setState({
                dataSource:list,
                status:true,
                pageIndex:1
              });
            }
          }
        }
      )
    }
    if(type=="upPage"){
      page=page-1;
      flag.props.dispatch(
        {
          type:"query/querySecret",
          payload: {
            url:config.dataUrl+ "/userinfo/querySearchPositionData",
            data: {
              position:position,
              currentPage:page
            }
          },
          callback:(result)=>{
            if(result.code==200){
              let list=[];
              // let list2=removesDuplicates(result.data,result.data.name);
              result.data.map((item)=>{
                if(item.location[0]!=null ){
                  list.push(
                    {
                      name:item.name,
                      address:item.address,
                      location:item.location,
                      district:item.cityname+item.adname,
                      id:item.id,
                      phones:item.photos
                    }
                  );
                }
              })
              let position=this.state.data.position;
              flag.setState({
                dataSource:list,
                status:true,
                pageIndex:page
              });

              // flag.setState({
              //   currentPage:page-1
              // })
            }
          }
        }
      )
    }
    if(type=="downPage"){
      page=page+1;
      flag.props.dispatch(
        {
          type:"query/querySecret",
          payload: {
            url:config.dataUrl+ "/userinfo/querySearchPositionData",
            data: {
              position:position,
              currentPage:page
            }
          },
          callback:(result)=>{
            if(result.code==200){
              let list=[];
              // let list2=removesDuplicates(result.data,result.data.name);
              result.data.map((item)=>{
                if(item.location[0]!=null ){
                  list.push(
                    {
                      name:item.name,
                      address:item.address,
                      location:item.location,
                      district:item.cityname+item.adname,
                      id:item.id,
                      phones:item.photos
                    }
                  );
                }
              })
              let position=this.state.data.position;
              flag.setState({
                dataSource:list,
                status:true,
                pageIndex:page
              });
              // flag.setState({
              //   currentPage:page+1
              // })
            }
          }
        }
      )
    }

  }

  render(){
    let dataSource=this.state.dataSource;
    console.log("dataSource:"+dataSource)
    let result;
    if(dataSource[0]!=undefined){
      result=dataSource.map(this.renderOption).concat([
        <Option    disabled key="all" className={this.state.status==false?styles.hide:styles.show}>
          <div>
            <span  onClick={this.changePage.bind(this,"indexPage")}>共找到{this.state.resultCount}条结果</span>
            <span style={
   
   {marginLeft:'70px'}}>{this.state.pageIndex}/{this.state.pageCount}页</span>
            <span style={
   
   {marginLeft:'20px',cursor:'pointer',borderStyle:'solid',borderWidth:'1px',width:20,height:20}} onClick={this.changePage.bind(this,"indexPage")}>首页</span>
            <span style={
   
   {cursor:'pointer',borderStyle:'solid',borderWidth:'1px',width:20,height:20}}  className={this.state.pageIndex==1?styles.hideInput:styles.showInput} onClick={this.changePage.bind(this,"upPage")}>上一页</span>
            <span style={
   
   {cursor:'pointer',borderStyle:'solid',borderWidth:'1px',width:20,height:20}} className={this.state.pageIndex==this.state.pageCount?styles.hideInput:styles.showInput} onClick={this.changePage.bind(this,"downPage")}>下一页</span>
          </div>
        </Option>,
      ]);;
      console.log(result)
    }

    // const options = dataSource
    //   .map(group => (
    //     <OptGroup key={group.title}>
    //       {group.children.map(opt => (
    //         <Option key={opt.title} value={opt.title}>
    //           {opt.title}
    //         </Option>
    //       ))}
    //     </OptGroup>
    //   ))
    //   .concat([
    //     <Option disabled key="all" className="show-all">
    //       <div onClick={this.changePage}>
    //         首页
    //       </div>
    //     </Option>,
    //   ]);
    return(
      <div className={styles.Search}>
        <div className="global-search-wrapper" style={
   
   { width: 400 }}>
          <AutoComplete
            className="global-search"
            size="large"
            style={
   
   { width: '100%' }}
            // dataSource={options}
            dataSource={result}
            // dataSource={this.state.dataSource==undefined?null:this.state.dataSource.map(this.renderOption)}
            onChange={this.onChange}
            onSelect={this.onSelect}
            onSearch={this.handleSearch}
            placeholder="请输入地名"
            optionLabelProp="text"
          >
            <Input    allowClear={true}     onChange={this.InputText} suffix={
                <Button
                  className="search-btn"
                  style={
   
   { marginRight: -12 }}
                  size="large"
                  type="primary"
                  onClick={this.SearchPosition.bind(this)}
                >
                  <Icon type="search"     />
                </Button>
              }
            />
          </AutoComplete>
          {/*<div style={
   
   {backgroundColor:'white',width:500,height:200,position:'absolute',zIndex:200,top:'295px'}}>*/}
          {/*  <Pagination defaultCurrent={6} total={500}   />*/}
          {/*</div>*/}
        </div>

        <div id="cesiumContainer">
          <div style={
   
   {
            position: "absolute",
            width: "100px",
            height: "100px",
            zIndex: 1000,
            display: "none",
            background: "rgba(255, 255, 255, 0.5)",
            border: "2px solid greenyellow",
            borderRadius: "4px"
          }}></div>
        </div>
      </div>
    )
  }
}
function mapStateToProps(state) {
  return {
    verify:state.verify,
    user:state.user,
    viewer:state.viewer,
  };
}
export default connect(mapStateToProps)(SearchPosition);

四、实现效果

1.输入地点下拉列表

2.点击内容定位

3.点击搜索详细内容

4.详细内容分页

5.点击标注弹出信息

猜你喜欢

转载自blog.csdn.net/qq_17025903/article/details/107531352