import flash.geom.Point; import flash.geom.Rectangle; import flash.display.BitmapData; import flash.filters.BlurFilter; import flash.filters.ColorMatrixFilter; class Parcels { public static var root:MovieClip; public static var detail:TextField; public static var parcels:BitmapData; public static var render:BitmapData; public static var focus:BitmapData; public static var blur:BitmapData; public static var lastColor:Number; public static function main(mc:MovieClip):Void { root = mc; parcels = new BitmapData(Stage.width, Stage.height, false, 0x000000); root.attachBitmap(parcels, root.getNextHighestDepth()); render = new BitmapData(Stage.width, Stage.height, false, 0x000000); root.attachBitmap(render, root.getNextHighestDepth()); blur = new BitmapData(Stage.width, Stage.height, true, 0xFF0000); root.attachBitmap(blur, root.getNextHighestDepth()); focus = new BitmapData(Stage.width, Stage.height, true, 0xFF0000); root.attachBitmap(focus, root.getNextHighestDepth()); init(); } public static function init():Void { if(true) { // perspective var parcelsLoader:MovieClipLoader = new MovieClipLoader(); parcelsLoader.addListener({onLoadInit: onParcelsLoaded}); parcelsLoader.loadClip('downtownParcelCodedPersp.png', root.createEmptyMovieClip('parcelsTmp', root.getNextHighestDepth())); var renderLoader:MovieClipLoader = new MovieClipLoader(); renderLoader.addListener({onLoadInit: onRenderLoaded}); renderLoader.loadClip('downtownPersp.jpg', root.createEmptyMovieClip('renderTmp', root.getNextHighestDepth())); } else { // flat var parcelsLoader:MovieClipLoader = new MovieClipLoader(); parcelsLoader.addListener({onLoadInit: onParcelsLoaded}); parcelsLoader.loadClip('downtownParcelCoded.png', root.createEmptyMovieClip('parcelsTmp', root.getNextHighestDepth())); var renderLoader:MovieClipLoader = new MovieClipLoader(); renderLoader.addListener({onLoadInit: onRenderLoaded}); renderLoader.loadClip('downtownAerial.jpg', root.createEmptyMovieClip('renderTmp', root.getNextHighestDepth())); } root.onMouseMove = showParcelInfo; root.onMouseUp = getParcelDetails; } public static function onParcelsLoaded(clip:MovieClip):Void { if(parcels) parcels.draw(clip); clip.removeMovieClip(); Stage.align = 'TL'; Stage.scaleMode = 'noScale'; } public static function onRenderLoaded(clip:MovieClip):Void { if(render) render.draw(clip); blur.applyFilter(render, new Rectangle(0, 0, render.width, render.height), new Point(0, 0), new BlurFilter(3, 3, 6)); var matrix:Array = new Array(); matrix = matrix.concat([.9, 0, 0, 0, 0]); // red matrix = matrix.concat([0, .9, 0, 0, 0]); // green matrix = matrix.concat([0, 0, .9, 0, 0]); // blue matrix = matrix.concat([0, 0, 0, 1, 0]); // alpha blur.applyFilter(blur, new Rectangle(0, 0, render.width, render.height), new Point(0, 0), new ColorMatrixFilter(matrix)); clip.removeMovieClip(); } public static function parcelInfoFromColor(color:Number):String { var lot:String = color.toString(10).slice(-3); var block:String = color.toString(10).slice(0, -3); while(block.length < 5) block = '0'+block; if(lot == '000') return 'Block '+block; return 'Block '+block+', Lot '+lot; } public static function parcelUrlFromColor(color:Number):String { var lot:String = color.toString(10).slice(-3); var block:String = color.toString(10).slice(0, -3); while(block.length < 4) block = '0'+block; if(lot == '000') return 'http://gispubweb.sfgov.org/website/sfparcel/getblock.asp?blockid='+block; //return 'http://gispub02.sfgov.org/assessorblocks/block'+block+'.pdf'; //return 'http://gispub02.sfgov.org/website/sfparcel/showlotinfo.asp?LotIDValue='+block+lot; return 'http://gispubweb.sfgov.org/website/sfparcel/showlotinfo.asp?LotIDValue='+block+lot; } public static function getPixelColor():Number { return parcels.getPixel(root._xmouse, root._ymouse); } public static function focusOnParcel(color:Number):Void { if(color != lastColor) { var bounds:Rectangle = parcels.getColorBoundsRect(0x00FFFFFF, parcels.getPixel(root._xmouse, root._ymouse)); // fuzzy edges for mask var gutter:Number = 5; var maskBlur:BlurFilter = new BlurFilter(gutter, gutter, 1); var mask:BitmapData = new BitmapData(bounds.width+2*gutter, bounds.height+2*gutter, true, 0x00000000); for(var x:Number = 0; x < bounds.width; x += 1) for(var y:Number = 0; y < bounds.height; y += 1) if(parcels.getPixel(x+bounds.left, y+bounds.top) == color) mask.setPixel32(x+gutter, y+gutter, 0xFF000000); // blur the mask mask.applyFilter(mask, new Rectangle(0, 0, bounds.width+2*gutter, bounds.height+2*gutter), new Point(0, 0), maskBlur); // clear previous focus and copy focused pixels with a blurry mask focus.fillRect(new Rectangle(0, 0, parcels.width, parcels.height), 0x00000000); focus.copyPixels(render, new Rectangle(bounds.left-gutter, bounds.top-gutter, bounds.width+2*gutter, bounds.height+2*gutter), new Point(bounds.left-gutter, bounds.top-gutter), mask, new Point(0, 0)); lastColor = color; } } public static function showParcelInfo():Void { if(!detail) { detail = root.createTextField('detail', root.getNextHighestDepth(), 0, 0, 100, 100); detail.embedFonts = false; detail.selectable = false; detail.background = true; detail.border = true; } var pixel:Number = getPixelColor(); if(pixel) { focusOnParcel(pixel); detail.text = parcelInfoFromColor(pixel); //+' ('+(pixel>>16 & 0xFF).toString(10)+', '+(pixel>>8 & 0xFF).toString(10)+', '+(pixel & 0xFF).toString(10)+')'; detail._width = detail.textWidth + 6; detail._height = detail.textHeight + 4; detail._x = root._xmouse - detail._width - 20; detail._y = root._ymouse - detail._height - 20; if(detail._x < 0) detail._x = root._xmouse; if(detail._y < 0) detail._y = root._ymouse + 16; detail._x = 10; detail._y = 10; detail._visible = true; } else { detail._visible = false; } } public static function getParcelDetails():Void { var pixel:Number = getPixelColor(); if(pixel) getURL(parcelUrlFromColor(pixel), '_blank'); } }