After taking another look at this post, I came up with a way of making multiple windows that will all blur the same image. I have to admit, though, I’m not particularly fond nor proud of the way I did it. The trouble is this: a masked display object can only have a single mask – so all items which will be used as a mask must be added to a single encompassing parent. But you would also like each mask item to be draggable along with the window it “rides behind”. Therefore, ideally, you’d like each mask item to be a child of the window instance (as I did it in the previous post). But there lies the rub. A display object can have only a single parent, hence you can’t add the child to both the mask and the window.
The solution I came up with was this: add the masking item to the mask instance and move the masking item with the window using an ENTER_FRAME event (rather than a parent-child relationship). If anyone has a more elegant solution, please post a comment. I’m probably overlooking something simple, but brilliant…
The MWindowBlur (Multiple Window Blur) class:
package com.onebyonedesign.extras {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.events.Event;
import flash.filters.BlurFilter;
import flash.geom.Point;
import flash.utils.Dictionary;
/**
* Allows creation of multiple windows that blur the same background image
* @author Devon O.
*/
public class MWindowBlur {
private var _background:DisplayObjectContainer;
private var _blurData:BitmapData;
private var _blurImage:Bitmap;
private var _blurAmount:int;
private var _blur:BlurFilter;
private var _mask:Sprite = new Sprite();
private var _point:Point = new Point();
private var _windows:Array = [];
private var _maskDictionary:Dictionary = new Dictionary(true);
public function MWindowBlur(background:DisplayObjectContainer, blurAmount:int = 8) {
_background = background;
_blurAmount = (blurAmount >= 0 && blurAmount <= 255) ? blurAmount : 8;
_blur = new BlurFilter(_blurAmount, _blurAmount, 3);
createBlur();
}
public function addWindow(window:DisplayObjectContainer):Boolean {
if (_windows.indexOf(window) > -1) return false;
var WindowClass:Class = Object(window).constructor;
var m:DisplayObjectContainer = new WindowClass();
m.transform = window.transform;
m.filters = window.filters;
if (window.scale9Grid) {
m.scale9Grid = window.scale9Grid;
}
_maskDictionary[window] = m;
_windows.push(window);
if (!_mask.willTrigger(Event.ENTER_FRAME))
_mask.addEventListener(Event.ENTER_FRAME, moveMask);
_mask.addChild(m);
if (!_background.contains(_mask))
_background.addChild(_mask);
return true;
}
public function removeWindow(window:DisplayObjectContainer = null):Boolean {
if (!_windows.length) return false;
if (!window) return removeWindow(_windows[_windows.length - 1]);
var index:int = _windows.indexOf(window);
if (index < 0) return false;
_windows.splice(index, 1);
_mask.removeChild(_maskDictionary[window]);
if (!_windows.length)
_mask.removeEventListener(Event.ENTER_FRAME, moveMask);
return true;
}
public function kill():void {
if (_mask.willTrigger(Event.ENTER_FRAME))
_mask.removeEventListener(Event.ENTER_FRAME, moveMask);
if (_background.contains(_mask))
_background.removeChild(_mask);
if (_background.contains(_blurImage))
_background.removeChild(_blurImage);
_blurData.dispose();
_blurImage = null;
_blurData = null;
_maskDictionary = null;
_background = null;
_blur = null;
}
public function get blurAmount():int { return _blurAmount; }
public function set blurAmount(value:int):void {
_blurAmount = value;
createBlur();
}
private function createBlur():void {
if (_blurData) _blurData.dispose();
_blur.blurX = _blur.blurY = _blurAmount;
_blurData = new BitmapData(_background.width, _background.height, false);
_blurData.draw(_background);
_blurData.applyFilter(_blurData, _blurData.rect, _point, _blur);
_blurImage = new Bitmap(_blurData);
_blurImage.mask = _mask;
_background.addChild(_blurImage);
}
private function moveMask(event:Event):void {
var i:int = _windows.length;
while (i--) {
var w:DisplayObjectContainer = _windows[i];
var m:DisplayObjectContainer = _maskDictionary[w];
m.transform = w.transform;
}
}
}
}
The Flash document class for a test ride:
package {
import com.onebyonedesign.extras.MWindowBlur;
import com.onebyonedesign.ui.OBO_ValueSlider;
import com.onebyonedesign.ui.events.ValueSliderEvent;
import fl.controls.Button;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.filters.DropShadowFilter;
import flash.text.AntiAliasType;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
/**
* Demonstrates MWindowBlur (for multiple windows) Class
* @author Devon O.
*/
public class Main extends Sprite {
// GraphicWindow is MovieClip in .fla library
private var _activeWindow:GraphicWindow;
// Background is MovieClip in .fla library
private var _bg:Background;
private var _windowBlur:MWindowBlur;
private var _shadow:DropShadowFilter = new DropShadowFilter(2, 90, 0x000000, 1, 2, 2, 1, 3);
private var _windowArray:Array = [];
public function Main():void {
// Background is MovieClip in .fla library
_bg = new Background();
addChild(_bg);
init();
}
private function init():void {
initBlur();
initControlPanel();
addWindow();
}
private function initBlur():void {
_windowBlur = new MWindowBlur(_bg);
}
private function initControlPanel():void {
var cp:Sprite = new Sprite();
cp.graphics.beginFill(0xEAEAEA);
cp.graphics.drawRoundRect(0, 0, 222, 70, 10, 10);
cp.graphics.endFill();
cp.filters = [_shadow];
cp.x = 10;
cp.y = stage.stageHeight - cp.height - 10;
var tf:TextField = new TextField();
var fmt:TextFormat = new TextFormat("_sans", 11);
tf.defaultTextFormat = fmt;
tf.autoSize = TextFieldAutoSize.LEFT;
tf.selectable = false;
tf.mouseEnabled = false;
tf.antiAliasType = AntiAliasType.ADVANCED;
tf.text = "Blur amount:";
tf.x = 5;
tf.y = 5;
cp.addChild(tf);
var blurSlider:OBO_ValueSlider = new OBO_ValueSlider(139, 0, 32, _windowBlur.blurAmount);
blurSlider.x = tf.x + tf.textWidth + 8;
blurSlider.y = 13;
blurSlider.addEventListener(ValueSliderEvent.DRAG, blurChangeHandler);
cp.addChild(blurSlider);
var b1:Button = new Button();
b1.label = "Add Window";
b1.x = 5;
b1.y = 40;
b1.addEventListener(MouseEvent.CLICK, addWindow);
cp.addChild(b1);
var b2:Button = new Button();
b2.label = "Remove Window";
b2.x = b1.x + b1.width + 10;
b2.y = 40;
b2.addEventListener(MouseEvent.CLICK, removeWindow);
cp.addChild(b2);
addChild(cp);
}
private function addWindow(event:MouseEvent = null):void {
// GraphicWindow is MovieClip in library
var window:GraphicWindow = new GraphicWindow();
window.width = randRange(50, 300);
window.height = randRange(50, 200);
window.x = randRange(0, 500 - window.width);
window.y = randRange(0, 500 - window.height);
window.filters = [_shadow];
_windowArray.push(window);
addChild(window);
_windowBlur.addWindow(window);
window.addEventListener(MouseEvent.MOUSE_DOWN, pressHandler);
}
private function removeWindow(event:MouseEvent):void {
if (_windowArray.length) {
_windowBlur.removeWindow();
removeChild(_windowArray.pop());
}
}
private function blurChangeHandler(event:ValueSliderEvent):void {
_windowBlur.blurAmount = int(event.value);
}
private function pressHandler(event:MouseEvent):void {
_activeWindow = event.currentTarget as GraphicWindow;
addChild(_activeWindow);
stage.addEventListener(MouseEvent.MOUSE_UP, releaseHandler);
_activeWindow.startDrag(false);
}
private function releaseHandler(event:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_UP, releaseHandler);
_activeWindow.stopDrag();
}
private function randRange(min:Number, max:Number):Number {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
}
}
And a quick example:
[kml_flashembed movie="https://blog.onebyonedesign.com/wp-content/uploads/2008/07/windowblur2.swf" height="500" width="500" /]