Tuesday, December 15, 2009
OpenScales
I've been working for some time now with the Openscales AS3 library. Finally we have a Flex GIS client. The library is work in progress, but already offers really nice features and functions. At some point soon I will share some of my work and code. I've been busy customising core functional elements including adding Yahoo and Bing baselayers, restricting WFS rendering to scale, allowing WFS layers to be turned on and off, custom styling the interface and components. More to come.
Labels:
client,
Flex,
maps. GIS,
open source,
OpenScales
Flex Web Services
I don't often use web services in Flex. But recetly found need to dip my toe in. The following I thought was an exellent simple example. taken from http://www.cflex.net/showFileDetails.cfm?ObjectID=582. Thanks Tracy.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns="*"
creationComplete="getWeather()" >
<mx:Script>
<![CDATA[
import mx.controls.dataGridClasses.DataGridColumn;
import mx.rpc.events.ResultEvent;
import mx.managers.CursorManager;
import mx.controls.Alert;
default xml namespace = "http://www.webservicex.net"; //necessary to access the xml elements easily
[Bindable]private var _xmlResult:XML; //holds the result xml
[Bindable]private var _xlDayData:XMLList; //dataProvider for the day weather dataGrid
[Bindable]private var _sPlace:String;
/** invokes the web service operation to get the weather */
private function getWeather():void
{
CursorManager.setBusyCursor();
WS.GetWeatherByZipCode.send();
}
/** called by the WebService result event. Sets the dataProviders as necessary */
private function onResult(oEvent:ResultEvent):void
{
_xmlResult = XML(oEvent.result);
var xmlResultNode:XML = _xmlResult.GetWeatherByZipCodeResult[0];
var xmlDetailsNode:XML = xmlResultNode.Details[0];
outputInfo.text = _xmlResult.toXMLString();
_sPlace = xmlResultNode.PlaceName.text() + ", " + xmlResultNode.StateCode.text();
_xlDayData = xmlDetailsNode.WeatherData;
CursorManager.removeBusyCursor();
}//onResult
/** labelFunction for DataGrid. It seems that the namespace on the xml makes
* using the DataGridColumn dataField not work. At least I couldn't get it to work. */
private function lfDayData(oItem:Object, dgc:DataGridColumn):String
{
var sReturn:String = "";
var xmlItem:XML = XML(oItem); //get the item object cast as an xml object
var sHeaderText:String = dgc.headerText; //get the header text for this column
switch (sHeaderText) //logic to determine which node to get the data from
{
case "Day":
sReturn = xmlItem.Day.text();
break;
case "High":
sReturn = xmlItem.MaxTemperatureF.text();
break;
case "Low":
sReturn = xmlItem.MinTemperatureF.text();
break;
}
return sReturn;
}
]]>
</mx:Script>
<mx:WebService id="WS" wsdl="http://www.webservicex.net/WeatherForecast.asmx?WSDL"
useProxy="false"
fault="Alert.show(event.fault.faultString), 'Error'"
result="onResult(event)" >
<mx:operation name="GetWeatherByZipCode" resultFormat="e4x" >
<mx:request>
<ZipCode>{zipcode.text}</ZipCode>
</mx:request>
</mx:operation>
</mx:WebService>
<mx:Panel title="WebService Example" height="75%"
paddingTop="10" paddingBottom="10" paddingLeft="10" paddingRight="10" id="myPanel">
<mx:TextArea x="200" width="400" height="250" id="outputInfo" />
<mx:HBox>
<mx:Label width="100%" color="blue"
text="Enter a zip code."/>
<mx:TextInput id="zipcode" text="30117"/>
<mx:Button label="Get weather" click="getWeather()"/>
</mx:HBox>
<mx:Text id="txtPlace" htmlText="{_sPlace}"/>
<mx:DataGrid dataProvider="{_xlDayData}" height="180">
<mx:columns>
<mx:DataGridColumn labelFunction="lfDayData" headerText="Day" width="200" />
<mx:DataGridColumn labelFunction="lfDayData" headerText="High" width="100" />
<mx:DataGridColumn labelFunction="lfDayData" headerText="Low" width="100" />
</mx:columns>
</mx:DataGrid>
</mx:Panel>
</mx:Application>
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns="*"
creationComplete="getWeather()" >
<mx:Script>
<![CDATA[
import mx.controls.dataGridClasses.DataGridColumn;
import mx.rpc.events.ResultEvent;
import mx.managers.CursorManager;
import mx.controls.Alert;
default xml namespace = "http://www.webservicex.net"; //necessary to access the xml elements easily
[Bindable]private var _xmlResult:XML; //holds the result xml
[Bindable]private var _xlDayData:XMLList; //dataProvider for the day weather dataGrid
[Bindable]private var _sPlace:String;
/** invokes the web service operation to get the weather */
private function getWeather():void
{
CursorManager.setBusyCursor();
WS.GetWeatherByZipCode.send();
}
/** called by the WebService result event. Sets the dataProviders as necessary */
private function onResult(oEvent:ResultEvent):void
{
_xmlResult = XML(oEvent.result);
var xmlResultNode:XML = _xmlResult.GetWeatherByZipCodeResult[0];
var xmlDetailsNode:XML = xmlResultNode.Details[0];
outputInfo.text = _xmlResult.toXMLString();
_sPlace = xmlResultNode.PlaceName.text() + ", " + xmlResultNode.StateCode.text();
_xlDayData = xmlDetailsNode.WeatherData;
CursorManager.removeBusyCursor();
}//onResult
/** labelFunction for DataGrid. It seems that the namespace on the xml makes
* using the DataGridColumn dataField not work. At least I couldn't get it to work. */
private function lfDayData(oItem:Object, dgc:DataGridColumn):String
{
var sReturn:String = "";
var xmlItem:XML = XML(oItem); //get the item object cast as an xml object
var sHeaderText:String = dgc.headerText; //get the header text for this column
switch (sHeaderText) //logic to determine which node to get the data from
{
case "Day":
sReturn = xmlItem.Day.text();
break;
case "High":
sReturn = xmlItem.MaxTemperatureF.text();
break;
case "Low":
sReturn = xmlItem.MinTemperatureF.text();
break;
}
return sReturn;
}
]]>
</mx:Script>
<mx:WebService id="WS" wsdl="http://www.webservicex.net/WeatherForecast.asmx?WSDL"
useProxy="false"
fault="Alert.show(event.fault.faultString), 'Error'"
result="onResult(event)" >
<mx:operation name="GetWeatherByZipCode" resultFormat="e4x" >
<mx:request>
<ZipCode>{zipcode.text}</ZipCode>
</mx:request>
</mx:operation>
</mx:WebService>
<mx:Panel title="WebService Example" height="75%"
paddingTop="10" paddingBottom="10" paddingLeft="10" paddingRight="10" id="myPanel">
<mx:TextArea x="200" width="400" height="250" id="outputInfo" />
<mx:HBox>
<mx:Label width="100%" color="blue"
text="Enter a zip code."/>
<mx:TextInput id="zipcode" text="30117"/>
<mx:Button label="Get weather" click="getWeather()"/>
</mx:HBox>
<mx:Text id="txtPlace" htmlText="{_sPlace}"/>
<mx:DataGrid dataProvider="{_xlDayData}" height="180">
<mx:columns>
<mx:DataGridColumn labelFunction="lfDayData" headerText="Day" width="200" />
<mx:DataGridColumn labelFunction="lfDayData" headerText="High" width="100" />
<mx:DataGridColumn labelFunction="lfDayData" headerText="Low" width="100" />
</mx:columns>
</mx:DataGrid>
</mx:Panel>
</mx:Application>
Sunday, November 22, 2009
Flex and SOAP
Its always fun to work with Web service in Flex. Those pesky headers! Found a couple of terrific links on the subject. Now its easy :-)
http://www.actionscript.org/forums/showthread.php3?t=195916&highlight=e4x+faq
http://craigkaminsky.blogspot.com/2009/05/flex-3-make-net-namespaces-in-soap-xml.html
Just to put some code behind this....
Here is part of the feed:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<feed xml:base="http://www.placespr.com/WebDataService1.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
<title type="text">ptg_categories</title>
<id>http://www.placespr.com/webdataservice1.svc/ptg_categories</id>
<updated>2009-11-22T15:26:36Z</updated>
<link rel="self" title="ptg_categories" href="ptg_categories" />
<entry>
<id>http://www.placespr.com/WebDataService1.svc/ptg_categories(1)</id>
<title type="text" />
<updated>2009-11-22T15:26:36Z</updated>
<author>
<name />
</author>
<link rel="edit" title="ptg_categories" href="ptg_categories(1)" />
<category term="ponce_1000Model.ptg_categories" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:cat_id m:type="Edm.Int32">1</d:cat_id>
<d:name m:null="true" />
<d:service>hotels.asmx</d:service>
<d:icon>/images/icons/hotels.gif</d:icon>
<d:ordering m:type="Edm.Int32">1</d:ordering>
<d:counting m:type="Edm.Int32">75</d:counting>
</m:properties>
</content>
</entry>
......
and here is the modified code from these excellent links:
private function getCategoriesResult(evt:ResultEvent):void {
var respXML:XML = evt.result as XML;
var xmlSource:String = respXML.toXMLString();
//Strip off the headers
xmlSource = xmlSource.replace(/<[^!?]?[^>]+?>/g, removeNamspaces); // will invoke the function detailed below
var cleanXML:XML = XML(xmlSource);
for each( var item:XML in cleanXML.entry ) // looping over the reportHistory elements to act on them
{
trace( "name: " + item.content.properties.service);
}
}
// Web service response cleaner function
private function removeNamspaces(...rest):String
{
rest[0] = rest[0].replace(/xmlns[^"]+\"[^"]+\"/g, "");
var attrs:Array = rest[0].match(/\"[^"]*\"/g);
rest[0] = rest[0].replace(/\"[^"]*\"/g, "%attribute value%");
rest[0] = rest[0].replace(/(<\/?|\s)\w+\:/g, "$1");
while (rest[0].indexOf("%attribute value%") > 0)
{
rest[0] = rest[0].replace("%attribute value%", attrs.shift());
}
return rest[0];
}
http://www.actionscript.org/forums/showthread.php3?t=195916&highlight=e4x+faq
http://craigkaminsky.blogspot.com/2009/05/flex-3-make-net-namespaces-in-soap-xml.html
Just to put some code behind this....
Here is part of the feed:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<feed xml:base="http://www.placespr.com/WebDataService1.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
<title type="text">ptg_categories</title>
<id>http://www.placespr.com/webdataservice1.svc/ptg_categories</id>
<updated>2009-11-22T15:26:36Z</updated>
<link rel="self" title="ptg_categories" href="ptg_categories" />
<entry>
<id>http://www.placespr.com/WebDataService1.svc/ptg_categories(1)</id>
<title type="text" />
<updated>2009-11-22T15:26:36Z</updated>
<author>
<name />
</author>
<link rel="edit" title="ptg_categories" href="ptg_categories(1)" />
<category term="ponce_1000Model.ptg_categories" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:cat_id m:type="Edm.Int32">1</d:cat_id>
<d:name m:null="true" />
<d:service>hotels.asmx</d:service>
<d:icon>/images/icons/hotels.gif</d:icon>
<d:ordering m:type="Edm.Int32">1</d:ordering>
<d:counting m:type="Edm.Int32">75</d:counting>
</m:properties>
</content>
</entry>
......
and here is the modified code from these excellent links:
private function getCategoriesResult(evt:ResultEvent):void {
var respXML:XML = evt.result as XML;
var xmlSource:String = respXML.toXMLString();
//Strip off the headers
xmlSource = xmlSource.replace(/<[^!?]?[^>]+?>/g, removeNamspaces); // will invoke the function detailed below
var cleanXML:XML = XML(xmlSource);
for each( var item:XML in cleanXML.entry ) // looping over the reportHistory elements to act on them
{
trace( "name: " + item.content.properties.service);
}
}
// Web service response cleaner function
private function removeNamspaces(...rest):String
{
rest[0] = rest[0].replace(/xmlns[^"]+\"[^"]+\"/g, "");
var attrs:Array = rest[0].match(/\"[^"]*\"/g);
rest[0] = rest[0].replace(/\"[^"]*\"/g, "%attribute value%");
rest[0] = rest[0].replace(/(<\/?|\s)\w+\:/g, "$1");
while (rest[0].indexOf("%attribute value%") > 0)
{
rest[0] = rest[0].replace("%attribute value%", attrs.shift());
}
return rest[0];
}
Labels:
ESRI arcmap flex api,
headers,
web service,
XML
Tuesday, November 17, 2009
IE8 Vista Problem
I'll not br rotten about Microsoft, since I develop on Windows .. but sometimes!!
I found I could not open IE, out of the blue. Spent a frustrating couple of hours troubleshooting. All to do with security updates and IE settins. The solution which worked of me is as follows:
Open internet explorer and go to menu TOOLS, than to INTERNET OPTIONS. Open the CONNECTION tab,and click on SETTINGS. You then uncheck the 'use of proxy server for this connection' and click ok .
I found I could not open IE, out of the blue. Spent a frustrating couple of hours troubleshooting. All to do with security updates and IE settins. The solution which worked of me is as follows:
Open internet explorer and go to menu TOOLS, than to INTERNET OPTIONS. Open the CONNECTION tab,and click on SETTINGS. You then uncheck the 'use of proxy server for this connection' and click ok .
Sunday, November 15, 2009
AlivePDF
Its been a hectic time with project work. Much to share particularly with regards the ArcGIS Flex API and the open source OpenScales Flex library.
Just a quick mention today on AlivePDF. Historically, I've had to generate PDF's in PHP. AlivePDF is based on the PHP library FPDF. It makes generating PDF's from Flex very straighforward. Alex Britez has written a simple example here.
Just a quick mention today on AlivePDF. Historically, I've had to generate PDF's in PHP. AlivePDF is based on the PHP library FPDF. It makes generating PDF's from Flex very straighforward. Alex Britez has written a simple example here.
Labels:
AlivePDF,
ArcGIS API,
Flex,
maps,
OpenScales
Saturday, October 17, 2009
Open Source GIS Clients
I have had a number of companies recently approach me about open source GIS options. This has something to do with my recently published articles. One interesting area has been an investigation into Flex GIS clients. Openlayers is the premier Web 2.0 GIS client; well supported, a rich library filled with an array of functionality .. but written in Javascript. Now I have nothing against Javascript, its free, has a big community behind it and runs in the browser. But I'm a Flex developer. I prefer it because .. it has an excellent IDE which makes for easy debugging, developing sophisticated interactive application is both quick and easy, applications run the same in all browsers, actionscript is object oriented. Actionscript is just nicer and easier to work with .. in my view.
So enough. Anybody who argues against these opinions I would not oppose. Its just how I feel about it. Anyway, the whole Flex GIS open source client issue. I have worked with Modest Maps for sometime now to develop mostly consumer maps. Stop right there! Consumer maps? The world of online maps remains somewhat split. GIS maps and consumer maps. Consumer maps I define as the use of basemaps - tiles which are derived from satellite images or vector road maps for example - to build mash ups; video, imagery, text using, often, the addition of map markers for access (or clickable icons geospatially placed on the map). Here is a simple example. Google, Yahoo, Bing, mapquest offer largely API's for developing consumer maps.
So what are online GIS maps. A simple question? Well maybe. GIS has moved from the desktop to the Web. It was very much a niche market. Geography type nerds generating applications and analyses in large part for government (a generalisation but close to reality). The frustration for GIS vendors was how do they broaden the market. ESRI and the other key private vendors struggled to sell into the enterprise. They still do in fact.
Suddenly google maps arrived on the scene. It shook the mapping industry to its core. Internet maps were everywhere. Its worth noting that Mapquest preceded Google, but the fanfare (and $) waited for Googles arrival. Suddenly the other GIS vendors needed to react. ESRI produced rival online products. But with a GIS twist.
So here we are today. A plethora of consumer map APIs. And ESRI sitting in a somewhat awkward position offering free API's hooking easily into their own server product(s) ArcGIS (not so easily into other providers). Offering consumer and GIS API functionality. With a focus to sell their complete stack to those interested. Their purpose is to make money.
So how about those of us wanting to build online GIS maps, but avoid the high cost of the private vendor solutions? The open source GIS stack is very mature. But how about Flex clients?
I've spent some time looking at the options. Base requirements include:
- Rendering both WFS and WMS in combination
- Overlays of these services on various basemaps
- Drawing tools for line point and polygons
- Identify functionality
I looked at both Modest Maps and OpenScales. Though not its focus there has been some work done on Modest Maps toward some level of interaction with spatial servers. I added a WMS layer at:
http://www.flexmappers.com/mapserving/mapservingWMS/
Note, I had to make some tweeks to the WMS provider, provided with the library.
Openscales is less mature. But very impressive for how long development has been underway. I built the following map application:
http://www.flexmappers.com/mapserving/openscales.html
It supplies much of the base functionality I was looking to include. WMS is proving a little challenging (but i suspect a style tag is mssing from the tile request) and the map interaction is not a smooth as Modest maps. Only openstreetmap is provided, but I am looking to port code from Modest maps to add this functionality.
Ultimately Flex should simply be rendering the points, lines, and polygons supplied by the server.
I am interested to see how easy it might be to port from one library to the other. Either way, Openscales is a very interesting project. One well worth supporting.
So enough. Anybody who argues against these opinions I would not oppose. Its just how I feel about it. Anyway, the whole Flex GIS open source client issue. I have worked with Modest Maps for sometime now to develop mostly consumer maps. Stop right there! Consumer maps? The world of online maps remains somewhat split. GIS maps and consumer maps. Consumer maps I define as the use of basemaps - tiles which are derived from satellite images or vector road maps for example - to build mash ups; video, imagery, text using, often, the addition of map markers for access (or clickable icons geospatially placed on the map). Here is a simple example. Google, Yahoo, Bing, mapquest offer largely API's for developing consumer maps.
So what are online GIS maps. A simple question? Well maybe. GIS has moved from the desktop to the Web. It was very much a niche market. Geography type nerds generating applications and analyses in large part for government (a generalisation but close to reality). The frustration for GIS vendors was how do they broaden the market. ESRI and the other key private vendors struggled to sell into the enterprise. They still do in fact.
Suddenly google maps arrived on the scene. It shook the mapping industry to its core. Internet maps were everywhere. Its worth noting that Mapquest preceded Google, but the fanfare (and $) waited for Googles arrival. Suddenly the other GIS vendors needed to react. ESRI produced rival online products. But with a GIS twist.
So here we are today. A plethora of consumer map APIs. And ESRI sitting in a somewhat awkward position offering free API's hooking easily into their own server product(s) ArcGIS (not so easily into other providers). Offering consumer and GIS API functionality. With a focus to sell their complete stack to those interested. Their purpose is to make money.
So how about those of us wanting to build online GIS maps, but avoid the high cost of the private vendor solutions? The open source GIS stack is very mature. But how about Flex clients?
I've spent some time looking at the options. Base requirements include:
- Rendering both WFS and WMS in combination
- Overlays of these services on various basemaps
- Drawing tools for line point and polygons
- Identify functionality
I looked at both Modest Maps and OpenScales. Though not its focus there has been some work done on Modest Maps toward some level of interaction with spatial servers. I added a WMS layer at:
http://www.flexmappers.com/mapserving/mapservingWMS/
Note, I had to make some tweeks to the WMS provider, provided with the library.
Openscales is less mature. But very impressive for how long development has been underway. I built the following map application:
http://www.flexmappers.com/mapserving/openscales.html
It supplies much of the base functionality I was looking to include. WMS is proving a little challenging (but i suspect a style tag is mssing from the tile request) and the map interaction is not a smooth as Modest maps. Only openstreetmap is provided, but I am looking to port code from Modest maps to add this functionality.
Ultimately Flex should simply be rendering the points, lines, and polygons supplied by the server.
I am interested to see how easy it might be to port from one library to the other. Either way, Openscales is a very interesting project. One well worth supporting.
Labels:
ESRI arcmap flex api,
GIS,
Modest Maps,
open source,
OpenLayers,
OpenScales
Sunday, October 11, 2009
Flex and PHP POST
I always forget the syntax when trying to get around the Flex sandbox and use PHP. On the Flex side we need the following:
[Bindable]private var pr_url:String;
..
private function init():void
{
..
pr_url = "url to SOAP service for example";
pr.send();
}
..
<mx:HTTPService id="pr" resultFormat="e4x" result="getMonths_result(event);" fault="getMonths_fault(event);" method="POST" url="http://www.flexmappers.com/puertorico/test.php">
<mx:request xmlns="">
<url>
{pr_url}
</url>
</mx:request>
</mx:HTTPService>
On the PHP side:
<?php
header('Content-Type: text/xml');
$url = $_POST["url"];
$data = file_get_contents($url);
echo $data;
?>
[Bindable]private var pr_url:String;
..
private function init():void
{
..
pr_url = "url to SOAP service for example";
pr.send();
}
..
<mx:HTTPService id="pr" resultFormat="e4x" result="getMonths_result(event);" fault="getMonths_fault(event);" method="POST" url="http://www.flexmappers.com/puertorico/test.php">
<mx:request xmlns="">
<url>
{pr_url}
</url>
</mx:request>
</mx:HTTPService>
On the PHP side:
<?php
header('Content-Type: text/xml');
$url = $_POST["url"];
$data = file_get_contents($url);
echo $data;
?>
Subscribe to:
Posts (Atom)