2017-02-05 9 views
-1

Теперь на странице google.com/maps, когда я нажимаю на имя/метку страны или города, эта область подсвечивается и открывает окно с всплывающим окном.Ярлыки с метками в Google Map API

Можно ли реализовать то же самое с API Карт Google? Чтобы выделить ярлык над мышью, выделите границы страны, штата или города по щелчку и, чтобы выбрать по метке/имени пользователя в js.

Я просмотрел документацию API Google Maps API, но аналогичная функциональность не найдена.

Спасибо!


Извините за неточный вопрос.

Можно ли установить клики по названию страны/города на карте с помощью API, например, на странице google.com/maps?

+1

уверен, что это возможно, но вам нужен источник данных для границ – charlietfl

+0

Upvoted, как без комментариев для downvoting – Datadimension

+0

@DataMechanics голосования анонимно по дизайну здесь – charlietfl

ответ

0

Рекомендовать класс GMap 'barebones'. Как это происходит, я просто повторно посетить это сам так попробуйте этот код (возможно, потребуются некоторые изменения)

/** 
* 'GMap' 
* extends googlemaps to allow simpler coding in other apps, should be loaded after the main google maps 
* a new instance of a google map is contructed calling this with identical arguments to the standard class and then returned 
* the map name must be unique and reserved as a global by the client code, eg var pagemap outside of function, so the external callbacks 
* can use this name to run a function against, eg pagemap.queryMove_do 
* 
*/ 

function GMap(mapId, options) { 
    this.name = null; 
    this.map = null; 
    this.bounds = null; //view point boundary 
    this.gui_reg; 
    this.mapoptions; 
    this.calledbackonload; 
    this.polygons = {}; 
    this.lngoffset = {'direction': '', referenceelem: ''}; 
    this.infowindows = {}; 
    this.infowindowindex = 0; 
    GMap.prototype.__construct = function (mapId, options) { 
    var mapbuffer = new Data_buffer(); //this has to be vague as 3rd party api data is not always the same format, simply return data to the logged map interface objects 

    if (typeof window.MAP_INTERFACE_CTRL === 'undefined') {//if not created, global constant to co-ordinate ajax requests with map objects and 3rd party API, and allow funneling back to local objects 
     window.MAP_INTERFACE_CTRL = new Data_buffer(); //this has to be vague as 3rd party api data is not always the same format, simply return data to the logged map interface objects 
    } 
    options.panControlOptions = model.array_defaults(
      options.ctrlcfg, 
      { 
       position: google.maps.ControlPosition.RIGHT_BOTTOM 
      } 
    ); 
    options.zoomControlOptions = model.array_defaults(
      options.ctrlcfg, 
      { 
       position: google.maps.ControlPosition.RIGHT_CENTER 
      } 
    ); 
    this.mapoptions = model.array_defaults(
      options, 
      { 
       center: new google.maps.LatLng(54.5, -7), 
       zoom: 6, 
       minzoom: 15, 
       maxzoom: 21 
      } 
    ); 
    this.gui_reg = {location: {address: new Array()}}; 
    this.name = mapId; 
    this.map = new google.maps.Map(document.getElementById(mapId), this.mapoptions); 
    var selfobj = this; 
    google.maps.event.addListener(//processes client registration for registered events 
      this.map, 
      'dragend', //center changed causes too many requests 
      function() { 
       selfobj.update_client_go("location"); 
      } 
    ); 
//create invisible scratchpad 
    if ($('#map_pool').length == 0) { 
     $('body').append("<div id='map_pool'></div>"); 
     $('#map_pool').hide(); 
    } 
    /* 
    callback_obj = this; 
    google.maps.event.addListener(this.map, 'tilesloaded', function(evt) { 
    callback_obj.map.setZoom(9); 
    });*/ 
    } 

    /*****************************************************************/ 
    /* METHODS FOR BOTH GMAP AND CLIENT */ 
    /*****************************************************************/ 

    /* 
    * defines offset of mapcentre away from an element such as custom controls 
    * which overlay a large amount of map 
    * positive or negative according to offset direction where the element might be on the 
    * left or the right 
    */ 
    GMap.prototype.set_lng_offset = function (elemid, dir) { 
    var direction = 'right'; 
    if (dir == 'left') { 
     direction = dir; 
    } 
    this.lngoffset = {direction: direction, referenceelem: elemid}; 
    } 

    /* 
    * returns lng offset according to definitions and current map situation 
    */ 
    GMap.prototype.calc_lng_offset = function() { 
//get lng width of map 
    var eastlng = this.map.getBounds().getNorthEast().lng(); 
    var westlng = this.map.getBounds().getSouthWest().lng(); 
    var lngspan; 
    if (westlng <= 0 && eastlng >= 0) { 
     lngspan = Math.abs(westlng) + eastlng; 
    } else if (westlng >= 0 && eastlng <= 0) { 
     lngspan = (180 - westlng) + (180 - Math.abs(eastlng)); 
    } else if (westlng < 0 && eastlng < 0) { 
     lngspan = Math.abs(eastlng) + westlng; 
    } else { 
     lngspan = eastlng - westlng; 
    } 

//get px width of map and referenced element 
    var mapwidth = $("#" + this.name).width(); 
    var offsetpx = $("#" + this.lngoffset.referenceelem).width(); 
    //convert this px to lng offset for map by multiplying by lngpx 
    var lngperpx = lngspan/mapwidth; //calc lng/px as lngpx 
    //calc the offset lng 
    var offsetlng = offsetpx * lngperpx; 
    if (this.lngoffset.direction == 'left') { 
     var offsetlng = 0 - offsetlng; 
    } 
    return offsetlng; 
    } 

    /* 
    * returns an object with north south east west and centre coordinates of the current view 
    * args.precision states number of figures after decimal returned - if not give a full result is returned. 
    * @returns {float north,float east,float south,float west,float lat,float lng} 
    */ 
    GMap.prototype.get_viewport_coords = function (args) { 
    if (args == undefined) { 
     args = {}; 
    } 
    var coords = {}; 
    coords.north = this.map.getBounds().getNorthEast().lat(); 
    coords.east = this.map.getBounds().getNorthEast().lng(); 
    coords.south = this.map.getBounds().getSouthWest().lat(); 
    coords.west = this.map.getBounds().getSouthWest().lng(); 
    coords.lat = this.map.getCenter().lat(); 
    coords.lng = this.map.getCenter().lng(); 
    if (args.precision != undefined) { 
     coords.north = coords.north.toFixed(args.precision); 
     coords.east = coords.east.toFixed(args.precision); 
     coords.south = coords.south.toFixed(args.precision); 
     coords.west = coords.west.toFixed(args.precision); 
    } 
    return coords; 
    } 

    /* 
    * 'map_query' 
    * takes a text query and queries to google for info 
    * 
    * required due to APIs not being the same, a uuid is registered globally and a global process used to redirect 
    * because of this the global process must identify a map object by UUID and only expect a single argument as an object literal (JSON) 
    * this is then passed back to the object that initiated the ajax or UUID request 
    * 
    * @param OBJECT query_cfg to send to gmap geocode 
    *  @param string query_cfg.type states what type of query and what action to take, allowing multiple use for this method 
    *  @param string query_cfg.query_data a string containing address data such as '<postcode>, <street>, <property>' 
    *  @param string query_cfg.callback to return the data to 
    */ 
    GMap.prototype.geo_query = function (query_cfg) { 

//package pre query data and set defaults if not set 
    query_cfg = model.array_defaults(
      query_cfg, 
      { 
       clientid: this.name, 
       callback: 'update_client_do'//client code can set its own callback,else set callback to this 
      } 

    ); 
    var geo_queryid = MAP_INTERFACE_CTRL.callback_push(query_cfg); 
    switch (query_cfg.type) { 
     case "location"://returns location data at given lat lng coords 
     var gcoder = new google.maps.Geocoder(); 
     gcoder.geocode({'location': {lat: query_cfg.lat, lng: query_cfg.lng}}, function (results, status) { 
      var server_response = {results: results, status: status}; 
      eval("MAP_INTERFACE_CTRL.callback_pop('" + geo_queryid + "',server_response)"); 
     }); 
     break; 
     case "address_latlng": 
     var gcoder = new google.maps.Geocoder(); 
     gcoder.geocode({'address': query_cfg.query_data}, function (results, status) { 
      var server_response = {results: results, status: status}; 
      eval("MAP_INTERFACE_CTRL.callback_pop('" + geo_queryid + "',server_response)"); 
     }); 
     break; 
     case "sv_pano_latlng"://gets streetview pano for given lat lng 
     var sv_service = new google.maps.StreetViewService(); 
     sv_service.getPanoramaByLocation(query_cfg.latlng, query_cfg.radius, function (results, status) { 
      var server_response = {results: results, status: status}; 
      eval("MAP_INTERFACE_CTRL.callback_pop('" + geo_queryid + "',server_response)"); 
     }); 
     break; 
     case "viewport_range"://returns lat lng for viewport and centre to callback 
     var gcoder = new google.maps.Geocoder(); 
     var bounds = this.bounds; 
     var center = this.map.getCenter(); 
     gcoder.geocode({address: change_request}, function (results, status) { 
      callback_obj.viewport_range_do(results, status) 
     }); 
     break; 
    } 
    } 

    /* 
    * 'formatted_geo_result' 
    * interprets geocoded results to a standard uniform independent of map api 
    * @param OBJECT geo_result data returned (in this map interface from google) 
    */ 
    GMap.prototype.formatted_geo_result = function (geodata) { 
    var formatted = {}; 
    var itemdefaults = { 
     address: '', 
     lat: null, 
     lng: null 
    } 
    for (var i in geodata.results) { 
     var item = { 
     address: geodata.results[i].formatted_address, 
     lat: geodata.results[i].geometry.location.lat(), 
     lng: geodata.results[i].geometry.location.lng(), 
     } 
     formatted[i] = model.array_defaults(item, itemdefaults); 
    } 
    return formatted; 
    } 
    /* 
    * 'map_change' 
    * takes a request and processes and changes map accordingly 
    * 
    * callerobj is optional, if not given then callback will be back to this map object 
    * if a callerobj is given this must be to an object which can accept it 
    * (if callerobj is a top level function it needs to pass the object as keyword window - not 'window') 
    * The callback method is named as query type with _do appended eg address_move_do 
    * Some query types require the caller object to handle the query and DO NOT have a method defined in the map object 
    * If this map object DOES have the callback but a callback_obj is given then it will override this map object 
    * 
    * @param string change_request free text to send to gmap object 
    * @param string change_type states what type of query and what action to take, allowing multiple use for this method 
    * @param string callback function to run on change completion. 
    */ 
    GMap.prototype.map_change = function (change_type, change_data, callback) { 
    switch (change_type) { 
     case "lat_lng": 
     this.map.panTo({lat: change_data.latlng.lat, lng: change_data.latlng.lng + this.calc_lng_offset()}); 
     break; 
     case "address"://to address_latlng as translation for this map object 
     this.geo_query({type: "address_latlng", clientid: this.name, callback: "map_change_do", change_type: change_type, query_data: change_data}); 
     break; 
    } 
    if (callback != undefined) { 
     this.loadedCallback(callback); 
    } 
    } 

    /* 
    * 'map_change_do' 
    * processes any ajax return required by map_change 
    * 
    * @param string change_request free text to send to gmap object 
    * @param string change_type states what type of query and what action to take, allowing multiple use for this method 
    */ 
    GMap.prototype.map_change_do = function (pre_data, callback_data) { 
    switch (pre_data.change_type) { 
     case "address": 
     this.map_change("lat_lng", {latlng: {lat: callback_data.results[0].geometry.location.lat(), lng: callback_data.results[0].geometry.location.lng()}}); //callback_data.results[0].geometry.location.lat() 
     break; 
    } 
    } 

    /* 
    * permanently deletes all objects such as map markers (pins) etc 
    */ 
    GMap.prototype.clearmapobjects = function() { 
    this.map.clearMarkers(); 
    } 

    GMap.prototype.panotestA = function() { 
    var locquery = "framlingham tech centre"; 
    this.map_change("address", locquery); 
    this.map.setZoom(20); 
    this.geo_query("location", locquery) 
    this.geo_query({type: "address_latlng", clientid: this.name, callback: "panotestB", query_data: locquery}); 
    } 
    GMap.prototype.panotestB = function (pre_data, callback_data) { 
    var pin = this.add_pin(callback_data.results[0].geometry.location.lat(), callback_data.results[0].geometry.location.lng(), {infopop: {content: 'hello', streetview: true}}); 
    } 
    /* 
    * 'add_pin' 
    * adds a pin to a map 
    * 
    * @param float lat is latitude position 
    * @param float lng is longitude position 
    * @param object info_args other pin constructs such as the info displayed while clicking it 
    * @return object marker 
    */ 
    GMap.prototype.add_pin = function (lat, lng, info_args) { 
    info_args = model.array_defaults(
      info_args, 
      { 
       width: 16, 
       height: 16, 
       animation: google.maps.Animation.DROP, 
       icon: { 
       url: "http://" + ROOTUC + "//css/images/icons/ROYOdot_a.gif" 
       }, 
       infopop: null 
      } 
    ); 
    /* 
    var icon = { 
    url: info_args.icon.url, 
    size: new google.maps.Size(20, 20), 
    origin: new google.maps.Point(0, 0), 
    anchor: new google.maps.Point(0, 0) 
    }; 
    */ 
    var iconImage = new google.maps.MarkerImage(
      info_args.icon.url, // url to image inc http:// 
      null, // desired size 
      null, // offset within the scaled sprite 
      null, // anchor point is half of the desired size 
      new google.maps.Size(info_args.width, info_args.height) // required size 
      ); 
    var pin = new google.maps.Marker({ 
     position: new google.maps.LatLng(lat, lng), 
     map: this.map, 
     title: info_args.label, 
     icon: iconImage, 
     optimized: false, //to allow for animations 
     animation: info_args.animation, 
    }); 

    if (info_args.infopop != null) { 
     /*content is forced into div with black font as google default 
     * is white text on white background ?!?!?! 
     */ 

     info_args.infopop = model.array_defaults(
       info_args.infopop, 
       { 
       fontcolor: '#000000', 
       infowidth: '40em', 
       streetview: false 
       }); 
     //standard google defs 
     var infowindow = new google.maps.InfoWindow(); 
     //extra seperate data ref for client apps 
     infowindow.metadata = { 
     parent: this, 
     parentid: this.infowindowindex, 
     }; 
     this.infowindows[this.infowindowindex] = { 
     infowidth: info_args.infopop.infowidth, 
     content: info_args.infopop.content, 
     fontcolor: info_args.infopop.fontcolor, 
     latlng: {lat: lat, lng: lng}, 
     streetview: info_args.infopop.streetview 
     }; 
     this.infowindowindex++; 

     //build for pin click 
     google.maps.event.addListener(pin, 'click', function() { 
     var infodata = infowindow.metadata.parent.infowindows[infowindow.metadata.parentid]; 

     //build content 
     var infocontent = "<div id='" + infowindow.metadata.parent.name + "infowindow" + (infowindow.metadata.parentid) + "' style='color:" + infodata.fontcolor + ";width:" + infodata.infowidth + "'>"; 
     infocontent += infodata.content; 
     if (infodata.streetview) { 
      infocontent += "<div id='" + infowindow.metadata.parent.name + "infowindowsvframe" + (infowindow.metadata.parentid) + "' class='infostreetviewframe' >"; 
      infocontent += ". . . loading view</div>"; 
     } 
     infocontent += "</div>"; 
     infowindow.setContent(infocontent); 
     infowindow.open(this.map, pin); 
     if (infodata.streetview) { 
      var service = new google.maps.StreetViewService(); 
      infowindow.metadata.parent.geo_query({type: "sv_pano_latlng", latlng: infodata.latlng, radius: 50, clientid: infowindow.metadata.parent.name, streetviewframe: infowindow.metadata.parent.name + "infowindowsvframe" + (infowindow.metadata.parentid), callback: "add_streetview_do"}); 
     } 
     }); 
    } 
    } 

    /* 
    * 'add_streetview' 
    * for flexibility addition of a streetview into a named dom element id 
    * 
    * @param object args 
    *  @param.args string elemid the element to put the streetview into 
    * 
    */ 
    GMap.prototype.add_streetview_do = function (predata, callbackdata) { 
    var svelement = document.getElementById(predata.streetviewframe); 
    if (callbackdata.status == google.maps.StreetViewStatus.OK) { 
     var targetPOVlocation = predata.latlng 
     var svLatLng = {lat: callbackdata.results.location.latLng.lat(), lng: callbackdata.results.location.latLng.lng()}; 

     // var svLatLng = new google.maps.LatLng(callbackdata.results.location.latLng.lat(), callbackdata.results.location.latLng.lng()); 

     //var svLatLng = callbackdata.results.location.latLng; 

     var povyaw = this.getBearing(svLatLng, targetPOVlocation); 
     var sv = new google.maps.StreetViewPanorama(svelement); 
     var svoptions = { 
     position: svLatLng, 
     addressControl: false, 
     linksControl: false, 
     panControl: false, 
     zoomControlOptions: { 
      style: google.maps.ZoomControlStyle.SMALL 
     }, 
     pov: { 
      heading: povyaw, 
      pitch: 10, 
      zoom: 1 
     }, 
     enableCloseButton: false, 
     visible: true 
     }; 
     sv.setOptions(svoptions); 
    } else { 
     svelement.innerHTML = "no streetview available"; 
    } 
    } 

    /* 
    * 'getBearing' 
    * calcs bearing from two latlngs 
    * 
    */ 
    GMap.prototype.getBearing = function (fromLatLng, targetLatLng) { 
    var DEGREE_PER_RADIAN = 57.2957795; 
    var RADIAN_PER_DEGREE = 0.017453; 

    var dlat = targetLatLng.lat - fromLatLng.lat; 
    var dlng = targetLatLng.lng - fromLatLng.lng; 
    // We multiply dlng with cos(endLat), since the two points are very closeby, 
    // so we assume their cos values are approximately equal. 
    var bearing = Math.atan2(dlng * Math.cos(fromLatLng.lat * RADIAN_PER_DEGREE), dlat) 
      * DEGREE_PER_RADIAN; 

    if (bearing >= 360) { 
     bearing -= 360; 
    } else if (bearing < 0) { 
     bearing += 360; 
    } 
    return bearing; 
    } 

    /* 
    * 'add_polygon' 
    * adds a polygon to a map using an array of lat lng coords 
    * these are pushed in the order they appear in the locationarray 
    * 
    * @param array locationarray - which event/change type triggers update of this element 
    * 
    */ 
    GMap.prototype.add_polygon = function (args) { 

//construct and store polygon 
    var polyobj = model.array_defaults(args, {name: "polygon", polygon: null, infohtml: null, box: null, focuson: false}); 
    //remove any same named polygon 
    if (this.polygons[args.name] != undefined) { 
     this.polygons[args.name].polygon.setMap(null); 
     this.polygons[args.name] = null; 
    } 


    var newpolygon = new Array(); 
    polyobj.box = new google.maps.LatLngBounds(); 
    for (var l in args.polygon) { 
     var point = new google.maps.LatLng(args.polygon[l].lat, args.polygon[l].lng); 
     newpolygon.push(point); 
     polyobj.box.extend(point); 
    } 
    polyobj.polygon = new google.maps.Polygon(
      { 
       map: this.map, 
       paths: newpolygon, 
       strokeColor: '#00ff00', 
       strokeOpacity: 0.75, 
       strokeWeight: 2, 
       fillColor: '#00ff00', 
       fillOpacity: 0.15 
      } 
    ); 
    this.polygons[args.name] = polyobj; 
    //set required changes to map 
    if (args.infohtml != null) { 
// content is forced into div with black font as google default is white text on white background ?!?!?! 
     polyobj.info = new google.maps.InfoWindow(
       { 
       content: "<div style='color:#000000'>" + args.infohtml + "</div>" 
       }); 
     var selfobj = this; 
     google.maps.event.addListener(this.polygons[args.name].polygon, 'click', function (event) { 
     var point = event.latLng; 
     selfobj.polygons[args.name].info.setPosition(point); 
     selfobj.polygons[args.name].info.open(selfobj.map); 
     }); 
    } 

    if (polyobj.focuson) { 
     this.map.fitBounds(polyobj.box); 
    } 
    } 


    /*****************************************************************/ 
    /* methods for CLIENT --> GMAP change */ 
    /*********************************************************S ********/ 

    /* 
    * allows gui to register elements so when changes/events occur in the map gui, its 
    * parent gui can be updated. 
    * @param string change_type - which event/change type triggers update of this element 
    * @param string change_return - data required to be returned eg latlng or address etc 
    * @param string callback - the page element identifier to update 
    */ 
    GMap.prototype.register_elem = function (change_type, event_return_cfg) { 
    switch (change_type) { 
     case "location": 
     switch (event_return_cfg.return_type) { 
      case "address": 
      this.gui_reg.location.address.push(event_return_cfg); 
      break; 
     } 
     break; 
    } 
    } 

    /*****************************************************************/ 
    /* methods for GMAP --> CLIENT change */ 
    /*****************************************************************/ 

    /* 
    * checks registered change type to send back to client 
    * @param string change_type - which event/change type triggers update of this element 
    * @param string data_request - data required to be returned 
    * @param string regelem - the parent gui identifier to update5 
    * @param object attr - which attribute to update eg for input, its value, for div its html 
    */ 
    GMap.prototype.update_client_go = function (change_type, data_request) { 
    switch (change_type) { 
     case "location": 
     var loc = this.get_viewport_coords(); 
     this.geo_query({type: "location", lat: loc.lat, lng: loc.lng}); 
    } 
    } 

    /* 
    * actions client_update 
    * @param string change_type - which event/change type triggers update of this element 
    * @param string data_request - data required to be returned 
    * @param string regelem - the parent gui identifier to update5 
    * @param object attr - which attribute to update eg for input, its value, for div its html 
    */ 
    GMap.prototype.update_client_do = function (pre_data, callback_data) { 
    if (callback_data.status != "ZERO_RESULTS") { 
     switch (pre_data.type) { 
     case "location": 
      var location_data_registrars = this.gui_reg.location; 
      for (var loc_type_list in location_data_registrars) { 
      switch (loc_type_list) { 
       case "address": 
       var address = callback_data.results[0].formatted_address; 
       for (var r in location_data_registrars[loc_type_list]) { 
        var event_return = location_data_registrars[loc_type_list][r]; 
        if (event_return != undefined) { 
        event_return.address = this.address_parse("postcode", address); 
        if (event_return.callback != undefined) { 
         eval(event_return.callback + "(event_return)"); 
        } 
        } 
       } 
       break; 
      } 
      } 
      break; 
     } 
    } 
    } 

    /*****************************************************************/ 
    /* PRIVATE METHODS */ 
    /*****************************************************************/ 
    GMap.prototype.address_parse = function (required_part, address) { 
    var result = ""; 
    address = address.split(", "); 
    var country = address[address.length - 1]; 
    switch (country) { 
     case "UK": 
     switch (required_part) { 
      case "postcode": 
      result = address[address.length - 2]; 
      result = result.substr(result.indexOf(" ") + 1); 
      break; 
     } 
     break; 
    } 
    return result; 
    } 

    GMap.prototype.loadedCallback = function (callback) { 
    this.calledbackonload = false; 
    google.maps.event.addListenerOnce(this.map, 'tilesloaded', function() { 
     google.maps.event.clearListeners(this.map, 'idle'); 
     eval(callback + '()'); 
    }); 
    google.maps.event.addListenerOnce(this.map, 'idle', function() { 
     eval(callback + '()'); //add idle as a catch all 
    }); 
    /* 
    google.maps.event.addListenerOnce(this.map, 'idle', function() { 
    eval(callback + '()') 
    }); 
    */ 
    } 

    /* 
    * zooms map to next level from current depending on dir being '+' or '-' 
    */ 
    GMap.prototype.incrementZoom = function (dir, callback) { 
    var newZoom = this.map.getZoom(); 
    if (dir == '+') { 
     newZoom++; 
    } 
    if (dir == '-') { 
     newZoom--; 
    } 
    this.map.setZoom(newZoom); 
    if (callback != undefined) { 
     this.loadedCallback(callback); 
    } 
    } 

    /* 
    * zooms map to fully zoomed in 
    */ 
    GMap.prototype.zoomMax = function (callback) { 
    this.map.setZoom(this.mapoptions.maxzoom); 
    if (callback != undefined) { 
     this.loadedCallback(callback); 
    } 
    } 

    /* 
    * zooms map to fully zoomed out 
    */ 
    GMap.prototype.zoomMin = function (callback) { 
    this.map.setZoom(this.mapoptions.minzoom); 
    if (callback != undefined) { 
     this.loadedCallback(callback); 
    } 
    } 

    /* 
    * zooms map to contain the given box as per gmaps southwest/northeast corner specs 
    */ 
    GMap.prototype.boxZoom = function (latfrom, latto, lngfrom, lngto) { 
    var bottomleft = {lat: latfrom, lng: lngfrom}; 
    var topright = {lat: latto, lng: lngto}; 
    var box = new google.maps.LatLngBounds(bottomleft, topright); 
    this.map.fitBounds(box); 
    } 

    /* 
    * forces zoom in to min max params and returns true if it has been constrained 
    * additional callback if required for when zoom to constraints has finished 
    */ 
    GMap.prototype.constrainzoom = function (callback) { 
    if (this.map.getZoom() > this.mapoptions.maxzoom) { 
     this.map.setZoom(this.mapoptions.maxzoom); 
    } else if (this.map.getZoom() < this.mapoptions.minzoom) { 
     this.map.setZoom(this.mapoptions.minzoom); 
    } else { 
     return false; 
    } 
    if (callback != undefined) { 
     this.loadedCallback(callback); 
    } 
    return true; 
    } 

    /*add extras to generic map object*/ 
    google.maps.Map.prototype.clearMarkers = function() { 
    for (var i = 0; i < this.markers.length; i++) { 
     this.markers[i].setMap(null); 
    } 
    this.markers = new Array(); 
    }; 
    /* 
    * places an existing div by id as a map control 
    */ 
    GMap.prototype.addcontrol = function (divid, posn) { 
    if (posn == undefined) { 
     posn = google.maps.ControlPosition.TOP_LEFT; 
    } 
    this.map.controls[posn].push(document.getElementById(divid)); 
    } 
    /* translate normal functions to internal map object */ 
    /* trigger setup */ 
    this.__construct(mapId, options); 
}