Inserting Yahoo! maps in a Flex 2 application
One of the most challenging parts of creating Home Locator was the integration with Yahoo! Maps since there was no Flex 2 version of their API (they have a Flex 1.5 version, which does not work in Flex 2).
A lot of people asked me at CFUnited and by email about how I did it. In response to that, I made this simple example that shows the details, although not all of the functions are implemented.
It is important to say before we start that I don't recommend using this technique unless you need it right away. It would be better to wait until Yahoo! releases the Flex 2 version of their API. If you can wait, it will be so much easier for you and you won't have to deal with the whole Local Connection stuff (I will explain this in a minute).
As I mentioned before, Yahoo! doesn't have a Flex 2.0 map API, so if we want to have a map, we need to use the Flash API. But having the map in Flash and the rest of the app in Flex it is not as simple as having everything written in Flex. This is because now the player has 2 virtual machines, one for Flex that runs ActionScript 3 and another for Flash that runs ActionScript 2. The problem is that the communication between both VM is not straightforward. It is not very clean and it's not as robust as I would like it to be. But we need to communicate in some way and that way is by using Local Connection. Peter Ent from Adobe made a great post explaining the details of how to communicate Flash and Flex via Local Connection so I highly recommend you to read it.
These are the steps to put the map in a Flex app:
- You need to download and install the Yahoo! Map Flash component
- Get a Yahoo! ID.
- Create a .fla movie and drag the Map component from the component panel to the stage.
- Put an instance name to your map. In my case a used "myMap".
- Write the Yahoo! ID on the parameters of the component.
- Write your ActionScript code and compile it. You can experiment a bit with the code, mine is very basic as you can see below (I did it on the fist frame of the movie):
// ActionScript file
import com.yahoo.maps.markers.CustomPOIMarker;
import com.yahoo.maps.tools.PanTool;
import com.yahoo.maps.widgets.NavigatorWidget;
// register as a listener to get notified when the map finishes the initialization state
myMap.addEventListener(com.yahoo.maps.api.flash.YahooMap.EVENT_INITIALIZE, onInitMap);
function onInitMap(eventData)
{
// create tools and widgets to control the map
myMap.addTool(new PanTool(), true);
myMap.addWidget(new NavigatorWidget("closed"));
// notify Flex that the map finished the initialization state
connectedMap.send("_flexClient","mapInitialized");
}
var connectedMap:LocalConnection = new LocalConnection();
connectedMap.addMarker = function (connectionData:Object):Void
{
//Add the marker to the map
myMap.addMarkerByAddress(CustomPOIMarker,connectionData.address, connectionData.marker);
myMap.setCenterByAddress(connectionData.address, 2500);
}
connectedMap.connect("_flashClient");
What I did in the Flash movie is to set a listener for the "initialize" event. This event gets fired when the map finishes its initialization. Inside this event, I added a "Tool" and a "widget" to be able to control, drag and zoom the map. I also call the Flex application to let it know that flash finished its initialization, and it's ready for use. This also helps me forcing the connection from Flash, because I found (in the beta, that is. I don't know if the bug is fixed now) that if you don't start the connection from Flash the connection sometimes doesn't work.
I also want to mention that I used an underscore in the beginning of the connection name because I found (also in the beta, but I think that is fixed now) that the connection does not work if you name it without it. For example I used "_flexClient" and "_flashClient" for my names.
I included the .fla in the source code. So you only need to open the file, include your ID following the steps described at Yahoo!, compile the swf , and you are ready to go.
Now let's look at the Flex side. There are two files. One is the mxml application (MapExample.mxml) where all the components are.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*" viewSourceURL="/assets/content/exampleFiles/flex/map/srcview/index.html">
<local:MapConnection id="mapConnection"/>
<mx:Panel x="10" y="10" width="392" height="336" layout="absolute">
<mx:SWFLoader id="map" width="370" height="260" source="assets/mapExample.swf" autoLoad="true" x="1" y="1"/>
<mx:TextInput id="address" x="63" y="268" width="229" enter="mapConnection.addMarker(address.text)"/>
<mx:Button x="301" y="268" label="Search" click="mapConnection.addMarker(address.text)"/>
<mx:Label x="10" y="271" text="Address:"/>
</mx:Panel>
</mx:Application>
In this file, we have the SWFLoader tag that will be loading the map into our flex app. In this file we also have a tag
package
{
import flash.net.LocalConnection;
public class MapConnection extends LocalConnection
{
private var isInitialized:Boolean;
private var index:uint;
public function MapConnection(server:String = "_flexClient")
{
try {
connect(server);
}
catch (error:ArgumentError)
{
// server already created/connected
}
super();
}
public function mapInitialized():void
{
isInitialized = true;
trace("SearchConnection init")
}
public function addMarker(address:String):void
{
var marker:Object = {index:++index, title:"title", description:"description", markerColor:0x990099, strokeColor:0xFFFF00 };
if(isInitialized) send("_flashClient","addMarker", {address:address, marker:marker});
}
}
}
In this other file we have one constructor and two methods. One method is "mapInitialized()" that will be called by Flash when Flash finishes the initialization of the map. The other is "addMarker()" that is called by the button that sends the info on the text field as the "address" parameter. What the method does is take that info, create a marker object, and send that to the Flash client (the map) using the local connection method "send()" that we inherit from LocalConnection.
As you can see, this example is very straightforward. You enter an address or just a zip code (easy to type) and click search to see the address marked in the map.
View Example
Scott
Nahuel
You mean when you first load the page? You need to enter the address/zip code to see a marker. There is no marker by default.
If you mean that the marker does not appear after you entered the location, it's a bug. I've seen that happening, but not very often. I don't know if it is a bug in Yahoo! or Flex.
Yechezkal
I am not sure that the connection is initialziing. I am trying to find if I can get the console output to see if the trace on the connection is working.
Yechezkal
After the message arrives at the _flashClient, I have no real idea what happens, or why it is not displaying.
Piatek
Nahuel
From what you say, I think that the problem is sending the marker info from Flex to Flash. You can try adding a trace on the Flash side and see if you receive the call (to see the trace on the console you need to run the app on the flex debug mode)
Piatek,
I have the same version as yours, so it should work
Piatek
Any insight would be much appreciated!!!
Laura
The movie you compile in Flash must be added to the assets folder in Flex. It doesn't do anything by itself, if that is your question. (If the movie does not get copied to the bin folder in Flex, copy it there too)
Piatek
BTW - Long time visitor - EXCELLENT site keep it up!!!!
Yechezkal
It is now recentering properly.
But the marker does not appear.
Oddly I do not see any trace messages in the Debug Console.
Chaz
I am using flex for the first time and I have a question.
My sample app is the flexstore.
In the template flexstore.mxml it bring in all of the mxml files in that directory and I see the viewstack tag is using some of the templates to display the content. My question is if I have a link button on the homeview.mxml and by clicking that button change the view to show the ProductsView.mxml template how can I do this?
Thanks
Yechezkal
Joshua
Chuck
Craig Newroth
Josh R.
The error says I can work around this by "This may be worked around by calling Security.allowDomain." what does it mean by this and where in your example would this be placed?
Here is the error I get.
SecurityError: Error #2121: Security sandbox violation: BitmapData.draw: http://worksofartembroidery.com/wofa.swf cannot access http://us.maps1.yimg.com/us.tile.maps.yimg.com/tile?md=200604181524&col=1973&row=899&z=5. This may be worked around by calling Security.allowDomain.
at flash.display::BitmapData/draw()
at mx.effects.effectClasses::MaskEffectInstance/::getVisibleBounds()
at mx.effects.effectClasses::MaskEffectInstance/::initMask()
at mx.effects.effectClasses::MaskEffectInstance/startEffect()
at mx.effects::Effect/play()
at mx.effects::EffectManager$/::createAndPlayEffect()
at mx.effects::EffectManager$/http://www.adobe.com/2006/flex/mx/internal::eventHandler()
at flash.events::EventDispatcher/flash.events:EventDispatcher::dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.core::UIComponent/setVisible()
at mx.containers::ViewStack/::commitSelectedIndex()
at mx.containers::ViewStack/mx.containers:ViewStack::commitProperties()
at mx.core::UIComponent/validateProperties()
at mx.managers::LayoutManager/::validateProperties()
at mx.managers::LayoutManager/::doPhasedInstantiation()
at Function/http://adobe.com/AS3/2006/builtin::apply()
at mx.core::UIComponent/::callLaterDispatcher2()
at mx.core::UIComponent/::callLaterDispatcher()
Curt Hall
I've been playing around with this app, and I'm having a tough time getting the EVENT_DRAG_STOP and EVENT_DRAG_START events to work properly. I'm using Flex 2, and I'm adding the lines myMap.addEventListener(EVENT_DRAG_STOP, myFunction);
then, function myFunction(eventData){ connectedMap.send("_flexClient", "dragStop");
My method is flex does an Alert, but nothing shows up... I've tried several things, including stretching out the pathway to com.yahoo.maps.tools.PanTool.EVENT_DRAG_STOP, but to no luck. Any ideas? Also, would the proper way to send data to the Flex app be
connectedMap.send("_flexClient", "dragStop", var1, var2, etc);?
Thanks in advance!
Adam Fortuna
Adam Fortuna
Darius
**Error** Scene=Scene 1, layer=Layer 2, frame=1:Line 14: There is no property with the name 'addMarker'.
connectedMap.addMarker = function (connectionData:Object):Void
Total ActionScript Errors: 1 Reported Errors: 1
Trace
Thanks!
Joris Schets
Hans Vansteene
Nahuel
If you trying to use this example with a viewStack or Tabs and you cannot make it work, I think it is because the creationPolicy of those components is different from the rest. They have a "deferred instantiation" by default. You can try two things:
1. Change the creationPolicy to "ContainerCreationPolicy.ALL" 2. Create another mxml and put all the code there and add that component as a child of the viewStack.
If that doesn't do the trick, I don't know :(
Dave Meas
I am having problems with my application AND the example. I cannot get the map to center or get any tags added. I am writing a simple application to tag sales data to states/cities. Any help would be greatly appreciated.
Thanks!
Dave Meas
beatport.com
Here is my code:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<local:MapConnection id="mapConnection" />
<mx:Sprite id="mapDisplay"/>
<mx:Panel x="10" y="60" width="700" height="630">
<mx:SWFLoader id="map" width="700" height="600" source="assets/mapExample.swf" autoLoad="true" x="100" y="100"/>
</mx:Panel>
<mx:TextInput id="address" x="60" y="80" width="280"/>
<mx:Button x="60" y="110" click="mapConnection.addMarker(address.text)"/>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Thomas
Anupam
But the problem is that i want to call an event from the Flex whenever user clicks a CustomPOIMarker on the map.
I have tried but the event is never getting called,tried to get help from so many forums but of no use...
Can you provide some insight in this issue
Thanks in Advance
Anupam
Jeff Phillips
http://www.adobe.com/devnet/flex/samples/tourtracker/
Rostislav Siryk
However, I'm having troubles when trying to make BitmapData.draw to loaded Yahoo Map using this API in Flex 2 app. The error is "SecurityError: Error #2121: Security sandbox violation: BitmapData.draw: http://localhost/MapsTest.swf cannot access http://us.maps1.yimg.com/us.tile.maps.yimg.com/tile?md=200702051436&col=-1&row=5&z=14&t=p. This may be worked around by calling Security.allowDomain.
at flash.display::BitmapData/draw()
"
Does anyune have a clue how to overcome this annoyance?
eatmorepossum
*** Security Sandbox Violation ***
error.
specifically:
*** Security Sandbox Violation ***
SecurityDomain 'http://myserver:8080/cfflex/TestProject/bin/TestProject-debug.html?debug=true' tried to access incompatible context 'http://us.maps1.yimg.com/us.tile.maps.yimg.com/tile?md=200702051436&col=3&row=1&z=14&t=p'
[SWF] /us.tile.maps.yimg.com/tile - 7,304 bytes after decompression
I have added a crossdomain.xml policy file at the root of my server.
*********************crossdomain.xml*******************
<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE cross-domain-policy
SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd
">
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>
***************end*crossdomain*******************
It is my understanding that there also must be a crossdomain.xml policy file at the root of yahoos server:
http://us.maps1.yimg.com/
I am stuck at the moment. Does anyone have any suggestions? Thanks,
Chris
eatmorepossum
private const SWFDOMID:String = "TestProject";
complete explanation here: http://tech.groups.yahoo.com/group/yws-maps/message/5165
Matt Miraglia
I was wondering if the Home Locator source code was available to download anywhere? This looks like a great example showing alot of different aspects of what Flex can do along with adding Yahoo maps.
Thanks in advance,
Matt M.
Cody Snider
Nicky
Rostislav Siryk
To get the picture what I'm talking about, please see my Apollo 3D Google Map sample application (sources included):
http://flash-ripper.com/en/2007/sources-for-apollo-3d-test-application/
aubweb
I've got the same issue with the error #2121
My map is in a viewstack but where the creationpolicy is set to 'all'.
I saved a crossdomainpolicy file to the root of my serverm the SWFDOMID is correct ...
I have the error but the map is correctly displayed, it's weird but annoying to have this error.
I dunno what else to do... please help me, us to find a sollution.
SecurityError: Error #2121: security violation Sandbox : BitmapData.draw : ...GreenTouch.swf cannot access to http://us.maps1.yimg.com/us.tile.maps.yimg.com/tile?md=200705152300&col=67111&row=21592&z=1&t=p. ....Security.allowDomain.
at flash.display::BitmapData/draw()
at mx.effects.effectClasses::MaskEffectInstance/::getVisibleBounds()
at mx.effects.effectClasses::MaskEffectInstance/::initMask()
at mx.effects.effectClasses::MaskEffectInstance/startEffect()
at mx.effects::Effect/play()
Thanks in advance
Aub
RobOToole
I have a very strange error....when i load my map component alone as its own application, the CustomPOIMarker opens fine but when i put it in my viewstack, the marker won't open fully(only does the mouse over open). Anyone else have this problem or an answer??
JMResler
Cardiff
vijay
vijay
Rostislav Siryk
They just introduced the Yahoo! Flash Platform Team:
http://www.yswfblog.com/blog/2007/08/14/introducing-the-yahoo-flash-platform-team/
So there's a hope Maps API will become better soon.
Omar Gonzalez
http://tech.groups.yahoo.com/group/ydn-flash/message/391
I hope we can get a crossdomain.xml in place soon, I'm sure there are plenty of people trying to place the Yahoo maps in their ViewStacks or use a transition effect. Let the voices be heard! =)
Diego Purgue
I need remove or open a specific Marker from the map. It's possible it??. I'm using flex 3.
Reggards
hi
Arthurnasius Amanyire
Shaguf Mohtisham