Zh GoogleMap CustomMapType

From Documentation
Jump to navigation Jump to search

Creating Custom Map Type

In this tutorial we will create three different Custom Map Types


Creating custom map type for common map

This map types for map, which you are not created (not create tiles), but you want use it in component (or plugin).

For example create custom map type for Open Street Map (which is included in component as predefined map type)


Go to Map Types


Lets create new type

In Map Types Details you have to fill required filds

  • Title - this is Name of your button on map
  • Descripion - tooltip for button
  • minZoom and maxZoom for map (you should know for what zoom tiles exists)
  • size and type of tiles
  • Get Tile URL function by using it Google Maps API can get tiles
  • Layer Type - it is way to how map of this type will be displayed
    • Map - displays only your tiles
    • Overlay - display your tiles over main map. This useful if your map covers only part of world and you want to show the other part too.

The result is


This is function code (this is JavaScript function)


function(ll, z) {
	var X = ll.x % (1 << z);  /* wrap */
	return "http://tile.openstreetmap.org/" + z + "/" + X + "/" + ll.y + ".png";
}


After creating map type lets show map of this type.

Set 'Published to yes (in other case this type would be skipped)


Go to Maps tab.

Open your map (if exists), or create new one.

Set Allow Custom Map Types to yes.

In next field Custom Map Types List enter your new custom map type ID. As you can see on first picture, my map type ID=1


Save changes and look at results

It is simple example of custom map type.



Creating custom map type for your tiles

For example you have an image of map, and want to use it in your site. Lets do that.

Open your favorite program to create tiles.

Create tiles from your image. Addition to tiles you've got a html-page to show your map.

Copy your tiles to folder on site, where you want store tiles.

Find the function in HTML-document, which return URL for tiles. Copy and paste function definition into Get Tile URL function field. Include into function body the other functions (if it is exists and needs). Correct address URL in your function to get tiles from right site folder.

Save and add your new map type to your map as we do in first example.


If your program for created tiles create more than one function, you have to the other functions include in main function for getting tiles.



Creating custom map type with Projection

Lets check Google Maps documentation for example source [Google Maps JavaScript API v3 - Projection]

This code there exists

// Note: this value is exact as the map projects a full
// 360 degrees of longitude.
var GALL_PETERS_RANGE_X = 800;

// Note: this value is inexact as the map is cut off at ~ +/- 83 degrees.
// However, the polar regions produce very little increase in Y range, so
// we will use the tile size.
var GALL_PETERS_RANGE_Y = 510;

function degreesToRadians(deg) {
  return deg * (Math.PI / 180);
}

function radiansToDegrees(rad) {
  return rad / (Math.PI / 180);
}

function GallPetersProjection() {

  // Using the base map tile, denote the lat/lon of the equatorial origin.
  this.worldOrigin_ = new google.maps.Point(GALL_PETERS_RANGE_X * 400 / 800,
      GALL_PETERS_RANGE_Y / 2);

  // This projection has equidistant meridians, so each longitude
  // degree is a linear mapping.
  this.worldCoordinatePerLonDegree_ = GALL_PETERS_RANGE_X / 360;

  // This constant merely reflects that latitudes
  // vary from +90 to -90 degrees.
  this.worldCoordinateLatRange = GALL_PETERS_RANGE_Y / 2;
};

GallPetersProjection.prototype.fromLatLngToPoint = function(latLng) {

  var origin = this.worldOrigin_;
  var x = origin.x + this.worldCoordinatePerLonDegree_ * latLng.lng();

  // Note that latitude is measured from the world coordinate origin
  // at the top left of the map.
  var latRadians = degreesToRadians(latLng.lat());
  var y = origin.y - this.worldCoordinateLatRange * Math.sin(latRadians);

  return new google.maps.Point(x, y);
};

GallPetersProjection.prototype.fromPointToLatLng = function(point, noWrap) {

  var y = point.y;
  var x = point.x;

  if (y < 0) {
    y = 0;
  }
  if (y >= GALL_PETERS_RANGE_Y) {
    y = GALL_PETERS_RANGE_Y;
  }

  var origin = this.worldOrigin_;
  var lng = (x - origin.x) / this.worldCoordinatePerLonDegree_;
  var latRadians = Math.asin((origin.y - y) / this.worldCoordinateLatRange);
  var lat = radiansToDegrees(latRadians);
  return new google.maps.LatLng(lat, lng, noWrap);
};

function initialize() {
  var gallPetersMap;

  var gallPetersMapType = new google.maps.ImageMapType({
    getTileUrl: function(coord, zoom) {
      var numTiles = 1 << zoom;

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

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

      // For simplicity, we use a tileset consisting of 1 tile at zoom level 0
      // and 4 tiles at zoom level 1.
      var baseURL = 'images/';
      baseURL += 'gall-peters_' + zoom + '_' + x + '_' + coord.y + '.png';
      return baseURL;
    },
    tileSize: new google.maps.Size(800, 512),
    minZoom: 0,
    maxZoom: 1,
    name: 'Gall-Peters'
  });

  gallPetersMapType.projection = new GallPetersProjection();

  var mapOptions = {
    zoom: 0,
    center: new google.maps.LatLng(0,0)
  };
  gallPetersMap = new google.maps.Map(document.getElementById("gallPetersMap"),
      mapOptions);

  gallPetersMap.mapTypes.set('gallPetersMap', gallPetersMapType);
  gallPetersMap.setMapTypeId('gallPetersMap');
  gallPetersMap.overlayMapTypes.insertAt(0, gallPetersMapType);
}

Go to Map Types tab of component

Create new Map Type

As you can see later, we doesn't change any lines, just only copy-paste blocks from this example.

As for our type will be like example create with that parameters

In body of script you can find new google.maps.ImageMapType from what I get it:

Title Gall-Peters
Description Gall-Peters Projection
Min Zoom 0
Max Zoom 1
is PNG Yes
Tile Width 800
Tile Height 512
Get Tile URL function
function(coord, zoom) {
      var numTiles = 1 << zoom;

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

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

      // For simplicity, we use a tileset consisting of 1 tile at zoom level 0
      // and 4 tiles at zoom level 1.
      var baseURL = 'http://code.google.com/intl/en/apis/maps/documentation/javascript/examples/images/';
      baseURL += 'gall-peters_' + zoom + '_' + x + '_' + coord.y + '.png';
      return baseURL;
    }


I've only change to absolute URL address to images
var baseURL = 'http://code.google.com/intl/en/apis/maps/documentation/javascript/examples/images/';


The others values

Opacity 1
Layer Type Map
Published Yes


And now we are ready to add Projection

Global scope - it is all variables and additional functions Value for this field


// Note: this value is exact as the map projects a full
// 360 degrees of longitude.
var GALL_PETERS_RANGE_X = 800;

// Note: this value is inexact as the map is cut off at ~ +/- 83 degrees.
// However, the polar regions produce very little increase in Y range, so
// we will use the tile size.
var GALL_PETERS_RANGE_Y = 510;

function degreesToRadians(deg) {
  return deg * (Math.PI / 180);
}

function radiansToDegrees(rad) {
  return rad / (Math.PI / 180);
}


Projection scope Value for this field


  // Using the base map tile, denote the lat/lon of the equatorial origin.
  this.worldOrigin_ = new google.maps.Point(GALL_PETERS_RANGE_X * 400 / 800,
      GALL_PETERS_RANGE_Y / 2);

  // This projection has equidistant meridians, so each longitude
  // degree is a linear mapping.
  this.worldCoordinatePerLonDegree_ = GALL_PETERS_RANGE_X / 360;

  // This constant merely reflects that latitudes
  // vary from +90 to -90 degrees.
  this.worldCoordinateLatRange = GALL_PETERS_RANGE_Y / 2;


The Projection.fromLatLngToPoint() method this is function to implement fromLatLngToPoint method for Projection Value for this field


function(latLng) {

  var origin = this.worldOrigin_;
  var x = origin.x + this.worldCoordinatePerLonDegree_ * latLng.lng();

  // Note that latitude is measured from the world coordinate origin
  // at the top left of the map.
  var latRadians = degreesToRadians(latLng.lat());
  var y = origin.y - this.worldCoordinateLatRange * Math.sin(latRadians);

  return new google.maps.Point(x, y);
}


The Projection.fromPointToLatLng() method this is function to implement fromPointToLatLng method for Projection Value for this field


function(point, noWrap) {

  var y = point.y;
  var x = point.x;

  if (y < 0) {
    y = 0;
  }
  if (y >= GALL_PETERS_RANGE_Y) {
    y = GALL_PETERS_RANGE_Y;
  }

  var origin = this.worldOrigin_;
  var lng = (x - origin.x) / this.worldCoordinatePerLonDegree_;
  var latRadians = Math.asin((origin.y - y) / this.worldCoordinateLatRange);
  var lat = radiansToDegrees(latRadians);
  return new google.maps.LatLng(lat, lng, noWrap);
}


Thats all. Now go to map details, enable custom map types and add your map type ID into list of custom map types, which enabled for your map.

How add Custom Map Type as a Predefined Map in component

If you want to add Custom Map Type as a Predefined Map in component, and not only you but the other people can use this type of map type (which enabled in Map Type list in Map Details or by plugin overriding map) you should do some steps:

  • contact with me (post to wishlist, for example, and fill in post form your real email), and I'll mail you to work by mail
  • and by mail you should:
    • provide Custom Map Type definition and proof link, from where you've get getTileUrl function (and Projection if needed)
    • is there no restriction to get Tiles from Map Tiles Owner (license)
    • is there site or email to my contact with owner to ask permission to use tiles and what credits should be included in extensions to show in map (documentation)
  • when I receive permission (if exists) to use its tiles - I'll include into component and plugin this map type
  • in any case, if I include this map type into predefined, and somebody of map owner contact to me about restriction - I have to remove it :), or notify by change access rules for this map type