Mapas

Introducción

En este tutorial, veremos como incluir mapas dentro de un formulario que muestren la ubicación que tiene un elemento en el mapa siguiendo las coordenadas de latitud y longitud.

Instalación del módulo de mapas

Ejecutamos el siguiente comando

npm install ontimize-web-ngx-map --save

Añadimos al fichero angular.json los estilos del mapas y la carpeta de recursos de los mapas leaflet

angular.json

{
  ...
  "assets": [
    "src/favicon.ico",
    "src/assets",
    {
      "glob": "**/*",
      "input": "node_modules/ontimize-web-ngx/assets",
      "output": "/assets"
    },
    {
      "glob": "**/*",
      "input": "node_modules/ngx-extended-pdf-viewer/assets",
      "output": "/assets"
    },
    {
      "glob": "**/*",
      "input": "node_modules/ontimize-web-ngx-charts/assets",
      "output": "/assets"
    },
    {
      "glob": "**/*",
      "input": "node_modules/leaflet/dist/images",
      "output": "/assets"
    },
    "src/manifest.webmanifest"
  ],
  "styles": [
    "node_modules/ontimize-web-ngx-charts/styles.scss",
    "node_modules/ontimize-web-ngx-map/styles.scss",
    "node_modules/ontimize-web-ngx/ontimize.scss",
    "src/assets/css/app.scss",
    "src/styles.scss"
  ],
  ...
}

Añadimos la declaración del módulo de mapas al módulo shared

shared.module.ts

import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { OntimizeWebModule } from 'ontimize-web-ngx';
import { AccountNumberRenderComponent } from '../main/accounts/accounts-home/account-number-render/account-number-render.component';
import { CustomertypeColumnRendererComponent } from '../main/customers/customers-home/customertype-column-renderer/customertype-column-renderer.component';
import { MovementColumnRendererComponent } from '../main/accounts/accounts-detail/movement-column-renderer/movement-column-renderer.component';
import { MENU_COMPONENTS } from './app.menu.config';
import { OChartModule } from 'ontimize-web-ngx-charts';
import { AccountsDetailComponent } from '../main/accounts/accounts-detail/accounts-detail.component';
import { OMapModule } from "ontimize-web-ngx-map";

export function intRateMonthlyFunction(rowData: Array<any>): number {
  return rowData["INTERESRATE"] / 12;
}

@NgModule({
  imports: [
    OntimizeWebModule,
    OChartModule,
    OMapModule
  ],
  declarations: [
    AccountNumberRenderComponent,
    CustomertypeColumnRendererComponent,
    MovementColumnRendererComponent,
    ...MENU_COMPONENTS,
    AccountsDetailComponent
  ],
  exports: [
    CommonModule,
    AccountNumberRenderComponent,
    CustomertypeColumnRendererComponent,
    MovementColumnRendererComponent,
    ...MENU_COMPONENTS,
    OChartModule,
    AccountsDetailComponent,
    OMapModule
  ]
})
export class SharedModule { }

Añadir el mapa a un formulario

Envolveremos el mapa con un contenedor que sólo se mostrará si hemos cargado la latitud y longitud en el formulario. Para ello, utilizaremos el evento del formulario onDataLoaded. Tanto el mapa como la capa de marcadores obtendrán las coordenadas de una función llamada getPositionGPS(), que devolverá la latitud y longitud, separadas por comas, que se hayan guardado en la carga del formulario

customers-detail.component.html

<o-form #form attr="customerDetail" service="customers" entity="customer" keys="CUSTOMERID" header-actions="R;I;U;D"
    show-header-navigation="no" class="fill-form" (onDataLoaded)="onFormDataLoaded($event)">
    <o-text-input attr="CUSTOMERID" sql-type="INTEGER" enabled="no"></o-text-input>
    <div fxFlex fxLayout="row" fxLayoutGap="8px">
        <div>
            <o-image id="CUSTOMER_PHOTO" attr="PHOTO" empty-image="assets/images/no-image.png"
                sql-type="OTHER"></o-image>
        </div>
        <mat-tab-group fxFlex="60">
            <mat-tab label="{{ 'CUSTOMER_PERSONAL_INFORMATION' | oTranslate }}">
                <div fxLayout="row" fxLayoutGap="8px">
                    <o-text-input fxFlex="40" attr="NAME" required="yes"></o-text-input>
                    <o-text-input fxFlex="40" attr="SURNAME" required="yes"></o-text-input>
                    <o-date-input fxFlex="20" attr="STARTDATE"></o-date-input>
                </div>
                <div fxLayout="row" fxLayoutGap="8px">
                    <o-nif-input fxFlex="40" attr="ID" required="yes"></o-nif-input>
                    <o-integer-input fxFlex="40" attr="PHONE" step="0" thousand-separator=" "></o-integer-input>
                    <o-combo fxFlex="20" attr="CUSTOMERTYPEID" service="customers" entity="customerType"
                        keys="CUSTOMERTYPEID" columns="CUSTOMERTYPEID;DESCRIPTION" visible-columns="DESCRIPTION"
                        value-column="CUSTOMERTYPEID"></o-combo>
                </div>
                <o-email-input attr="EMAIL"></o-email-input>
                <o-text-input attr="ADDRESS"></o-text-input>
                <div fxLayout="row" fxLayoutGap="8px">
                    <o-real-input fxFlex="50" attr="LONGITUDE" decimal-separator="," max-decimal-digits="10"
                        min-decimal-digits="0"></o-real-input>
                    <o-real-input fxFlex="50" attr="LATITUDE" decimal-separator="," max-decimal-digits="10"
                        min-decimal-digits="0"></o-real-input>
                </div>
                <o-textarea-input attr="COMMENTS"></o-textarea-input>
            </mat-tab>
            <mat-tab label="{{ 'ACCOUNTS' | oTranslate }}">
                <o-table #accountCustomerTable attr="accountsTable" service="customers" entity="vCustomerAccount"
                    keys="ACCOUNTID" parent-keys="CUSTOMERID" insert-button="no" refresh-button="yes"
                    detail-mode="dblclick" delete-button="no" query-rows="20"
                    columns="CUSTOMERID;ACCOUNTID;ENTITYID;OFFICEID;CDID;ANID;STARTDATE;ENDDATE;INTERESRATE;ACCOUNTTYP"
                    visible-columns="ACCOUNTNUMBER;STARTDATE;ENDDATE;INTERESRATE;INTERESRATE_MONTHLY;ACCOUNTTYP">
                    <o-table-button attr="openAccount" (onClick)="openAccountDetailSelected()"
                        label="{{ 'OPEN_ACCOUNT_SELECTED' | oTranslate }}" icon="credit_card"></o-table-button>
                    <o-table-button attr="createAccount" (onClick)="createNewAccount()"
                        label="{{ 'CREATE_ACCOUNT' | oTranslate }}" icon="add_card"></o-table-button>
                    <o-table-column attr="STARTDATE" title="STARTDATE" type="date" format="LL"></o-table-column>
                    <o-table-column attr="ENDDATE" title="ENDDATE" type="date" format="LL"></o-table-column>
                    <o-table-column attr="INTERESRATE" title="INTERESRATE" type="percentage" width="150px"
                        decimal-separator="," content-align="center"></o-table-column>
                    <o-table-column attr="ACCOUNTNUMBER" title="ACCOUNTNUMBER" content-align="center">
                        <app-account-number-render></app-account-number-render>
                    </o-table-column>
                    <o-table-column-calculated attr="INTERESRATE_MONTHLY" title="INTERESRATE_MONTHLY"
                        [operation-function]="intRateMonthly" type="percentage" decimal-separator=","
                        content-align="center">
                    </o-table-column-calculated>
                </o-table>
            </mat-tab>
        </mat-tab-group>
        <div fxFlex="40" fxFlex.md="100" *ngIf="hasGPSPositition()">
            <o-map class="o-map" [center]="getPositionGPS()" zoom="10" min-zoom="3" max-zoom="20" zoom-control="yes"
                search-control="no" layer-panel-visible="no">
                <o-map-layer layer-type="marker" layer-id="location_marker"
                    [layer-center]="getPositionGPS()"></o-map-layer>
            </o-map>
        </div>
    </div>
</o-form>

customers-detail.component.ts

import { Component, ViewChild } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { OFormComponent, OTableComponent } from 'ontimize-web-ngx';
import { intRateMonthlyFunction } from 'src/app/shared/shared.module';
import { AddAccountComponent } from './add-account/add-account.component';

@Component({
  selector: 'app-customers-detail',
  templateUrl: './customers-detail.component.html',
  styleUrls: ['./customers-detail.component.css']
})
export class CustomersDetailComponent {

  @ViewChild('accountCustomerTable') accountTable: OTableComponent;
  @ViewChild('form') form: OFormComponent;
  public intRateMonthly = intRateMonthlyFunction;
  public longitude;
  public latitude;

  constructor(
    private router: Router,
    public dialog: MatDialog
  ) { }

  public openAccountDetailSelected() {
    let selected = this.accountTable.getSelectedItems();
    if (selected.length === 1) {
      let accountId = selected[0]['ACCOUNTID'];
      let customerId = selected[0]['CUSTOMERID'];
      this.router.navigate(['main/customers/' + customerId + '/' + accountId], { queryParams: { isdetail: true } });
    }
  }

  public createNewAccount() {
    let customerId = this.form.getFieldValue('CUSTOMERID');
    let date = new Date().getTime();
    this.dialog.open(AddAccountComponent, {
      data: {
        CUSTOMERID: customerId,
        STARTDATE: date
      }, disableClose: false
    })
  }

  onFormDataLoaded(data: any) {
    if (data.LATITUDE) {
      this.latitude = data.LATITUDE;
    }
    if (data.LONGITUDE) {
      this.longitude = data.LONGITUDE;
    }
  }

  hasGPSPositition() {
    if (this.latitude && this.longitude) {
      return true;
    }
    return false;
  }

  getPositionGPS() {
    return this.latitude + ',' + this.longitude;
  }

}

Podéis encontrar todo este tutorial realizado en el siguiente repositorio de Github

arrow_back Tutorial anterior