项目整理——mobile gis 基于Ionic框架(Angular)的hybrid移动应用

概述

  1. 基于Ionic框架(Angular)开发hybrid移动应用,主要功能有地图要素展示、定位、导航、文件上传。
  2. 用户可查看或上传野生动物受伤地点,以及查看用户周围的援助设施(如警局、医院等)并查询路线
  3. 前端:HTML, Typescript结合Ionic框架(Angular),利用Google Map API对用户位置进行定位以及导航
  4. 后端:php, MySQL数据库

代码

app.module.ts

在每个子页面ts中import的module都要在app.module.ts中import并写入@NgModule中

import { FormsModule,ReactiveFormsModule } from '@angular/forms';

@NgModule({
  declarations: [AppComponent,SettingModalPage,ModalMapPage],
  entryComponents: [SettingModalPage,ModalMapPage],
  imports: [
    FormsModule,
    ReactiveFormsModule],
})

页面路由

  1. app-routing.module.ts中的Routes对象(Route对象被Angular抽象成一个接口,多个Route对象组成的数组用Route表示,注意跟Router: class区分)定义了路由的路径属性。
    用ionic generate page生成一个新的页面,就会在这里自动新增一个Route对象
    在这里插入图片描述
  2. app.component.html中的<ion-router-outlet>标签是页面中路由的出口。Router动态创建对应的组件,插入到<ion-router-outlet>标签中
    在这里插入图片描述
  3. 导航栏是tabs文件夹下的内容
    tabs.router.module.ts的Routes对象指定tabs导航栏怎么跳转到其他页面。所有子页面的Route对象都是tabs这一Route对象的子对象,即在其children数组内。
    用ionic generate page生成一个新的页面,要在这里创建对应的Route对象,即完成了一个页面的路由导航
    在这里插入图片描述
    tabs.page.html是导航栏的布局模板,在这里修改页面中标签的名称
    在这里插入图片描述
    在这里插入图片描述

创建search页面的地理定位(tab2)

关键:

  • 调用geolocation插件,获取定位
  • 函数的异步调用
  • 插值{{}}的使用

调用geolocation插件,获取定位

  1. 安装插件
    在这里插入图片描述
    在这里插入图片描述
  2. import模块
    src/app/app.module.ts.
    在这里插入图片描述
  3. 在子页面ts文件中import地理模块,在类的构造函数中声明geolocation
    在这里插入图片描述
  4. 在类中声明变量
    在这里插入图片描述

函数的异步调用

  1. 在类中声明方法findCurrentLocation(),用于获取定位。里面的then是异步调用,如果position成功返回则调用第一个箭头后的,如果失败则返回error,调用第二个箭头后的。
    在这里插入图片描述

  2. 在类的constructor中调用findCurrentLocation()
    在这里插入图片描述

插值{{}}的使用

  1. 在子页面的模板中(src/app/tab2/tab2.page.html)用插值({{}})把ts中生成的值绑定在页面
    在这里插入图片描述
  2. 最后得到页面
    在这里插入图片描述

创建定位地图页(map)

关键:

  • 导入Router模块,导航到另一个页面和传参
  • 使用ngOnInit()定义初始化函数
  • 调用google map api创建地图
  1. 生成地图页
    在这里插入图片描述

导入Router服务,导航到另一个页面和传参

  1. import中导入,并在constructor中进行依赖注入Router服务
    在这里插入图片描述

  2. 在tab2.page.ts中定义页面跳转函数goToMapPage(),在函数内部先调用findCurrentLocation()来获取当前坐标。
    在这里插入图片描述

  3. 在goToMapPage()调用**router.navigate()**方法导航到地图页面,添加一个 NavigationExtras (interface)对象,设置queryParams参数,并把这个页面获取到的坐标经纬度传给地图页面。
    在这里插入图片描述

  4. 在src/tab2/tab2.page.html中创建按钮绑定事件函数goToMapPage()
    在这里插入图片描述

  5. 在src/index.html中插入Google Maps JavaScript API的脚本,用于地图页面调用google的api
    在这里插入图片描述

  6. 在src/app/map/map.page.html中创建地图画布,src/app/map/map.page.scss中设置画布样式
    在这里插入图片描述
    在这里插入图片描述

  7. src/pages/map/map.page.ts中声明变量google
    在这里插入图片描述

  8. 在类中声明变量,其中变量mapElement来自html,用@ViewChild(属性装饰器,用于配置一个视图查询,类似getElementById)获取,设为ElementRef类(对视图中某个原生元素的包装器。)。
    在这里插入图片描述

  9. map.page.ts中导入,并注入依赖的服务ActivatedRoute(包含与当前组件相关的路由信息。)
    在这里插入图片描述

使用ngOnInit()定义初始化函数

  1. ActivatedRoute对象(interface)的queryParams参数获取tab2传来的参数。参数在传输过程转为字符串,要用**Number()**转为数值。
    **ngOnInit()**中设置表示组件一初始化就获取参数。
    在这里插入图片描述

调用google map api创建地图

  1. 定义loadMap()函数,用于调用Google API的google.maps.LatLng生成地图坐标,google.maps.Map(mapElement[, opts]) 创建地图,google.maps.Marker([opts])生成弹出窗口
    在这里插入图片描述
    创建google.maps.Geocoder对象,用 geocode(request, callback) 方法把坐标转为地址(reverse geocode),显示在弹出窗口
    在这里插入图片描述
  2. ngOnInit()中调用loadMap(),表示一初始化完成就生成地图
    在这里插入图片描述
  3. 最后结果(点击得到弹窗)
    在这里插入图片描述

创建搜索路径页面(setting-modal)

用NavParams, ModalController在页面内的窗口传参

  1. tab2.page.ts中import导入,并在constructor依赖注入ModalController (Ionic的内容窗格类,在本页面生成的一个窗口,通常用于做选项设置)

  2. 异步创建一个modalController窗口,在关闭时获取子页面的数据
    在这里插入图片描述

  3. setting-modal.page.ts中import导入,并在constructor依赖注入
    在这里插入图片描述

  4. 在这里插入图片描述

用*ngFor指令循环写数据

[{ngModel}]双向绑定实现输入和脚本同步

setting-modal.page.html
在这里插入图片描述

创建places页面,用于寻找周围设施

1. 用Promise的异步执行

2. 用Google Map的PlacesService查找地点

places.page.ts

  ngOnInit() {
    // 从tab2.ts传入数据
    this.route.queryParams.subscribe(params =>{
      console.log("param "+params);
      console.log(params.latitude);
      this.latitude = parseFloat(params.latitude);
      this.longitude = parseFloat(params.longitude);
      this.searchType = params.queryType;
      this.keyword = params.queryName;
      this.distance = parseInt(params.distance);
      console.log("distance "+params.distance);
      console.log("longitude "+params.longitude);
    });

    // 1.2 查找地方,resolve则循环搜索结果,在地图上mark出来;reject则输出错误
    this.queryPlaces().then((results:Array<any>)=>{
      for(let i=0;i<results.length;i++){
        this.createMarker(results[i]);
      }
      this.places = results;
    },(status)=>console.log(status));
  }
  
  queryPlaces(){
    // 2.1 创建地图
    this.currentLocation = new google.maps.LatLng(this.latitude,this.longitude);
    let mapOptions = {
      center:this.currentLocation,
      zoom:11
    }
    this.map = new google.maps.Map(document.getElementById('map'),mapOptions);

    // 2.2 创建google map的PlacesService对象,用于查找一定范围区域的searchType类型
    this.service = new google.maps.places.PlacesService(this.map);

    this.request = {
      location: this.currentLocation,
      radius: this.distance,
      type: this.searchType,
      rankBy: google.maps.places.DISTANCE
    };

    // 1.1 创建Promise对象,先执行nearbySearch再展示(resolve的话),或返回status(reject的话)
    return new Promise((resolve, reject)=>{
      this.service.nearbySearch(this.request,function(result,status){
        if(status === google.maps.places.PlacesServiceStatus.OK){
          resolve(result);
        }
        else{
          reject(status);
        }
      });
    });
  }

  // 2.3 用Marker对象创建标记点
  createMarker(place){
    let marker = new google.maps.Marker({
      map:this.map,
      animation:google.maps.Animation.DROP,
      position:place.geometry.location,
      title:place.name+place.vicinity+place.rating,
    });
    google.maps.event.addListener(marker,'click',function(){
      let infowindow = new google.maps.InfoWindow({
        content:marker.title
      });
      infowindow.open(this.map,marker)
    });
  }

创建direction导航页面

用*ngFor指令循环插值和事件绑定

places.page.html

    <ion-list>
      <ion-item>
          {{places?.length}} PLACES FOUND!<br/>
      </ion-item>
      <ion-item *ngFor="let place of places; let i = index" (click)="goToDirectionPage(i)">
        <ion-label>
          {{place.name}}<br/> {{place.vicinity}} <br/> Average Rating:{{place.rating}}
        </ion-label>
      </ion-item>
    </ion-list>

places.page.ts

  // 导航到direction页面,在html中点击调用,用index表示循环中的第几个place
  goToDirectionPage(index){
    // 把数据传给direction页面,必须转为字符串类型
    let navigationExtras:NavigationExtras = {
      queryParams:{
        origin:JSON.stringify(this.currentLocation),
        destination:JSON.stringify(this.places[index].geometry.location),
      }
    };
    this.router.navigate(['direction'],navigationExtras);
  }

用Google Map的DirectionsService和DirectionsRenderer对象设置导航

ngOnInit() {
    // 获取从places页面传来的数据,把字符串类型转回对象
    this.route.queryParams.subscribe(params =>{
      console.log("param "+params);

      this.origin = params.origin;
      this.destination = JSON.parse(params.destination);
      this.originObject = JSON.parse(this.origin);

      console.log("origin "+params.origin);
      console.log("destination "+params.destination);
    });

    // 
    this.calculateRoute();
  }

  calculateRoute(){
    let mapOptions = {
      center:new google.maps.LatLng(this.originObject),
      zoom:11
    }
    this.map = new google.maps.Map(document.getElementById('directionMap'),mapOptions);

    // 创建导航对象
    let directionsService = new google.maps.DirectionsService();
    let directionsDisplay = new google.maps.DirectionsRenderer();
    directionsDisplay.setMap(this.map);

    let request = {
      origin:this.originObject,
      destination:this.destination,
      travelMode: 'DRIVING'
    }

    directionsService.route(request,function(response,status){
      if (status === google.maps.DirectionsStatus.OK){
        directionsDisplay.setDirections(response);
        directionsDisplay.setPanel(document.getElementById('directionPanel'));
        console.log("status: " +status)
        
        var bounds = new google.maps.LatLngBounds();
        bounds.extend(this.originObject);
        bounds.extend(this.destination);
        this.map.fitBounds(bounds);
      }
      else{
        window.alert('Directions request failed due to '+status);
      }
    });
  }

创建表单页面(tab3)

用JSON.stringfy把输出的[object, object]转为字符串

用正则表达式去字符串的双引号

  async openModalMap(){
    const ModalMap = await this.modalController.create({
      component: ModalMapPage,
      componentProps:{latitude:this.latitude, longitude:this.longitude, address:this.address}
    });
    console.log("lati "+this.latitude)
    console.log("long "+this.longitude)

    // 关闭子页面setting-modal时,主页面获取子页面的数据searchDistance
    ModalMap.onDidDismiss().then((address)=>{
      // 正则表达式去字符串的双引号
      // JSON.stringfy把输出的[object, object]转为字符串
      this.address = JSON.stringify(address.data).replace(/"/g,"")
      this.form.controls.address.setValue(this.address);
      console.log('address: '+ JSON.stringify(address.data));
    });

版权声明:本文为goldgirly原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。