Tipos de mapas

Tipos de mapas

En este documento se analizan los tipos de mapas que puedes mostrar usando la Google Maps JavaScript API. La API usa un objeto MapType para contener información sobre estos mapas. Un objeto MapType es una interfaz que define la visualización, el uso de mosaicos de mapas y la conversión (dentro de sistemas de coordenadas) de coordenadas en pantalla a coordenadas terrestres (en el mapa). Cada MapType debe contener algunos métodos para administrar la recuperación y activación de mosaicos, y propiedades que definen su comportamiento visual.

El funcionamiento interno de los tipos de mapas dentro de la Google Maps API es un tema avanzado. La mayoría de los desarrolladores pueden simplemente usar los tipos de mapas básicos, mencionados a continuación. Sin embargo, también puedes definir tus propios mosaicos de mapas usando tipos de mapas personalizados o modificar la presentación de tipos de mapas existentes usando mapas con estilos. Cuando proporciones tipos de mapas personalizados, deberás comprender la manera de modificar el registro de tipos de mapas.

Tipos de mapas básicos

Hay cuatro tipos de mapas disponibles dentro de la Google Maps API. Además de los mosaicos conocidos de mapas de carreteras “pintados”, la Google Maps API admite otros tipos de mapas.

Los siguientes tipos de mapas se encuentran disponibles en la Google Maps API:

  • MapTypeId.ROADMAP muestra la vista del mapa de carreteras predeterminado. Este es el modo de mapa predeterminado.
  • MapTypeId.SATELLITE muestra imágenes satelitales de Google Earth.
  • MapTypeId.HYBRID muestra una combinación de vistas normales y satelitales.
  • MapTypeId.TERRAIN muestra un mapa físico basado en información terrestre.

El tipo de mapa que usa Map se modifica configurando su propiedad mapTypeId, ya sea realizando ajustes en la configuración de su objeto Map options dentro del constructor o llamando al método setMapTypeId(). El valor predeterminado de la propiedad mapTypeID es MapTypeId.ROADMAP.

Configuración de mapTypeId tras la construcción:

var myLatlng = new google.maps.LatLng(-34.397, 150.644);
var mapOptions = {
  zoom: 8,
  center: myLatlng,
  mapTypeId: google.maps.MapTypeId.SATELLITE
};
var map = new google.maps.Map(document.getElementById("map"),
    mapOptions);

Modificación dinámica de mapTypeId:

map.setMapTypeId(google.maps.MapTypeId.TERRAIN);

Ten en cuenta que la configuración del tipo de un mapa no se realiza en forma directa. En lugar de ello, se configura el mapTypeId de este para hacer referencia a un objeto MapType con un identificador. La Maps Javascript API V3 emplea un registro de tipos de mapas para administrar estas referencias. A continuación, se explica dicho registro.

Imágenes a 45°

La Google Maps API admite imágenes especiales a 45° para determinadas aplicaciones. Las imágenes de alta resolución proporcionan vistas en perspectiva de cada punto cardinal (norte, sur, este y oeste). Estas imágenes se encuentran disponibles a niveles de zoom más altos para los tipos de mapas admitidos.

En la imagen siguiente se muestra una vista en perspectiva a 45° del paseo marítimo de Santa Cruz, California:

Los tipos de mapas google.maps.MapTypeId.SATELLITE y google.maps.MapTypeId.HYBRID admiten imágenes a 45° a altos niveles de zoom, cuando se encuentran disponibles. Si el usuario aplica zoom de acercamiento a una ubicación para la que existen estas imágenes, las vistas de estos tipos de mapas automáticamente se modifican de la siguiente manera:

  • Se reemplazan las imágenes satelitales o híbridas por imágenes que ofrecen una perspectiva de 45°, con centro en la ubicación actual. De manera predeterminada, estas vistas se orientan hacia el norte. Si el usuario aplica zoom de alejamiento, las imágenes satelitales o híbridas predeterminadas aparecen nuevamente.
  • El control de rotación proporciona una combinación de opciones de inclinación y rotación. Si el valor de rotateControl es true, aparece un control de inclinación cuando hay disponibles imágenes a 45°. El control de inclinación permite al usuario dar a las imágenes una inclinación de 45°.
  • Cuando se inclinan las imágenes, aparece un gancho que permite al usuario rotar la vista 90° en sentido horario.

Cuando se aplica zoom de alejamiento a un tipo de mapa en el que se muestran imágenes a 45°, estos cambios se invierten y se restablecen los tipos de mapas originales.

Google agrega nuevas imágenes de ciudades a 45° constantemente. Consulta la lista de imágenes a 45° en Google Maps para obtener la información más reciente.

Cómo habilitar y deshabilitar imágenes a 45°

Puedes deshabilitar imágenes a 45° llamando a setTilt(0) en el objeto Map. Si deseas habilitar imágenes a 45° para tipos de mapas compatibles, llama a setTilt(45).

El método getTilt() de Map siempre refleja la inclinación actual que se muestra en el mapa. Si configuras una inclinación en un mapa y luego la eliminas (por ejemplo, aplicando zoom de alejamiento), el método getTilt() devolverá 0.

En el ejemplo siguiente se muestra una vista a 45° del centro de Portland, Oregon:

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 36.964, lng: -122.015},
    zoom: 18,
    mapTypeId: google.maps.MapTypeId.SATELLITE
  });
  map.setTilt(45);
}

Ver el ejemplo (aerial-simple.html).

Cómo rotar imágenes a 45°

Las imágenes a 45° son, en realidad, grupos de imágenes correspondientes a cada punto cardinal (norte, sur, este, oeste). Una vez que en tu mapa se muestren imágenes a 45°, puedes orientarlas hacia uno de sus puntos cardinales llamando a setHeading() en el objeto Map y pasándole un valor numérico expresado en grados con el norte como punto de partida.

En el ejemplo siguiente se muestra un mapa aéreo que gira en forma automática cada 3 segundos cuando se hace clic en el botón:

var map;

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 45.518, lng: -122.672},
    zoom: 18,
    mapTypeId: google.maps.MapTypeId.SATELLITE,
    heading: 90,
    tilt: 45
  });
}

function rotate90() {
  var heading = map.getHeading() || 0;
  map.setHeading(heading + 90);
}

function autoRotate() {
  // Determine if we're showing aerial imagery.
  if (map.getTilt() !== 0) {
    window.setInterval(rotate90, 3000);
  }
}

Ver el ejemplo (aerial-rotation.html).

Cómo modificar el registro de tipos de mapas

La propiedad mapTypeId de un mapa es un identificador de cadena que se usa para asociar un objeto MapType con un valor único. En cada objeto Map se incluye un elemento MapTypeRegistry que contiene la colección de objetos MapType del mapa en cuestión. Este registro se usa para seleccionar los tipos de mapas disponibles, por ejemplo, en el control MapType de Google Maps.

Las lecturas no se hacen directamente desde el registro de tipos de mapas En lugar de ello, se modifica el registro agregando tipos de mapas personalizados y asociándolos con un identificador de problemas que elijas. No se pueden modificar ni alterar los tipos de mapas básicos (puedes, no obstante, eliminarlos del mapa modificando el aspecto de su campo mapTypeControlOptions asociado).

El código siguiente permite configurar el mapa para que se muestren únicamente dos tipos de mapas en el campo mapTypeControlOptions de este, y modificar el registro para agregar la asociación con su identificador a la implementación real de la interfaz MapType. Nota: De manera deliberada, no documentamos la creación del tipo de mapa personalizado en el código anterior. Para obtener información sobre la construcción de un tipo de mapa, consulta Mapas con estilos o Tipos de mapas personalizados, a continuación.

// Modify the control to only display two maptypes, the
// default ROADMAP and the custom 'mymap'.
// Note that because this is simply an association, we
// don't need to modify the MapTypeRegistry beforehand.

var MY_MAPTYPE_ID = 'mymaps';

var mapOptions = {
  zoom: 12,
  center: brooklyn,
  mapTypeControlOptions: {
     mapTypeIds: [google.maps.MapTypeId.ROADMAP, MY_MAPTYPE_ID]
  },
  mapTypeId: MY_MAPTYPE_ID
};

// Create our map. This creation will implicitly create a
// map type registry.
map = new google.maps.Map(document.getElementById("map"),
    mapOptions);

// Create your custom map type using your own code.
// (See below.)
var myMapType = new MyMapType();

// Set the registry to associate 'mymap' with the
// custom map type we created, and set the map to
// show that map type.
map.mapTypes.set(MY_MAPTYPE_ID, myMapType);

Mapas con estilos

StyledMapType te permite personalizar la presentación de mapas básicos estándares de Google. Podrás cambiar la visualización de elementos como carreteras, parques y áreas con edificaciones para reflejar un estilo diferente del que se usó en el tipo de mapa predeterminado.

Se incluye información sobre StyledMapType en la sección Mapas con estilos de esta guía del desarrollador.

Tipos de mapas personalizados

La Google Maps JavaScript API ahora admite la visualización y administración de tipos de mapas personalizados, lo que te permite implementar tus propias superposiciones de imágenes o mosaicos de mapas.

Existen varias implementaciones de tipos de mapas posibles dentro de la API V3:

  • Conjuntos de mosaicos estándares que consisten en imágenes que en conjunto constituyen mapas cartográficos completos. Estos conjuntos de mosaicos también se conocen como tipos de mapas básicos. Estos tipos de mapas se comportan como los tipos de mapas predeterminados existentes: RUTAS, SATÉLITE, HÍBRIDO y TIERRA. Puedes agregar tu tipo de mapa personalizado a un conjunto mapTypes de Google Maps para permitir que la IU de la Google Maps API maneje tu tipo de mapa personalizado como un tipo de mapa estándar (por ejemplo, incluyéndolo en el control MapType).
  • Superposiciones de mosaicos de imágenes que aparecen sobre tipos de mapas básicos existentes. Generalmente, estos tipos de mapas se usan para aumentar un tipo de mapa existente a fin de que se muestre información adicional, y a menudo están limitados a ubicaciones o niveles de zoom específicos. Ten en cuenta que estos mosaicos pueden ser transparentes. Esto te permite agregar funciones a mapas existentes.
  • Tipos de mapas sin imágenes, que te permiten manipular la visualización de información en el nivel más esencial.

Cada una de estas opciones se basa en la creación de una clase que realiza la implementación de la interfaz de MapType. A su vez, la clase ImageMapType proporciona comportamiento integrado para simplificar la creación de objetos MapType de imágenes.

Antes de explicar las clases que implementan MapType, es importante comprender la manera en que Google Maps determina coordenadas y decide las partes de un mapa que se mostrarán. Deberás implementar una lógica similar para cualquier objeto MapType básico o de superposición.

Coordenadas de mapas

La Google Maps API usa varios sistemas de coordenadas:

  • Valores de latitud y longitud que hacen referencia a un punto del planeta de manera exclusiva. (Google usa el Sistema geodésico mundial de 1984, o estándar WGS84).
  • Coordenadas mundiales que hacen referencia a un punto del mapa de manera exclusiva.
  • Coordenadas de mosaicos que hacen referencia a un mosaico específico en el mapa, al nivel de zoom específico.

Coordenadas mundiales

Cuando la Google Maps API debe convertir una ubicación del planeta en una ubicación en un mapa (la pantalla), primero debe convertir valores de latitud y longitud en una coordenada “mundial”. Esta conversión tiene lugar a través de una proyección de mapa. Google Maps usa la proyección Mercator para este propósito. También puedes definir tu propia proyección implementando la interfaz google.maps.Projection. (Ten en cuenta que las interfaces de la API V3 no son clases con las que se puede crear subclases, sino simplemente especificaciones para clases que puedes definir tú mismo).

Para aportar practicidad al cálculo de coordenadas de píxeles (mira la imagen siguiente), se aplica la suposición de que un mapa con nivel 0 de zoom es un mosaico de tamaño básico. Luego se definen coordenadas mundiales relacionadas con coordenadas de píxeles en el nivel 0 de zoom usando la proyección para convertir latitudes y longitudes en posiciones de píxeles en el mosaico básico. Estas coordenadas mundiales son valores de puntos flotantes medidos del origen de la proyección del mapa a la ubicación específica. Ten en cuenta que este es un valor de punto flotante. Su resolución puede ser mucho más elevada que la resolución actual de la imagen del mapa que se muestra. En otras palabras, las coordenadas mundiales son independientes del nivel de zoom actual.

Las coordenadas mundiales de Google Maps se miden a partir del origen de la proyección Mercator (la esquina noroeste del mapa a 180° de longitud y aproximadamente 85° de latitud) y aumentan en el sentido de la x, hacia el este (derecha), y en el sentido de la y, hacia el sur (abajo). Debido a que el mosaico Mercator básico de Google Maps mide 256 x 256 píxeles, el espacio de coordenadas mundiales utilizable es {0-256}, {0-256} (Mira la imagen siguiente).

Ten en cuenta que las proyecciones Mercator tienen un ancho limitado en sentido longitudinal, pero un alto ilimitado en sentido latitudinal. Las imágenes del mapa básico se “recortan” usando la proyección Mercator a aproximadamente +/- 85° para que la forma del mapa resultante sea cuadrada, lo cual hace más sencilla la lógica de selección de mosaicos. Ten en cuenta que una proyección puede generar coordenadas mundiales fuera del espacio de coordenadas utilizable del mapa básico si la representación se realiza muy cerca de los polos, por ejemplo.

Coordenadas de píxeles

Las coordenadas mundiales reflejan ubicaciones absolutas en una proyección determinada, pero es necesario traducirlas a coordenadas de píxeles para determinar la desviación “en píxeles” a un nivel de zoom determinado. Estas coordenadas de píxeles se calculan usando la siguiente fórmula:

pixelCoordinate = worldCoordinate * 2zoomLevel

A partir de esta ecuación, se puede observar que cada nivel de aumento de zoom equivale al doble en la dirección de x e y. Por lo tanto, cada nivel de aumento de zoom tiene una resolución cuatro veces superior en comparación con el nivel anterior. Por ejemplo, en el nivel de zoom 1, el mapa consta de 4 mosaicos de 256 x 256 píxeles. Esto da como resultado un área de 512 x 512 píxeles. En el nivel de zoom 19, se puede hacer referencia a cada píxel de x e y del mapa con un valor de 0 a 256 * 219.

Debido a que las coordenadas mundiales se basan en el tamaño de mosaicos del mapa, la parte entera de las coordenadas de un píxel tiene como efecto la identificación del píxel exacto en dicha ubicación y en el nivel de zoom actual. Ten en cuenta que en el nivel de zoom 0, las coordenadas de píxeles son iguales a las coordenadas mundiales.

Ahora existe una manera de indicar con precisión cada ubicación en el mapa, a cada nivel de zoom. La Google Maps API construye un viewport a partir del centro del mapa con nivel de zoom (como un objeto LatLng) y el tamaño del elemento DOM que lo contiene, y convierte este cuadro de límite en coordenadas de píxeles. Luego, la misma API determina de manera lógica todos los mosaicos de mapa que caben dentro de los límites de píxeles determinados. Se hace referencia a cada uno de estos mosaicos de mapa a través de coordenadas de mosaicos, que simplifican enormemente la visualización de imágenes de mapas.

Coordenadas de mosaicos

La Google Maps API no podría cargar todas las imágenes de mapas a los niveles de zoom más altos que son más útiles; en lugar de ello, las desglosa a cada nivel de zoom y las convierte en un conjunto de mosaicos de mapa que se disponen de manera lógica en un orden descifrable para la aplicación. Cuando en un mapa se aplica desplazamiento hacia una nueva ubicación, o un cambio en el nivel de zoom, la Google Maps API determina los mosaicos necesarios mediante coordenadas de píxeles y convierte esos valores en un conjunto de mosaicos que se recuperarán. Estas coordenadas de mosaicos se asignan usando un esquema que permite determinar fácilmente, desde la perspectiva lógica, el mosaico que contiene las imágenes de un punto determinado.

La numeración de los mosaicos de Google Maps se origina en el mismo punto que la de los píxeles. Para la implementación de la proyección Mercator a través de Google, el mosaico de origen siempre se encuentra en la esquina noroeste del mapa. Los valores de x aumentan de oeste a este y los de y lo hacen de norte a sur. Los mosaicos reciben indexación mediante coordenadas x,y a partir del origen mencionado. Por ejemplo, en el nivel de zoom 2, y con el mundo dividido en 16 mosaicos, se puede hacer referencia a cada uno de estos con un par x,y único:

Ten en cuenta que al dividir las coordenadas de píxeles por el tamaño de mosaico y tomar la parte entera del resultado, se obtienen como subproducto las coordenadas de mosaico del nivel de zoom actual.

En el ejemplo siguiente se muestran coordenadas (valores LatLng, coordenadas mundiales, coordenadas de píxeles y coordenadas de píxeles) para Chicago, IL, a diferentes niveles de zoom:

Ver el ejemplo (map-coordinates.html)

La interfaz MapType

En los tipos de mapas personalizados debe implementarse la interfaz MapType. Esta interfaz especifica ciertas propiedades y ciertos métodos que permiten a la API iniciar solicitudes para tus tipos de mapas cuando determine que debe mostrar mosaicos de mapas con el viewport y el nivel de zoom actuales. Debes administrar estas solicitudes para decidir el mosaico que se cargará.

Nota: Puedes crear una clase propia para implementar esta interfaz, o bien (si tus imágenes son compatibles) usar la clase ImageMapType, que ya viene preparada para hacerlo.

Las clases que implementan la interfaz MapType exigen que definas y completes las siguientes propiedades:

  • tileSize (obligatoria) especifica el tamaño del mosaico (del tipo google.maps.Size). Los tamaños deben corresponder a formas rectangulares. No es necesario que estas sean cuadrados.
  • maxZoom (obligatoria) especifica el nivel de zoom máximo en el que deben mostrarse mosaicos de este tipo de mapa.
  • minZoom (opcional) especifica el nivel de zoom mínimo en el que deben mostrarse mosaicos de este tipo de mapa. De manera predeterminada, este valor es 0. Esto indica que no existe un nivel de zoom mínimo.
  • name (opcional) especifica el nombre de este tipo de mapa. Esta propiedad solo es necesaria si deseas que se pueda seleccionar este tipo de mapa dentro de un control MapType. (Consulta Cómo agregar controles MapType, a continuación).
  • alt (opcional) especifica el texto alternativo de este tipo de mapa, que se muestra mediante activación de texto. Esta propiedad solo es necesaria si deseas que se pueda seleccionar este tipo de mapa dentro de un control MapType. (Consulta Cómo agregar controles MapType, a continuación).

De manera adicional, a través de las clases que apliquen la interfaz MapType se deben implementar los siguientes métodos:

  • getTile() (obligatorio) es llamado cuando la API determina que en el mapa deben mostrarse nuevos mosaicos para el viewport en cuestión. El método getTile() debe tener la siguiente firma:

    getTile(tileCoord:Point,zoom:number,ownerDocument:Document):Node

    La API determina si debe llamar a getTile() según las propiedades tileSize, minZoom y maxZoom de MapType, y según el viewport y el nivel de zoom actuales del mapa. El receptor de este método debe devolver un elemento HTML con una coordenada, un nivel de zoom y un elemento de DOM al cual debe adjuntarse la imagen de mosaico.

  • releaseTile() (opcional) es llamado cuando la API determina que debe eliminarse un mosaico del mapa debido a que queda fuera de la vista. El método debe tener la siguiente firma:

    releaseTile(tile:Node)

    Normalmente, la eliminación de elementos adjuntados a los mosaicos del mapa debe administrarse una vez que se han agregado a este. Por ejemplo, si adjuntaste receptores de eventos a superposiciones de mosaicos de mapas, debes eliminarlos allí.

El método getTile() actúa como el controlador principal para determinar los mosaicos que deben cargarse dentro de un viewport.

Tipos de mapas básicos

Los tipos de mapas que construyas de esta manera pueden ser independientes o combinarse con otros como superposiciones. Los tipos de mapas independientes se conocen como tipos de mapas básicos. Probablemente te convenga hacer que la API trate los objetos MapType personalizados como a cualquier otro tipo de mapa básico existente (RUTAS, TIERRA, etc.). Para hacerlo, agrega tu objeto MapType personalizado a la propiedad mapTypes de Map. Esta propiedad es de tipo MapTypeRegistry.

Con el código siguiente se crea un objeto MapType básico para mostrar las coordenadas de mosaicos de un mapa y se dibuja un contorno de los mosaicos:

/*
 * This demo demonstrates how to replace default map tiles with custom imagery.
 * In this case, the CoordMapType displays gray tiles annotated with the tile
 * coordinates.
 *
 * Try panning and zooming the map to see how the coordinates change.
 */

/**
 * @constructor
 * @implements {google.maps.MapType}
 */
function CoordMapType(tileSize) {
  this.tileSize = tileSize;
}

CoordMapType.prototype.maxZoom = 19;
CoordMapType.prototype.name = 'Tile #s';
CoordMapType.prototype.alt = 'Tile Coordinate Map Type';

CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
  var div = ownerDocument.createElement('div');
  div.innerHTML = coord;
  div.style.width = this.tileSize.width + 'px';
  div.style.height = this.tileSize.height + 'px';
  div.style.fontSize = '10';
  div.style.borderStyle = 'solid';
  div.style.borderWidth = '1px';
  div.style.borderColor = '#AAAAAA';
  div.style.backgroundColor = '#E5E3DF';
  return div;
};

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 10,
    center: {lat: 41.850, lng: -87.650},
    streetViewControl: false,
    mapTypeId: 'coordinate',
    mapTypeControlOptions: {
      mapTypeIds: ['coordinate', google.maps.MapTypeId.ROADMAP],
      style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
    }
  });

  map.addListener('maptypeid_changed', function() {
    var showStreetViewControl = map.getMapTypeId() !== 'coordinate';
    map.setOptions({
      streetViewControl: showStreetViewControl
    });
  });

  // Now attach the coordinate map type to the map's registry.
  map.mapTypes.set('coordinate',
                   new CoordMapType(new google.maps.Size(256, 256)));
}

Ver el ejemplo (maptype-base.html).

Tipos de mapas de superposición

Algunos tipos de mapas están diseñados para funcionar sobre tipos de mapas existentes. Estos tipos de mapas tienen capas transparentes que muestran puntos de interés o datos adicionales al usuario. (La capa de tráfico de Google es un ejemplo de estos tipos de mapas).

En estos casos, no te convendrá tratar este tipo de mapa como una entidad separada. En lugar de ello, puedes agregar de manera directa el tipo de mapa a un objeto MapType existente usando la propiedad overlayMapTypes de Map. Esta propiedad contiene un MVCArray de objetos MapType. Todos los tipos de mapas (básicos y de superposición) se representan dentro de la capa mapPane. Los tipos de mapas de superposición aparecen sobre cualquier mapa básico al que se adjunten y en el orden en que aparecen en el conjunto Map.overlayMapTypes.

El ejemplo siguiente es idéntico al previo, con la excepción de que se creó un objeto MapType de superposición de mosaicos sobre el tipo de mapa ROADMAP:

/*
 * This demo illustrates the coordinate system used to display map tiles in the
 * API.
 *
 * Tiles in Google Maps are numbered from the same origin as that for
 * pixels. For Google's implementation of the Mercator projection, the origin
 * tile is always at the northwest corner of the map, with x values increasing
 * from west to east and y values increasing from north to south.
 *
 * Try panning and zooming the map to see how the coordinates change.
 */

/** @constructor */
function CoordMapType(tileSize) {
  this.tileSize = tileSize;
}

CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
  var div = ownerDocument.createElement('div');
  div.innerHTML = coord;
  div.style.width = this.tileSize.width + 'px';
  div.style.height = this.tileSize.height + 'px';
  div.style.fontSize = '10';
  div.style.borderStyle = 'solid';
  div.style.borderWidth = '1px';
  div.style.borderColor = '#AAAAAA';
  return div;
};

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 10,
    center: {lat: 41.850, lng: -87.650}
  });

  // Insert this overlay map type as the first overlay map type at
  // position 0. Note that all overlay map types appear on top of
  // their parent base map.
  map.overlayMapTypes.insertAt(
      0, new CoordMapType(new google.maps.Size(256, 256)));
}

Ver el ejemplo (maptype-overlay.html).

Tipos de mapas de imágenes

La implementación de un objeto MapType para que funcione como un tipo de mapa básico puede llevar tiempo y trabajo. La API proporciona una clase especial que implementa la interfaz MapType para los tipos de mapas más comunes; tipos de mapas que constan de mosaicos hechos de archivos de una imagen.

Esta clase, ImageMapType, se construye usando una especificación de objeto ImageMapTypeOptions en la que se definen las siguientes propiedades obligatorias:

  • tileSize (obligatoria) especifica el tamaño del mosaico (del tipo google.maps.Size). Los tamaños deben corresponder a formas rectangulares. No es necesario que estas sean cuadrados.
  • getTileUrl (obligatoria) especifica la función, generalmente proporcionada como un literal de función en línea, para administrar la selección del mosaico de imagen adecuado según las coordenadas mundiales y el nivel de zoom proporcionados.

Con el código siguiente se implementa una clase ImageMapType básica usando los mosaicos “moon tile” de Google. En el ejemplo se emplea una función de normalización para garantizar que los mosaicos se repitan en el eje x (no en el y) de tu mapa.

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 0, lng: 0},
    zoom: 1,
    streetViewControl: false,
    mapTypeControlOptions: {
      mapTypeIds: ['moon']
    }
  });

  var moonMapType = new google.maps.ImageMapType({
    getTileUrl: function(coord, zoom) {
        var normalizedCoord = getNormalizedCoord(coord, zoom);
        if (!normalizedCoord) {
          return null;
        }
        var bound = Math.pow(2, zoom);
        return '//mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw' +
            '/' + zoom + '/' + normalizedCoord.x + '/' +
            (bound - normalizedCoord.y - 1) + '.jpg';
    },
    tileSize: new google.maps.Size(256, 256),
    maxZoom: 9,
    minZoom: 0,
    radius: 1738000,
    name: 'Moon'
  });

  map.mapTypes.set('moon', moonMapType);
  map.setMapTypeId('moon');
}

// Normalizes the coords that tiles repeat across the x axis (horizontally)
// like the standard Google map tiles.
function getNormalizedCoord(coord, zoom) {
  var y = coord.y;
  var x = coord.x;

  // tile range in one direction range is dependent on zoom level
  // 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc
  var tileRange = 1 << zoom;

  // don't repeat across y-axis (vertically)
  if (y < 0 || y >= tileRange) {
    return null;
  }

  // repeat across x-axis
  if (x < 0 || x >= tileRange) {
    x = (x % tileRange + tileRange) % tileRange;
  }

  return {x: x, y: y};
}

Ver el ejemplo (maptype-image.html).

Proyecciones

La Tierra es una esfera tridimensional (aproximadamente), mientras que un mapa es una superficie bidimensional. Al igual que cualquier planisferio de la Tierra, el mapa que se ve dentro de la Google Maps API es una proyección de dicha esfera en una superficie plana. Una proyección puede definirse de la manera más simple como una asignación de valores de latitud y longitud a coordenadas del mapa de la proyección.

En las proyecciones de la Google Maps API debe implementarse la interfaz Projection. Una implementación de Projection no solo debe proporcionar una asignación de un sistema de coordenadas a otro, sino también una asignación bidireccional. Es decir, debes definir la manera de traducir coordenadas del planeta (objetos LatLng) al sistema de coordenadas mundicales de Projection y viceversa. Google Maps usa la proyección Mercator para crear mapas a partir de datos geográficos y convertir eventos de mapas en coordenadas geográficas. Puedes obtener estas proyección llamando a getProjection() en Map (o cualquier objeto MapType básico estándar) Con esta interfaz Projection estándar bastará para la mayoría de los usos, pero también puedes definir y usar tus propias proyecciones.

Cómo implementar una proyección

Al implementar una proyección personalizada, deberás definir algunos aspectos:

  • Las fórmulas para asignar coordenadas de latitud y longitud al plano cartesiano y viceversa. (La interfaz Projection solo admite transformaciones a coordenadas rectilíneas).
  • El tamaño de mosaico básico. Todos los mosaicos deben ser rectangulares.
  • El “tamaño del mundo” de un mapa con el mosaico básico en el nivel de zoom 0. Ten en cuenta que para los mapas compuestos por un mosaico en el nivel de zoom 0, el tamaño del mundo y el tamaño de mosaico básico son idénticos.

Coordinar transformaciones en proyecciones

Cada proyección proporciona dos métodos que permiten realizar conversiones de uno de estos dos sistemas de coordenadas al otro, lo cual te permite convertir coordenadas geográficas a mundiales:

  • El método Projection.fromLatLngToPoint() convierte un valorLatLng en una coordenada mundial. Este método se usa para posicionar superposiciones en el mapa (y el mapa en sí mismo).
  • El método Projection.fromPointToLatLng() convierte una coordenada mundial en un valorLatLng. Este método se usa para convertir eventos en coordenadas geográficas como los clics sobre el mapa.

Google Maps interpreta que las proyecciones son rectilíneas.

En general, puedes usar una proyección en dos casos: para crear un mapa del mundo o para crear un mapa de un área local. En el primer caso, debes asegurarte de que tu proyección también sea rectilínea y normal en todas las longitudes. Algunas proyecciones (en especial, las cónicas) pueden ser “normales a nivel local” (es decir, apuntar hacia el norte) y, no obstante, desviarse del norte geográfico, por ejemplo, cuanto más se posiciona el mapa respecto de una longitud de referencia determinada. Puedes usar dicha proyección a nivel local, pero debes tener presente que esta es necesariamente imprecisa y que los errores serán cada vez más notorios cuanta más desviación exista respecto de la longitud de referencia.

Selección de mosaicos de mapas en proyecciones

Las proyecciones no solo son útiles para determinar las posiciones de ubicaciones o superposiciones, sino también para posicionar los propios mosaicos de mapas. La Google Maps API representa mapas básicos a través de la interfaz MapType, que debe declarar una propiedad projection para identificar la proyección del mapa y un método getTile() para recuperar mosaicos de mapas conforme a valores de coordenadas de mosaicos. Las coordenadas de mosaicos se basan en el tamaño de mosaico básico que usas (la forma debe ser rectangular) y el “tamaño del mundo” de tu mapa, que equivale al tamaño en píxeles de tu mapa mundial en el nivel de zoom 0. Ten en cuenta que para los mapas compuestos por un mosaico en el nivel de zoom 0, el tamaño del mundo y el tamaño de mosaico básico son idénticos.

Debes definir el tamaño de mosaico básico dentro de la propiedad tileSize de tu objeto MapType. El tamaño del mundo se define de manera implícita dentro de los métodos fromLatLngToPoint() y fromPointToLatLng() de tu proyección.

Debido a que la selección de imágenes depende de estos valores pasados, resulta útil nombrar imágenes que puedan seleccionarse de manera programática con esos valores; por ejemplo, map_zoom_tileX_tileY.png.

En el ejemplo siguiente se define un ImageMapType en el que se usa la proyección de Gall-Peters:

// This example defines an image map type using the Gall-Peters projection.
// https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection

function initMap() {
  // Create a map. Use the Gall-Peters map type.
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 0,
    center: {lat: 0, lng: 0},
    mapTypeControl: false
  });

  initGallPeters();
  map.mapTypes.set('gallPeters', gallPetersMapType);
  map.setMapTypeId('gallPeters');

  // Show the lat and lng under the mouse cursor.
  var coordsDiv = document.getElementById('coords');
  map.controls[google.maps.ControlPosition.TOP_CENTER].push(coordsDiv);
  map.addListener('mousemove', function(event) {
    coordsDiv.textContent =
        'lat: ' + Math.round(event.latLng.lat()) + ', ' +
        'lng: ' + Math.round(event.latLng.lng());
  });

  // Add some markers to the map.
  map.data.setStyle(function(feature) {
    return {
      title: feature.getProperty('name'),
      optimized: false
    };
  });
  map.data.addGeoJson(cities);
}

var gallPetersMapType;
function initGallPeters() {
  var GALL_PETERS_RANGE_X = 800;
  var GALL_PETERS_RANGE_Y = 512;

  // Fetch Gall-Peters tiles stored locally on our server.
  gallPetersMapType = new google.maps.ImageMapType({
    getTileUrl: function(coord, zoom) {
      var scale = 1 << zoom;

      // Wrap tiles horizontally.
      var x = ((coord.x % scale) + scale) % scale;

      // Don't wrap tiles vertically.
      var y = coord.y;
      if (y < 0 || y >= scale) return null;

      return 'images/gall-peters_' + zoom + '_' + x + '_' + y + '.png';
    },
    tileSize: new google.maps.Size(GALL_PETERS_RANGE_X, GALL_PETERS_RANGE_Y),
    isPng: true,
    minZoom: 0,
    maxZoom: 1,
    name: 'Gall-Peters'
  });

  // Describe the Gall-Peters projection used by these tiles.
  gallPetersMapType.projection = {
    fromLatLngToPoint: function(latLng) {
      var latRadians = latLng.lat() * Math.PI / 180;
      return new google.maps.Point(
          GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360),
          GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians)));
    },
    fromPointToLatLng: function(point, noWrap) {
      var x = point.x / GALL_PETERS_RANGE_X;
      var y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y));

      return new google.maps.LatLng(
          Math.asin(1 - 2 * y) * 180 / Math.PI,
          -180 + 360 * x,
          noWrap);
    }
  };
}

// GeoJSON, describing the locations and names of some cities.
var cities = {
  type: 'FeatureCollection',
  features: [{
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [-87.650, 41.850]},
    properties: {name: 'Chicago'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [-149.900, 61.218]},
    properties: {name: 'Anchorage'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [-99.127, 19.427]},
    properties: {name: 'Mexico City'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [-0.126, 51.500]},
    properties: {name: 'London'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [28.045, -26.201]},
    properties: {name: 'Johannesburg'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [15.322, -4.325]},
    properties: {name: 'Kinshasa'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [151.207, -33.867]},
    properties: {name: 'Sydney'}
  }, {
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [0, 0]},
    properties: {name: '0°N 0°E'}
  }]
};

Ver el ejemplo (map-projection-simple.html).

Enviar comentarios sobre...

Google Maps JavaScript API
Google Maps JavaScript API
Si necesitas ayuda, visita nuestra página de asistencia.