Introduction
Do you need to store latitude/longitude coordinates of an address, or show a little input to choose a point in Google Maps? Here is a little solution to this problem: extend the TextBox
to interact with Google Maps!
Background
To create this simple control, you need only to know a little of C#, the MooTools JavaScript framework, and have a Google Maps key.
Using the Code
We will start with the code. First of all, you need to create an empty ASCX file with this sample code:
<%@Control Language="C#" AutoEventWireup="false" src="gmapinput.cs" %>
Then, create a new C# class file that extends a normal textbox (System.Web.UI.WebControls.TextBox
):
[DefaultProperty("Text")]
[ToolboxData("<{0}:Input runat=server></{0}:Input>")]
public class GoogleMapInput : TextBox
{
...
}
Above all, we need a basic property (the Google Maps key); in this case, I presume that there is a web.config setting with this value and with this name: googleMapsKey
.
public string GoogleMapKey
{
get
{
object o = ViewState["GoogleMapKey"];
if (o == null) {
if(System.Configuration.ConfigurationSettings.
AppSettings["googleMapsKey"]!=null)
return System.Configuration.ConfigurationSettings.
AppSettings["googleMapsKey"];
else
return string.Empty;
}else return o.ToString();
}
Set { ViewState["GoogleMapKey"] = value; }
}
Now, we need to check some features:
- Check for (and if not included) Mootools.js
- Include the specific JavaScript code (the
mootools
class) to create the gmap input - Include the specific CSS stylesheet
System.Web.UI.HtmlControls.HtmlHead myhead = this.Page.Header;
string embedobjecturl =
"/template/plugins/GoogleMapInput/GoogleMapInput.js";
string cssembedobjecturl =
"/template/plugins/GoogleMapInput/GoogleMapInput.css";
for (int i = 0; i < myhead.Controls.Count; i++)
{
if (((LiteralControl)myhead.Controls[i]).Text.
ToLower().IndexOf("mootools-1.2-core.js") == -1) {
}
if (((LiteralControl)myhead.Controls[i]).Text.
ToLower().IndexOf("mootools-1.2-more.js") == -1) {
}
Now, we need to override the render properties to write our textbox:
protected override void Render(HtmlTextWriter writer)
{
string thisContainer = this.ClientID + "CC";
string valore = this.Text;
string lat = "";
string log = "";
if (!string.IsNullOrEmpty(valore) && valore.Trim() != "")
{
if (valore.IndexOf(',') != -1) {
lat = valore.Trim().Substring(0, valore.IndexOf(','));
log = valore.Trim().Substring(valore.IndexOf(',') + 1);
}
}
writer.Write("<div id=\""+thisContainer+"\" >");
writer.Write("<div class=\"ginputarea\">");
writer.Write("<fieldset>");
writer.Write("<legend>Località</legend>");
writer.Write("<label for=\""+thisContainer+
"_inputAdd\">Località</label>");
writer.Write("<input type=\"text\" id=\""+
thisContainer+"_inputAdd\" /> ");
writer.Write("<input type=\"button\" id=\""+
thisContainer+"_btmAdd\" " +
"value=\"update\" class=\"btmgupd\" />");
writer.Write("</fieldset>");
writer.Write("<fieldset class=\"latlong\">");
writer.Write("<legend>Coordinate</legend>");
writer.Write("<label for=\""+thisContainer+
"_inputLA\">Lat.</label>");
writer.Write("<input type=\"text\" id=\""+
thisContainer+"_inputLA\" /> ");
writer.Write("<label for=\""+thisContainer+
"_inputLO\">Long.</label>");
writer.Write("<input type=\"text\" id=\""+
thisContainer+"_inputLO\" /> ");
writer.Write("<input type=\"button\" id=\""+thisContainer+
"_btmLL\" value=\"update\" " +
"class=\"btmgupd\" /> ");
writer.Write("</fieldset>");
writer.Write("</div>");
writer.Write("<div class=\"gmaparea\">");
writer.Write("<div id=\"" + thisContainer +
"_maps\" style=\"width:240px; height:135px;" +
" border:1px solid #333; \">");
writer.Write("</div>");
writer.Write("</div>");
writer.Write("<input type=\"hidden\" value=\"" + this.Text +
"\" id=\"" + this.ClientID +
"\" name=\"" + this.UniqueID + "\" />");
writer.Write("</div>");
string gK = this.GoogleMapKey;
string lato = "";
if (lat.Trim() != "" && log.Trim() != "") {
lato = ",latitude:'" + lat +
"',longitude:'" + log + "'";
}
writer.Write("<script language=\"javascript\" defer=\"defer\">\n");
writer.Write("var " + this.ID + "imoEl =
new GoogleMapsObj('','','',{panelID:'" +
thisContainer + "', " +
this.ClientID + "'" + lato + "}); \n");
writer.Write("function mappa(puntoL,puntoG) {\n");
writer.Write("" + this.ID + "imoEl.setLatLong(puntoL,puntoG);\n");
writer.Write("}\n");
writer.Write("</script>\n");
}
And at the end, we speak about the mootools
class (presuming that you know the basics of the MooTools syntax, or you can check http://docs.mootools.net):
[Follows the JavaScript code for the mootools
class:]
var GoogleMapsObj = new Class( {
options: {
panelID:'mioEmbeder',
googlekey: '1',
dataID : '',
latitude:'',
longitude:'',
currentURL:''
},
After the options declaration, we need to init the class:
initialize: function(address, lat, long, options) {
this.options.panelID = options.panelID;
this.options.googlekey = options.googlekey;
if(options.dataID)
this.options.dataID = options.dataID;
if(options.latitude)
this.options.latitude = options.latitude;
if(options.longitude)
this.options.longitude = options.longitude;
var inpAdd = $(this.options.panelID+'_inputAdd') ;
var btmAdd = $(this.options.panelID+'_btmAdd') ;
var inpLA = $(this.options.panelID+'_inputLA') ;
var inpLO = $(this.options.panelID+'_inputLO') ;
var btmLL = $(this.options.panelID+'_btmLL') ;
var mappa = $(this.options.panelID+'_maps') ;
if(this.options.latitude!='')
inpLA.value = this.options.latitude;
if(this.options.latitude!='')
inpLO.value = this.options.longitude;
if(address.toString()!='')
inpAdd.value = address;
if(lat.toString()!='')
inpLA.value = lat;
if(long.toString()!='')
inpLO.value = long;
var mioFF = this;
After the set up of all DOM elements and values, we need to assign the events to the buttons:
if( btmAdd ) {
btmAdd.addEvent('click',function(e) {
evt = new Event(e);evt.stop();
var address = $(mioFF.options.panelID+'_inputAdd');
var _lat = '';
if(address) _lat = address.value;
if(_lat=='' ) return;
mioFF.initGMaps(_lat);
});
}
if( btmLL ) {
btmLL.addEvent('click',function(e) {
evt = new Event(e);evt.stop();
var lat = $(mioFF.options.panelID+'_inputLA');
var long = $(mioFF.options.panelID+'_inputLO');
var _lat = '';
var _long = '';
if(lat) _lat = lat.value;
if(long) _long = long.value;
if(_lat=='' || _long=='') return;
var objD = $(mioFF.options.dataID);
if(objD) {
objD.value = _lat + ','+_long;
}
mioFF.initGMaps('');
});
}
This is the more important call; with this function, we init Google Maps with or without the latitude/langitude or address info.
this.initGMaps('');
},
This is the function that inits Google Maps:
initGMaps : function(address) {
var lat = $(this.options.panelID+'_inputLA');
var long = $(this.options.panelID+'_inputLO');
var _lat = '';
var _long = '';
if(lat) _lat = lat.value;
if(long) _long = long.value;
var urlA = '';
if(_lat!='') urlA+='&lt=' + _lat;
if(_long!='') urlA+='&lg=' + _long;
if(address!='') {
urlA+='&ad='+escape(address);
}
if(this.options.currentURL!=urlA) {
this.options.currentURL=urlA;
} else return;
var eCont = $(this.options.panelID+'_maps');
eCont.empty();
eCont.set('html','');
This is my simple solution to show Google Maps: I use an iFrame to show the map, to set the passed URL or lat/lng coordinates (var: urlA
), and to set the Google key:
if(window.ie) {
var iframe = '<iframe src="/template/plugins/GoogleMapInput/testg.aspx?g='+
this.options.googlekey+urlA+
'" frameborder="0" allowtransparency="true"'+
' height="135" width="240" scrolling="no" ></iframe>';
eCont.set('html',iframe);
} else {
var ifrm = new Element('iframe');
ifrm.setProperties({
id :'googleFrame',
name: 'googleFrame',
frameborder:'0',
allowtransparency:'true',
height:'135',
width:'240',
scrolling:'no'
});
ifrm.setProperty('src',
"/template/plugins/GoogleMapInput/testg.aspx?g="+
this.options.googlekey+urlA);
eCont.adopt(ifrm);
}
},
Here is another useful function to retrieve the value from the HTML input:
setLatLong : function(lat,long) {
var _lat = $(this.options.panelID+'_inputLA');
var _long = $(this.options.panelID+'_inputLO');
if(_lat) _lat.value = lat;
if(_long) _long.value = long;
var objD = $(this.options.dataID);
if(objD) {
objD.value = lat + ','+long;
}
}
});
GoogleMapsObj.implement(new Options, new Events);
This is the C# part to read the querystring and to setup the default values:
<%@ Page Language="c#" ContentType="text/html" ResponseEncoding="utf-8" %>
<script language="c#" runat="server">
string googleKey="";
string lat ="";
string logi ="";
string addr ="";
void Page_Load(object o, EventArgs e ) {
if(Request.Params["g"]==null)
googleKey = "";
else
googleKey = Request.Params["g"].ToString();
if(Request.Params["lt"]==null)
lat = "37.4419";
else
lat = Request.Params["lt"].ToString();
if(Request.Params["lg"]==null)
logi = "-122.1419";
else
logi = Request.Params["lg"].ToString();
if(Request.Params["ad"]==null)
addr = "";
else
addr = HttpUtility.UrlDecode(Request.Params["ad"].ToString());
}
</script>
This is the Google Maps JavaScript part:
<script src="http://www.google.com/jsapi?key=<%=googleKey%>"
type="text/javascript"></script>
<script type="text/javascript">
google.load("maps", "2.x");
var map = null;
var geocoder = null;
function load() {
var latitude = <%=lat%>;
var longitude = <%=logi%>;
var address = '<%=addr%>';
if (GBrowserIsCompatible()) {
map = new google.maps.Map2(document.getElementById("map"));
if(!map) return;
map.setCenter(new google.maps.LatLng(latitude, longitude), 13);
var marker = new google.maps.Marker(new GLatLng(latitude, longitude));
map.addOverlay(marker);
if(address!='') getLatLong(address);
}
}
function getLatLong(address) {
geocoder = new google.maps.ClientGeocoder();
if (geocoder) {
geocoder.getLatLng(
address,
function(point) {
if (!point) {
alert(address + " not found");
window.parent.mappa('','');
} else {
map.setCenter(point, 13);
window.parent.mappa(point.lat(),point.lng());
var marker = new google.maps.Marker(point);
map.addOverlay(marker);
}
}
);
}
}
</script>
And at the end, here is the full HTML code:
//[here the c# part]
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
//[here the google map (javascript) part]
</head>
<body style=" margin:0px; padding:0px;" onLoad="load()" onUnload="GUnload()">
<form runat="server">
<div id="map" style="width: 240px; height: 135px;"></div>
</form>
</body>
</html>
Now we have all the files ready; at this point, we have:
- GMapInput.cs
- GMapInput.ascx
- GMapInput.js
- Testg.aspx
- ..if you want GMapInput.css (to customize the control)
And you can include your new web control using a standard syntax like this:
<%@ Register TagPrefix="gmap"
TagName="Input" Src="/controls/myown/gmapinput.ascx" %>
And, here is the HTML code:
<gmap:Input id="myGmapTextBox" runat="server"/>
Points of Interest
This web control is part of a CMS system called Joack developed by me and my team. We have a lot of useful controls developed to integrate useful APIs, for example, the open social API and the Facebook API.
History
This is the first edition of this control; I hope that you find more powerful solutions and upgrade it!