Flex Flashbuilder Google Maps - apache-flex

Hi I'm wondering if anybody could help me with a problem I'm trying to solve with Flex & google maps.
I have a map that is populated by markers. Each marker has an event listener. And what I am hoping to achieve is that when each marker is clicked that a datagrid is populated with the data associated to that marker. However at the moment I can only populate the data grid with the LatLng object. I need to find a way to access the other data associated with that Marker.
Here is my event listener:
private function createMarker(latlng:LatLng, int:Number, tip:String, desc:String):Marker
{
var m:Marker = new Marker (latlng, new MarkerOptions ({hasShadow: true, tooltip: "" +tip}));
m.addEventListener(MapMouseEvent.CLICK, function(event:MapMouseEvent):void
{details.addItem(event.latLng.toString());});
return m;
}
I was thinking it might be along the lines of getitem where LatLng = event.latLng but I'm really new to flex so I can't figure it out at all.
Any ideas that might put me on the right track would be really appreciated.
L

Try this:
private var markerArray:Array = [];
private var markerDescriptsArray:Array = [];
private function createMarker(latlng:LatLng, int:Number, tip:String, desc:String):Marker
{
var m:Marker = new Marker (latlng, new MarkerOptions ({hasShadow: true, tooltip: "" +tip}));
m.addEventListener(MapMouseEvent.CLICK, function(event:MapMouseEvent):void
{
var _mIndex:uint;
for (var i:uint = 0; i < markerArray.length; i++)
{
if(markerArray[i] == Marker(e.currentTarget)) _mIndex = i;
}
details.addItem(markerDescriptsArray[_mIndex]);
});
markerArray.push(m);
markerDescriptsArray.push(desc);
return m;
}

Related

How to browse to the next page in a datasource that is loaded into table in Google AppMaker

I'm working on a requirement where I have a datasource named 'emailSearchResults' where I search for email messages metadata and load the results in the datasource.
The fields in the datasource are not relevant, however I set the datasource to have 50 records per page as per the below screenshot:
The script I used to load the datasource is shown in the query field, that call the following script:
function getMessageDetails(userId, msgID)
{
var messageDetails = [];
var messageData;
var msgID_,subject_,from_,date_;
messageData=Gmail.Users.Messages.get(userId,msgID,{format:"metadata", metadataHeaders:["Message-ID", "Subject", "From", "Date"]});
console.log(messageData.payload.headers);
//console.log(msgID);
//console.log(messageData.payload.headers[3].value);
date_="<na>";
from_="<na>";
subject_="<na>";
msgID_="<na>";
for (var counter =0;counter<4;counter++)
{
if (messageData.payload.headers[counter].name=="Message-ID")
{
msgID_=messageData.payload.headers[counter].value;
}
if (messageData.payload.headers[counter].name=="Subject")
{
subject_=messageData.payload.headers[counter].value;
}
if (messageData.payload.headers[counter].name=="From")
{
from_=messageData.payload.headers[counter].value;
}
if (messageData.payload.headers[counter].name=="Date")
{
date_=messageData.payload.headers[counter].value;
}
}
messageDetails.push(date_);
messageDetails.push(from_);
messageDetails.push(subject_);
messageDetails.push(msgID_);
return messageDetails;
}
function searchMessages(userId,condition)
{
//
// first we build the conditions
// we can make it fixed
// or we can make it dynamic
var searchResult;
var deleteResult;
var currentMessage;
var results = [];
var pageToken;
var params = {};
var _stat;
var options = {
includeSpamTrash: "true",
pageToken: pageToken
};
var msgRecord = [];
do
{
searchResult=Gmail.Users.Messages.list(userId,options);
for (var i = 0; i < searchResult.messages.length; i++)
{
var record=app.models.emailSearchResults.newRecord();
msgRecord=getMessageDetails(userId,searchResult.messages[i].id);
record.msgMainID=searchResult.messages[i].id;
record.msgID=msgRecord[3];
record.subject=msgRecord[2];
record.senderAddress=msgRecord[1];
record.msgDate=msgRecord[0];
/*console.log(searchResult.messages[i].id);
console.log(msgRecord[3]);
console.log(msgRecord[2]);
console.log(msgRecord[1]);
console.log(msgRecord[0]);
return;*/
results.push(record);
msgRecord=null;
}
if (searchResult.nextPageToken) {
options.pageToken = searchResult.nextPageToken;
}
} while (searchResult.pageToken);
searchResult=null;
return results;
}
On the main page I put a table and linked it to the datasource, and I enabled pagination on the table, so I get the pager buttons at the bottom of the table as below:
When I execute the app and the datasource is filled, I see the first page results in a correct way, however when I want to move to the next page, I click the next page button and once the loading is complete I find out that I still see the same results from the first page on the table.
I am not familiar with how to make the table show the results of the second page then the third page, and I am going in circles on this...
Hope the explanation is clear and addresses the issue..
I would really appreciate any help on this!
Regards
Currently pagination isn't working as expected with calculated datasources. You can, however, build your own. There are several changes you'll need to make to accomplish this. First you'll want to refactor your searchMessages function to something like this:
function searchMessages(userId, pageToken){
var results = [];
var options = {
includeSpamTrash: "true",
pageToken: pageToken,
maxResults: 50
};
var searchResult = Gmail.Users.Messages.list(userId, options);
for (var i = 0; i < searchResult.messages.length; i++){
var record = app.models.emailSearchResults.newRecord();
var msgRecord = getMessageDetails(userId,searchResult.messages[i].id);
record.msgMainID = searchResult.messages[i].id;
record.msgID = msgRecord[3];
record.subject = msgRecord[2];
record.senderAddress = msgRecord[1];
record.msgDate = msgRecord[0];
results.push(record);
}
return {records: results, nextPageToken: searchResult.nextPageToken};
}
Then you'll want to change your datasource query. You'll need to add a number parameter called page.
var cache = CacheService.getUserCache();
var page = query.parameters.page || 1;
var pageToken;
if(page > 1){
pageToken = cache.get('pageToken' + page.toString());
}
var results = searchMessages('me', pageToken);
var nextPage = (page + 1).toString();
cache.put('pageToken' + nextPage, results.nextPageToken);
return results.records;
You'll need to modify the pagination widget's various attributes. Here are the previous/next click functions:
Previous:
widget.datasource.query.pageIndex--;
widget.datasource.query.parameters.page = widget.datasource.query.pageIndex;
widget.datasource.load();
Next:
widget.datasource.query.pageIndex++;
widget.datasource.query.parameters.page = widget.datasource.query.pageIndex;
widget.datasource.load();
You should be able to take it from there.

OpenLayers: Registering function to marker event does not work

I have a map in OpenLayers with a simple layer and a marker layer.
The markers in the marker layer are generated from data.rows. For every marker, I want to register a function to the "mousedown" (or "click") event, but that does not seem to work. The markers got added to the map, but upon clicking, the function registered to the event is not entered.
// Marker-Layer
var markers = new OpenLayers.Layer.Markers("SABA")
// Icon
var size = new OpenLayers.Size(21, 25);
var offset = new OpenLayers.Pixel(-(size.w / 2), -size.h);
var iconPath = document.location.protocol + '//' + document.location.hostname + '/saba/modulesinst/sa/icons/pin.png';
var icon = new OpenLayers.Icon(iconPath, size, offset);
// Rows durchgehen
Array.each(data.rows, function(item, index) {
if (item.x != null && item.y != null) {
var newmarker = new OpenLayers.Marker(new OpenLayers.LonLat(item.x, item.y), icon.clone())
newmarker.events.register('mousedown', newmarker, function(evt) {
alert(item.name);
OpenLayers.Event.stop(evt);
});
markers.addMarker(newmarker);
}
});
this.listMap.addLayer(markers);
The Openlayers Documentation states that you should use a vector layer for this purpose instead of a marker layer: "Markers are the ‘older’ way to interact with geographic data in the browser. Most new code should, where possible, use vector layers in place of marker layers".
When you use a vector layer you can add markers like this:
var marker = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(lon,lat), attributes);
vectorLayer.addFeatures(marker);
and you can use this code to initialize the vector layer:
function selected (evt) {
alert(evt.feature.id + " selected on " + this.name);
}
var layer = new OpenLayes.Layer.Vector("VLayer");
layer.events.register("featureselected", layer, selected);
and finally this to add the select feature control to your map:
var control = new OpenLayers.Control.SelectFeature(layer);
map.addControl(control);
control.activate();
Refer to this Openlayers Documentation

Music player in Actionscript 3.0

I already added a stop button with autoplay but I need to make it so when you click the button again after you had stopped it, the music starts playing.
Source code:
var music:Sound = new Sound(new URLRequest("calmingsong.mp3"));
var sc:SoundChannel = music.play();
button1.addEventListener(MouseEvent.CLICK, stopMusic);
function stopMusic(e:Event):void
{
sc.stop();
}
If you just want to play the sound over from the beginning, just call the Sound object's play() method again (you get a new SoundChannel object when you do this).
If you'd like to resume playing the sound at the point where the user stopped it, you'll need to add additional variables to store the current "playback state"... Something like this:
var music:Sound = new Sound(new URLRequest("calmingsong.mp3"));
var sc:SoundChannel = music.play();
var startPosition:Number = 0;
var isPlaying = true; // default to true cause you auto play...
button1.addEventListener(MouseEvent.CLICK, togglePlayback);
function togglePlayback(e:Event):void
{
if (isPlaying)
{
startPosition = sc.position;
sc.stop();
isPlaying = false;
}
else
{
sc = music.play(startPosition);
isPlaying = true;
}
}

Google Maps API V3: Offset panTo() by x pixels

I have a some UI elements on the right of my map (sometimes), and I'd like to offset my panTo() calls (sometimes).
So I figured:
get the original latlng
convert it to screen pixels
add an offset
convert it back to latlng.
But I must misunderstand what Google Maps API refers to as the "Point Plane":
http://code.google.com/apis/maps/documentation/javascript/reference.html#Projection
Here is my code that seems to offset by lat-long:
function getCentreOffset( alatlng ) {
var PIXEL_OFFSET= 100;
var aPoint = me.gmap.getProjection().fromLatLngToPoint(alatlng);
aPoint.x=aPoint.x + OFFSET;
return me.gmap.getProjection().fromPointToLatLng(aPoint);
}
Here's a simpler version of Ashley's solution:
google.maps.Map.prototype.panToWithOffset = function(latlng, offsetX, offsetY) {
var map = this;
var ov = new google.maps.OverlayView();
ov.onAdd = function() {
var proj = this.getProjection();
var aPoint = proj.fromLatLngToContainerPixel(latlng);
aPoint.x = aPoint.x+offsetX;
aPoint.y = aPoint.y+offsetY;
map.panTo(proj.fromContainerPixelToLatLng(aPoint));
};
ov.draw = function() {};
ov.setMap(this);
};
You can then use it like this:
var latlng = new google.maps.LatLng(-34.397, 150.644);
var map = new google.maps.Map(document.getElementById("map_canvas"), {
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: latlng
});
setTimeout(function() { map.panToWithOffset(latlng, 0, 150); }, 1000);
Here is a working example.
Let me explain in detail. This extends the Map object itself. So you can use it just like panTo() with extra parameters for offsets. This uses the fromLatLngToContainerPixel() and fromContainerPixelToLatLng() methods of the MapCanvasProjecton class. This object has no contructor and has to be gotten from the getProjection() method of the OverlayView class; the OverlayView class is used for the creation of custom overlays by implementing its interface, but here we just use it directly. Because getProjection() is only available after onAdd() has been called. The draw() method is called after onAdd() and is defined for our instance of OverlayView to be a function that does nothing. Not doing so will otherwise cause an error.
Answer by Dean looks a lot cleaner as said in some comments, but was looking a little complicated to me. This single line solution is looking more elegant to me.
var map = $('#map_canvas').gmap3("get")
map.panBy(-500,-500); // (x,y)
Set center of map first. Then panyBy will shift the center in (x,y) direction. The more negative x, map will shift right. The more negative y, map will shift down.
Ok I found the answer here: How to call fromLatLngToDivPixel in Google Maps API V3?
First create function/prototpe to access the map's projection (difficult in V3)
//declare function/prototpe
function CanvasProjectionOverlay() {}
//define..
CanvasProjectionOverlay.prototype = new google.maps.OverlayView();
CanvasProjectionOverlay.prototype.constructor = CanvasProjectionOverlay;
CanvasProjectionOverlay.prototype.onAdd = function(){};
CanvasProjectionOverlay.prototype.draw = function(){};
CanvasProjectionOverlay.prototype.onRemove = function(){};
var gmap;
var canvasProjectionOverlay;
var PIXEL_OFFSET= 100;
function showUluru(isOffset=false){
//create map
var gmap = new google.maps.Map($('#map_canvas', {});
//create projection
canvasProjectionOverlay = new CanvasProjectionOverlay();
canvasProjectionOverlay.setMap(gmap);
var uluruRock = new google.maps.LatLng(-25.335448,135.745076);
if (isOffset)
uluruRock = getCentreOffset(uluruRock);
gmap.panTo( uluruRock )
}
//Use this function on LatLng you want to PanTo();
function getCentreOffset( alatlng ) {
var proj = canvasProjectionOverlay.getProjection();
var aPoint = proj.fromLatLngToContainerPixel(alatlng);
aPoint.x=aPoint.x+PIXEL_OFFSET;
return proj.fromContainerPixelToLatLng(aPoint);
}

call inline function and pass in current item as the argument - Flex 3

Im trying to create a loop of items like this...
for each (var btn:Object in ViewButtonData)
{
// build element
var box:HBox = new HBox();
box.styleName = "lefttab";
box.width = "100%";
box.addEventListener("rollOver", HoverTab(btn.id, 1));
box.addEventListener("rollOut", HoverTab(btn.id, 0));
// add element to list
}
I would like to pass in current HBox to the 'HoverTab' function. Is there a way to do that?
James Ward's comment is correct. You can just do:
function myHandler(event:Event):void {
var myHBox:HBox = event.currentTarget as HBox;
}
That said, the answer to your question is:
box.addEventListener("rollOver", function(e:Event) { HoverTab(box, btn.id, 1); });
..spread out for more readability:
box.addEventListener("rollOver",
function(e:Event) {
HoverTab(box, btn.id, 1);
}
);
The HBox should automatically be available in the event handler via event.currentTarget.
box.addEventListener("rollOver", hoverTab(btn.id, 1));
box.addEventListener("rollOut", hoverTab(btn.id, 0));
This won't work unless hoverTab is a function that returns a function that takes an event as its sole argument. Replace it with:
box.addEventListener("rollOver", hoverTab);
box.addEventListener("rollOut", rollOutTab);
And as James mentioned, you'll get HBox from event.currentTarget
function hoverTab(event:MouseEvent):void
{
var box:HBox = HBox(event.currentTarget);
}
To get btn.id inside hoverTab, store HBoxes and btn.ids into two arrays from the for-each loop. Now you can get the index of HBox using indexOf method - btn.id will be at the same index in its array.
var boxes:Array = [];
var ids:Array = [];
for each (var btn:Object in ViewButtonData)
{
// build element
var box:HBox = new HBox();
boxes.push(box);
ids.push(btn.id);
box.addEventListener(MouseEvent.ROLL_OVER, hoverTab);
box.addEventListener(MouseEvent.ROLL_OUT, rollOutTab);
// add element to list
}
function hoverTab(event:MouseEvent):void
{
var box:HBox = HBox(event.currentTarget);
var btnid:Number = ids[boxes.indexOf(box)];
}
Alternatively, (since ActionScript allows different types in the same array), you can push them into the same array and read the btn.id as array[array.indexOf(box) + 1]

Resources