Archive for the ‘JavaScript;Ajax’ Category

click on marker always show the last entry of data

June 14, 2008

This is a question from a co-worker of my last job. His is using gcliendGeocoder within a for-loop to dynamically get lat/lng and creating makers on Google maps. The problem is each time you click on a marker, the html text in the info window is always the one that should be for the last marker in the for-loop.

His code:

for (id = 0; id < addresses.length; id++)
{
var description = addresses[id];
var myBiz = biz[id];
geocoder.getLatLng(
description,
function(point)
{
var marker = new GMarker(point);
GEvent.addListener(marker, ‘click’,function(){marker.openInfoWindowHtml(description);});
map.addOverlay(marker);
}
);
}

The point here is “geocoder.getLatLng” is an “asynchronous” callback. That means when the “for-id-loop” reaches its end, the very first “getLatLng” may not get back yet. That’s why you always get the last description in the array. The fix is to add an additional counter inside the call back of “getLatLng”, and assign it as a dynamic property to the marker that gets returned from the callback, and then increment the counter by one at the end of the callback. When you handle the click, you always do a lookup on the marker using the id to find the right marker and the description.

var markers = [];
var closureID = 0;

for (id = 0; id < addresses.length; id++) {
var description = addresses[id];

geocoder.getLatLng(
description,
function(point) {
if(point)
{
var marker = new GMarker(point);
marker.id = closureID;
markers[closureID]=marker;
GEvent.addListener(marker, ‘click’,
function()
{
markers[marker.id].openInfoWindowHtml(addresses[marker.id]);
}
);
map.addOverlay(marker);
++closureID;
}
}
);

}

To see it in action, here is what happens “before“, and “after“:

E4X in ActionScript 3 and Flex 3

January 1, 2008

The following top AS3 classes, in conjunction with HTTPService and mx.rpc.events.ResultEvent classes are used in Flex (2+) to handle XML:

XML/XMLList/Namespace/QName

XMLList Class can be considered a collection of XML objects. It is a native ActionScript class that is advised to handle XML such as data binding. XMLNode has become the legacy class in AS 2.

So the first step of handling XML data is to deserialize an XML document or object into XMLList objects.

<mx:HTTPService id="dataFetcher" url="http://mysite/myData.xml" resultFormat="e4x" result="onData(event)" />

Remember you will almost always need to initialize the call by adding the following code to the “creationComplete” event handler of the mx:Application node:

<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” creationComplete=”dataFetcher.send()”/>

To deserialize the an XML object (sample shown as follows), use ResultEvent Class, like so:

<delSum Test="1" timestamp="2007-12-10T21:07:48Z">
<del pId=”Dem” dNeed=”2029″ dTot=”4056″ dChosen=”991″ dToBeChosen=”3237″>
<Cand cId=”1746″ cName=”Clinton” dTot=”290″ d1=”+290″ d7=”+290″ d30=”+150″/>
<Cand cId=”1918″ cName=”Obama” dTot=”194″ d1=”+194″ d7=”+194″ d30=”+55″/>
</del>
<del pId=”GOP” dNeed=”1113″ dTot=”2225″ dChosen=”251″ dToBeChosen=”2153″>
<Cand cId=”893″ cName=”Romney” dTot=”109″ d1=”+109″ d7=”+109″ d30=”+1″/>
<Cand cId=”302″ cName=”Paul” dTot=”47″ d1=”+47″ d7=”+47″ d30=”0″/>
</del>
</delSum>

private function onData(event:ResultEvent):void
{
demData = event.result.del.(@pId==”Dem”).Cand.(@cName!=”Uncommitted”);
gopData = event.result.del.(@pId==”GOP”).Cand.(@cName!=”Uncommitted”);
}

Note that event.result represents the top node, which is <delSum> node in the XML document.

XML filtering:

To locate a set of XML objects that represents similar characteristics, use the parenthesis () to include sets of boolean statements, following a dot after the node you want to carry out the filtering against, like so:

var product1:XMLList = catalog.product.(@id==1);//Returning the product node or nodes if there are multiple products whose id is equal to 1

or

var productName:String = catalog.product.(price<50).name;//Returns the name node

or

var manufName:String = catalog.product.(price<50).@manufacturer;//Returns the manufacturer attribute under the name node

To get list of candidate names:

var _tst:XMLList = event.result.del.(@pId=="GOP").Cand.(@cName!="Uncommitted").@cName
trace((_tst[0] is XML)+”; “+_tst[0].nodeKind() )//Returns “true; attribute”
trace(gopData[0].@cName+”; “+(gopData[0].nodeKind())//Returns “Romney; element”

Types of node include: text, comment, processing-instruction, attribute, or element.

google map css trap 101

November 6, 2007

#1. An div rule will sometimes screw up the overlay popup. Suppose you have #container>#mapDiv, the following will add a weird white bar underneath the popup window (speech bubble when openInfoWindowHTML/openInfoWindow are called):

#container div{
margin-top:10px;
padding-bottom:10px;
}

#2. For some mysterious reasons, sometimes the GInfoWindow object gets some extra document div(s) nested when you call openInfoWindowHTML/openInfoWindow and that results in extra white padding space between the real content and teh GInfoWindow object. The workaround is to specify the “maxWidth” property in the GInfoWindowOption object which is the second parameter for an openInfoWindow(HTML) call:

GEvent.addListener(marker, "click", function() {
marker.openInfoWindow(venue.getHTML(), {maxWidth:300});
});

Assign additional class to a div using Prototype 1.5/6

October 5, 2007

Senario:

You need to do something like this (only one div gets assigned class “hilit” at a time):

<div class = “thumbDivOther hilit” id=”thumb_intro” onclick=”showItem(’intro’, this);”>

Code:

currHilitDiv.removeClassName(’hilit’);
//This doesn’t work in IE6
//div.addClassName(’hilit’);
Element.addClassName(div, ‘hilit’);
currHilitDiv = div;

Instantiate one Flash object at once in a page

October 5, 2007

Senario:

I need to instantiate only one Flash object at once in a page, for instance under a row of tabs when the user clicks on one of them. Sometimes I toggle between different Flash objects; sometimes just another DOM div takes place of the Flash object. It’s very straightforward in Firefox since all you need to do is to toggle the “display” property (set it to the value of “none”). With Prototype library, you can use Element.hide()/show(). In IE, situations get a little complicated since if that Flash is playing a video clip, the stream continues (you still hear sound, etc.) regardless of its containing div’s “display”/”visibility” property values.

Solutions:

For the former situation, simply write a new swf object to the same div:

function loadSWF(fileName)
{
swfURL = appURL+’swf/’+fileName+’.swf’;
var so = new SWFObject(swfURL, “soObj”, “500″, “360″, “8″, “#eeeeee”);
so.addParam(”allowscriptaccess”,”always”);
so.addParam(”swliveconnect”, “true”);
so.useExpressInstall(”http://myhostname.com/js/swfobject/expressinstall.swf”);
so.write(”vidHolder”);
}

For the latter situation, destroy the swf object by doing the following when toggling to another div which doesn’t contain any swf object. This will stop the audio/video streams:

$(’vidHolder’).innerHTML = “”;

Google map infoWindow/infoWindowHtml doesn’t render background

February 28, 2007

Because google maps control how the overflowed DIV renders in infoWIndow/infoWIndowHtml class by itself, it sometime overshadows user defined overflow/max-height/max-width properties. It will cause the background tiles of infoWindows/infoWindowHtmls don’t render (lastly found in IE 6 Windows 2k/XP/SP 1, esp the page is iframed by another page, in my case it happens to be in another domain if it matters; or if the infoWindow is opened by click on a DOM object other than the marker it’s associated with). The solutions could be automatically loading the iframed page a second time, or emulating user directly clicking on the marker using javascript.

In the figure, the symptom happens in IE  6(winXP/2k pro) when the page with google maps is framed via a page from another domain. It happens If the user clicks on a ward number on the bottom of the page to pop up an infoWindowHtml the first time the iframe page gets loaded (instead of clicking on the corresponding custom markers within the map.) The fix is to use a trick that first calling “map.openInfoWindow()” then “map.closeInfoWindow()” immediately to simulate a mouse click the first time the map tiles rendered. What will happen in actuality is that no infoWindow will be displayed but it force IE to “rerender” the map tiles to get the right relative positioning for CSS.
unrendered map image tiles

max-height/overflow for google map infowindow

February 28, 2007

//KLUDGE: in windows XP SP2, if the user clicks the num div first to open an infowindow/infowindowhtml, the background images of the marker doesn’t render or renders partially (sometimes the center div bkg renders sometimes the frames images render); while this didn’t happen if the user clicks directly on a marker to open the infowindow/infowindowhtml. This trick helps to circumvent the situation by openinfowindow directly first to emulate the fact that a user clicks on a marker, or loading the framed page a second time.

lightweight flash object

February 21, 2007

here is how Google video is using Flash Object:

Sample code:

<embed 
	style=“width: 100%; height: 100%;” 
	id=“VideoPlayback” type=“application/x-shockwave-flash” 
	src=“/googleplayer.swf?&videoUrl=http://vp.video.google.com/videodownload?version=0&secureurl=twAAAClqeHzNZY6S6k1LAkocsV_7A_xqwntKJHO0hegdIh0hBuRs9_1-V7tRNbg-OSTyMxQDCx1AGMHU1_3ISijrxSMlVEw0NEWUDpKl4F92fIBqSrHu1RUDH_0yAqHqXWeJ1pSFr9687_OcAtO9uCX1G83md9lMwoFNWSKZrucxWQTsVwrl9cX7aqlQZpKDuHOlzaaVQg3d3T0V9lTyBy_u3bxPfrKZOGtezIm65D3iNtG4V4m4QSBHW7JdD4UsShMqjg&sigh=pgbjX9CQZkp-YvpdysLfgALvSiE&begin=0&len=2897133&docid=5650400464718085334&messagesUrl=http://video.google.com/FlashUiStrings.xlb?frame=flashstrings&hl=en&thumbnailUrl=http://video.google.com/ThumbnailServer2?app=vss&contentid=d3ce7e4fb30a2308&offsetms=155000&itag=w320&lang=en&sigh=l8Txh9HxxHBtd9YxkoP-f2uQASg” 
	allowscriptaccess=“always” 
	quality=“best” 
	bgcolor=“#ffffff” 
	scale=“noScale” 
	salign=“TL” 
	flashvars=“playerMode=normal&autoPlay=true&docid=5650400464718085334&clickUrl=” 
	align=“middle”>
 </embed>

Google uses escaped characters (like “\u003d” etc.) in javascript to dynamically generate the fullscreen pop-up window.

append a random number as the query string

February 16, 2007
function appendRandomQuery(){
if(!window.location.search.toString().length){
var ran = Math.round(Math.random()*10000000);
window.location.search = “?”+ran;
alert(”the random number is “+ran);
}
}

function appendRandomQueryToTop(){
if(!window.top.location.search.toString().length){
var ran = Math.round(Math.random()*10000000);
window.top.location.search = “?”+ran;
alert(”the random number is “+ran);
}
}

function appendRandomQueryPrarentWindow(){
if(!window.parent.location.search.toString().length){
var ran = Math.round(Math.random()*10000000);
window.parent.location.search = “?”+ran;
alert(”the random number is “+ran);
}
}

appendRandomQuery();

The techniques demonstrated above can be used to load an iframe twice automatically. The need for an iframe to be immediately reloaded again after loaded once is that some DOM objects are not rendered correctly the first time the page got loaded. In a google map mashup project I recently did, the first time the page gets loaded, the map was showing its top-left corner; tile images were cut-off 3/4 and the all other parts were grayed out. It seems the DOM objects were displaced to several hundreds pixels left-bottom to where they are supposed to be in the Google map. Most of the times (but not always!) reloading the page (by pressing the “Reload current page” button) will solve the issue. It happens in an iframe viewed in IE (6/7; XP sp1/2). Never happens in Firefox or Mozilla. A combination of attempts(including changing the slug in the content management system [urls for the parent window document]; getting rid of tage and using the javascript reload) seems to have fixed the bug.

pass additional parameters to event handler using Prototype.js

February 1, 2007

bindAsEventListener(scope, arg1, arg2,…)

example (all functions inside body script tags):

Event.observe(div, 'click', zoomToWard.bindAsEventListener(this, wardIndex));
function zoomToWard(evt, index){
	alert("index::: "+index);
	}
http://www.simpltry.com/?cat=2&paged=2

http://www.google.com/search?hl=en&q=pass+arguments+observe+prototype&btnG=Google+Search

in encytemedia
http://encytemedia.com/blog/articles/2006/02/08/working-with-events-in-prototype

typo - SWiK
http://swik.net/Typo+Prototype