/**
* Example application of the NoncontiguousCartogram class.
* Shows how to use WKT strings to set the centers of cartogram features.
*
* By Zachary Forest Johnson
* indiemaps.com/blog
*
*/
package
{
import com.bit101.components.HUISlider;
import com.bit101.components.Label;
import com.bit101.components.Text;
import com.indiemaps.mapping.cartograms.noncontiguous.NoncontiguousCartogram;
import com.indiemaps.mapping.cartograms.utils.CartogramUtils;
import com.indiemaps.mapping.projections.LambertConformalConic;
import com.indiemaps.mapping.utils.ShpDbfLoader;
import com.indiemaps.mapping.utils.WKTUtils;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.utils.Dictionary;
[SWF(backgroundColor='#cccccc', width='800', height='450')]
public class ManualCartogramTest extends Sprite
{
protected var shapefileLocation:String = 'data/shp/STATES2';
protected var attributeField:String = 'AGE_65_UP';
protected var anchorPercentile:Number = .85;
protected var maxWidthOfCartogram:Number = 350;
protected var maxHeightOfCartogram:Number = 400;
protected var combinedArrayForCartogram:Array = [];
protected var interactiveCartogram:NoncontiguousCartogram;
protected var tweeningCartogram:NoncontiguousCartogram;
protected var cartogramContainer:Sprite = new Sprite();
protected var interfaceContainer:Sprite = new Sprite();
protected var dragginFeature:Sprite = null;
protected var wktTextDisplay:Text;
protected var hingeDensitySlider:HUISlider;
public function ManualCartogramTest()
{
var shpDbfLoader:ShpDbfLoader = new ShpDbfLoader(shapefileLocation + '.shp', shapefileLocation + '.dbf');
shpDbfLoader.addEventListener(ShpDbfLoader.DATA_LOADED, onShpDbfDataLoaded);
cartogramContainer.y = 150;
cartogramContainer.x = 10;
addChild(cartogramContainer);
createInterface();
addChild(interfaceContainer);
}
protected function createInterface():void {
new Label(interfaceContainer, 10, 5, "State centers Well Known Text representation:");
wktTextDisplay = new Text(interfaceContainer, 10, 30);
wktTextDisplay.width = 780;
wktTextDisplay.height = 70;
hingeDensitySlider = new HUISlider(interfaceContainer, 200, 420, "Anchor density percentile", onSliderChange);
hingeDensitySlider.width = 400;
new Label(interfaceContainer, 140, 125, "move these states around");
}
protected function onSliderChange(event:Event):void {
interactiveCartogram.anchorPercentile = (event.target as HUISlider).value;
tweeningCartogram.anchorPercentile = (event.target as HUISlider).value;
}
public function getFeatureCentersArray():Array {
var featureCenters:Array = [];
for each (var featureObject:Object in combinedArrayForCartogram) {
featureCenters.push(new Point((interactiveCartogram.featureGraphics[featureObject] as Sprite).x, (interactiveCartogram.featureGraphics[featureObject] as Sprite).y));
}
return featureCenters;
}
protected function onShpDbfDataLoaded(e:Event):void {
var shpDbfLoader:ShpDbfLoader = e.target as ShpDbfLoader;
combinedArrayForCartogram = CartogramUtils.createCombinedArrayFromShpDbf(shpDbfLoader.shpRecords, shpDbfLoader.dbfRecords, multiPolygonConversionFunction);
CartogramUtils.removeObjectsFromCombinedArray(combinedArrayForCartogram, 'STATE_NAME', 'Hawaii', 'attributes');
CartogramUtils.removeObjectsFromCombinedArray(combinedArrayForCartogram, 'STATE_NAME', 'Alaska', 'attributes');
createCartogram();
makeCartogramInteractive();
wktTextDisplay.text = WKTUtils.createWKTMultiPointFromArray(getFeatureCentersArray());
}
protected function makeCartogramInteractive():void {
for each (var featureObject:Object in combinedArrayForCartogram) {
(interactiveCartogram.featureGraphics[featureObject] as Sprite).buttonMode = true;
(interactiveCartogram.featureGraphics[featureObject] as Sprite).addEventListener(MouseEvent.MOUSE_DOWN, onFeatureMouseDown);
}
}
protected function onFeatureMouseDown(e:MouseEvent):void {
(e.currentTarget as Sprite).startDrag();
dragginFeature = e.currentTarget as Sprite;
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
protected function onMouseUp(e:MouseEvent):void {
dragginFeature.stopDrag();
dragginFeature = null;
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
updateCenters();
}
protected function updateCenters():void {
wktTextDisplay.text = WKTUtils.createWKTMultiPointFromArray(getFeatureCentersArray());
tweeningCartogram.featureCenters = getFeatureCentersDictionary();
}
protected function getFeatureCentersDictionary():Dictionary {
var featureCentersArray:Array = WKTUtils.createArrayFromWKTMultiPoint(wktTextDisplay.text);
var featureCentersDictionary:Dictionary = new Dictionary();
for (var featureNum:Object in combinedArrayForCartogram) {
featureCentersDictionary[combinedArrayForCartogram[featureNum]] = featureCentersArray[featureNum];
}
return featureCentersDictionary;
}
protected function createCartogram():void {
interactiveCartogram = new NoncontiguousCartogram(combinedArrayForCartogram, maxWidthOfCartogram, maxHeightOfCartogram, attributeField, anchorPercentile, { fillColor : 0x0099cc, strokeColor : 0xffffff }, false);
tweeningCartogram = new NoncontiguousCartogram(combinedArrayForCartogram, maxWidthOfCartogram, maxHeightOfCartogram, attributeField, anchorPercentile, { fillColor : 0, strokeColor : 0xffffff }, true);
cartogramContainer.addChild(interactiveCartogram);
cartogramContainer.addChild(tweeningCartogram);
tweeningCartogram.x = 400;
tweeningCartogram.tweenDuration = .5;
initializeHingeDensitySlider();
}
protected function multiPolygonConversionFunction(multiPolygon:Array):Array {
var standardParallel1_degrees:Number = 33;
var standardParallel2_degrees:Number = 45;
var latitudeOrigin_degrees:Number = 23;
var longitudeOrigin_degrees:Number = -96;
var geometry:Array = LambertConformalConic.projectMultiPolygon(multiPolygon, NaN, NaN, NaN, NaN, standardParallel1_degrees, standardParallel2_degrees, latitudeOrigin_degrees, longitudeOrigin_degrees);
return geometry;
}
protected function initializeHingeDensitySlider():void {
hingeDensitySlider.maximum = 1;
hingeDensitySlider.minimum = 0;
hingeDensitySlider.value = interactiveCartogram.anchorPercentile;
}
}
}