All 3rd party libraries are included in the package, nothing else needs
to be downloaded.
The code was developed using Flex Builder 3. Simply import the entire archive
as a project.
The base Flex SDK version is 3.2, but it should work with any later 3.x Flex release.
Flex Open Source SDK
The build has been tested with version 3.5a of the Open Source Flex SDK. It
can be downloaded here: http://opensource.adobe.com/wiki/display/flexsdk/Download+Flex+3
Download the appropriate zipfile and unpack it. You may need to change
the protections on the binaries so that they are executable:
- cd <sdkdir>/bin
- chmod +x *
You will also need a recent version of Apache Ant, and a Java runtime environment.
Edit the build.properties file to point to the SDK.
To build a debug version:
- ant debug
Output is placed in the output.debug directory.
To build for release (optimised, no debug):
- ant release
Output is placed in the output.release directory.
The client must be run from within a webserver, both for testing and for deployment.
Mac OS X contains a built-in webserver. Simply enable it from System Preferences/Sharing,
and copy the output.debug/output.release files into the your Sites directory.
If you are using Linux, please see your local documentation (or use Google) for information
on how to enable the Apache webserver.
Windows users should use Google to find out how to install a local webserver.
Adobe corelib: https://github.com/mikechambers/as3corelib
AS3 data structures: http://lab.polygonal.de/ds/
The current versions of some of the above packages may be more recent
than those included in the package.
Template files for the installation live in the toplevel html-template
PureMVC is the glue that holds the application together.
PureMVC nomenclature is a little different from standard MVC.
Views are still the actual components that draw on the glass.
However, in PureMVC, models are called Proxies, and controllers
are called Mediators.
User events are caught within views, and these generate
application events which are picked up by mediators.
Mediators then call proxies to change/retrieve state.
When proxy states change, they send notifications which
are picked up by mediators, which then update views
Mediators need to know about their proxies and views,
but views and proxies don't need to know about each
State changes are often communicated through the use of Notifications.
These are named events which can carry data. Mediators typically
register their interest in a number of different notifications, which
can come from proxies or other mediators.
The Command class is a way to package up application logic
into a self-contained way that coordinates the work of other
objects. Commands can also be linked to notifications, ie,
a notification can cause a Command to be executed.
If a state change in a proxy needs to be picked by multiple
mediators, then it's generally better to use a Command: the
Command is able to synchronise changes in a controlled way.
The Facade is responsible for managing all these classes,
and for routing notifications around the system. This is the
first object created.
All proxies and mediators are effectively singletons, ie,
we don't create multiple copies of them.
charts - charting code
charts/bubblechart - bubble chart
charts/include - AS3 source for MXML components
commands - application Commands
components - various UI components
components/include - AS3 source for MXML components
data - data handling
events - application event classes
include - AS3 source for WDMMG component
mediators - application Mediators
proxies - application Proxies
uk - legacy UK/COFOG definitions
views - individual views
views/commands - view commands
views/components - view subcomponents
views/events - view event classes
views/include - AS3 source for view components
views/mediators - view Mediators
views/proxies - view Proxies
The toplevel main.mxml simply loads the WDMMG component from
com/iconomical/wdmmg. The main role of WDMMG is to provide
an overall screen layout, and to start up the application
by creating the facade, WDMMGFacade. Most of the facade's
job is done in the Facade superclass. The WDMMGFacade itself is
used to register and call the initial application-specific
The surrounding HTML must pass an 'assets' parameter to the
application on startup. This is read by StartupCommand,
and tells the application where to load all other asset
files, including the main dashboard-config.json file.
If this is not supplied, the 'assets/' directory is used.
StartupCommand then creates a number of startup proxies,
followed by the application mediator.
The main application mediator is WDMMGAppMediator. Its primary
job is to organise the startup sequence, and initialise
the interface once all config files and assets have been
loaded. It waits until it has received notifications from
the startup proxies, then executes InitialiseInterface.
- various proxies
ConfigProxy loads the dashboard-config file, and provides
access to the config data.
The config file format is described later in this document.
Apart from the long-term trends view, all data comes from
the data store.
Data query specification is largely parameterised through the
All numbers are in millions.
Data requests are made to a dataStore. Each data request
is identified by a name, and must specify a slice, and
the aggregation data keys to be retrieved.
In addition, the classification key names must be specified.
These allow the engine to retrieve more detailed information
about classification key values.
Currently, COFOG per-capita data by region is hardwired.
This is the only request where customised post-processing
is done, and until we have further examples, we can't
decide how to parameterise this.
DataStore is the class that deals directly with the
data store. DataStoreProxy provides the interface to the rest
of the application.
Data is received from the aggregator in table format. This is converted
into a more hierarchical structure for use elsewhere in the client.
Inside the client, data is collected into objects indexed by year.
Each year contains breakdowns by classification hierarchy.
Each classification level can contain further levels.
Non-data store requests are done through the DataManager class.
These are legacy requests for long-term time series data, and only
used by the long-term trends view.
User interface assets
Graphical assets are loaded through WDMMGAssetsProxy and
WDMMGAssetsProxy2, which are wrappers for WDMMGAssets
and WDMMGAssets2. Some older code might bypass the proxies.
Source files for the assets are in the toplevel assets directory.
These are .fla files, and have to be opened using Adobe Flash.
Each separate screen is a view, and they all live in the views
DailyBreadView: daily bread
LongTermFunctionalView: long term trends
LongTermSubfunctionalView: uk-wide bubble chart
NationalFunctionalView: nations stacked chart
NationalSubfunctionalView: nations bubble chart
RegionsFunctionalView: regional overview
RegionsSubfunctionsView: regional subfunctions
Each view has an MXML file, a proxy, and a mediator. MXML files use
source files from the include subdirectory.
Views are brought onto the screen by sending the appropriate
notification. This results in a Command being run - these are
all in the views/commands directory.
CurrentViewProxy keeps track which view is current. Each change-view
command works by changing the CurrentViewProxy state. CurrentViewProxy
then issues a notification, which is picked up by WDMMGViewsMediator.
WDMMGViewsMediator does the actual work of removing the old view
and organising the new one.
Each view is defined using an MXML file, which defines the overall layout.
Each MXML file includes an actionscript file, which contains the code for
View components are not available until its children are constructed. Each view
has a listener for the childrenCreated event. This listener notifies the mediator
that the view is now available, ie, that the mediator can invoke operations on
The mediator can only display data once the data itself is available, ie, when
the data has been received from the server. PESAViewMediator controls the
overall mediator startup through initialiseView(), and it invokes a method
called canInitialise(), which needs to be overridden in subclasses. If canInitialise()
returns true, then initialiseView() can draw the view.
The proxy for each view is responsible for obtaining the data. Each proxy has an
isDataReady() method, and this is normally called by each mediator's canInitialise()
method. If all the necessary data components are loaded, then isDataReady()
returns true. If the data is not yet available, then the data request calls have
the side effect of initialising the data loads.
Most of the plots are produced using an internal plotting framework.
Flare is used on only one view: long-term trends. We found that while Flare
is an excellent library for standalone visualisations, it wasn't best suited
for use in an embedded framework.
How to add another view
You need to create a number of new classes/files in the views directory:
- NewView.mxml (subclass of PESAView)
- mediators/NewViewMediator.as (subclass of PESAViewMediator)
- proxies/NewViewProxy.as (subclass of PESAViewProxy)
- views/NewViewCommand.as (subclass of ShowNewViewCommand)
Construct the user interface inside the NewView.mxml.
Define the communication between the view and the mediator. The view catches
the user events themselves, so define application-specific events which are
generated by the view, and caught by the mediator. The mediator drives the
view, so the view needs to provide access functions.
Define the communication between the mediator and the proxy. The proxy provides
the mediator with all of its data, so the proxy generally has to implement
get/set routines. Since this is largely an event-driven system and data might
not be immediately available, the proxy has to define notifications to indicate
data availability. The mediator has to register its interest in these notifications.
NewViewCommand must create the appropriate mediator type in the makeViewMediator
Register the NewViewCommand in mediators/WDMMGViewsMediator.
To hook the view into the legacy user interface, add a new button to any
of the ViewButtons components in views/components.
done by creating a function, and registering the function in registerCallbacks().
provides the interface to the rest of the application. Within this function,
There are numerous examples of both mechanisms in the class.
This is a JSON file. It describes a single dictionary of key/value pairs.
Values are strings unless otherwise noted.
This is the base URL for data store requests.
The default is http://data.wheredoesmymoneygo.org/
This is a more complicated structure. There are two required fields:
'classification' is an array of classification types, eg, cofog1. This is used
to obtain further data store information on the classifications.
'queries' is a map of query names to query specifications. Each specification is a
dictionary containing the following key/value pairs:
- slice (the name of the slice);
- dataKeys (ordered array of classification names);
- regionKey (optional classification key for regions);
- params (additional data store query parameters).
This is a largely ad-hoc structure, which is dictated by the varying
natures of the different views. Please see the toplevel flash/dashboard-config.json
for a complete example.
This is a dictionary of key/value strings pairs. The keys are classification identifiers,
eg, COFOG_1. The values are the names of icon assets in the WDMMGassets2.fla file.
This allows the developer to map arbitrary keys to reasonable icons throughout
If set to true, this disables the display of help text for spending classifications
within the application. Developers should handle this through the wdmmgInfobox call
This is a dictionary of classification key identifiers. Each identifier has
an array of strings denoting hex-encoded RGB colours, eg, 0x123456.
Classifications are considered to be hierarchical (eg, COFOG 1, 1.1, 1.1.1).
This string is displayed before currency values. The default is "£"
This string is displayed after currency values. The default is "".
The application provides an API to allow it to be
This allows the current view to be changed. Parameters can
also be provided.
focus (spending code, eg, 01.1 in cofog)
year (year text, eg, 2007-2008)
region (country names, spaces replaced with '-', entire uk is 'uk')
focus (spending code)
focus (spending code)
region (country names, spaces replaced with '-', entire uk is 'uk')
region (cofog region names, spaces replaced with '-')
filter (comma separated list of top-level spending codes)
focus (spending code)
code (toplevel classification code)
interesting (array of classification codes)
Remove the legacy header components.
Remove the legacy footer components.
Prevent the application from rewriting URLs as the
view is changed.
Called by the application when it is starting up.
removeHeader(), removeFooter() and disableUrls()
can be called here, but not changeView().
Called by the application when it is fully initialised,
ie, when the interface can be modified. changeView()
should not be called before wdmmgReady() is received.
wdmmgInfobox(code, classificationName, link)
Called by the application when the user wishes to see
more information on an item, and 'infoboxDisabled' has
been set to true in the config file.
Called by the application when a view changes. viewName
and params correspond to the changeView parameters.
Called by the application when the user clicks on a help button.
This is only enabled in the daily bread and long-term trends views.
The view names are 'daily-bread' and 'long-term'. For the long-term
view, the params contain an object specifying the view type, which
is either 'functions' or 'tme'.
Many things are not ideal. The project started as a very quick
and dirty prototype based around a non-homogeneous data set,
and there has been little opportunity to revisit or