Reputation: 2088
I'm trying to create a map application similar to this. Click the SWF Preview tab on the left of the image. Specifically, noticed how you can pan around, and the clickable buttons on the map move with it. Basically, how do they do that?
My application has a map that you can click and pan around using a startDrag() function. I have a separate layer with other, clickable movie clips that I'd like to follow the pans of the map layer. Unfortunately, Flash limits you to dragging only one movie clip at a time. Somebody proposed a solution using a prototype, but I can't get that working correctly, and I'm not sure if it's because I'm using ActionScript 3.0 or not.
Can anybody outline a better way for me to accomplish what I'm trying to do, or a better way to do what I'm currently doing? Appreciate it.
Upvotes: 0
Views: 4837
Reputation: 11
Thank you very much. I have changed it as below: package { import flash.display.MovieClip; import flash.events.*; import flash.geom.Rectangle; import flash.utils.setInterval; import flash.utils.clearInterval; import flash.display.MovieClip; import flash.display.DisplayObject; import flash.display.Sprite; import flash.geom.Point; import flash.utils.Dictionary;
public class DragSync {
private var _dragStartCoordinates:Point = null;
private var _siblingsDragStartCoordinates:Dictionary = null;
private var _primaryItem:Object = null;
private var _workSpace:Object = null; private var _dragWithPrimary:Array = null;
public function DragSync(primaryItem:Object,workSpace:Object, dragWithPrimary:Array)
{
_primaryItem = primaryItem;
_dragWithPrimary = dragWithPrimary;
_workSpace = workSpace;
_workSpace.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
_workSpace.addEventListener(MouseEvent.MOUSE_UP, dragMouseUpHandler);
_workSpace.addEventListener(MouseEvent.MOUSE_MOVE, dragMouseMoveHandler);
_workSpace.addEventListener(MouseEvent.MOUSE_OUT, dragOut);
}
private function mouseDownHandler(event:MouseEvent):void
{
trace("event mouse down");
_primaryItem.startDrag();
_dragStartCoordinates = new Point(_primaryItem.x, _primaryItem.y);
_siblingsDragStartCoordinates = new Dictionary(true);
for each (var sibling:DisplayObject in _dragWithPrimary)
{
_siblingsDragStartCoordinates[sibling] = new Point(sibling.x, sibling.y)
}
}
private function dragMouseUpHandler(event:MouseEvent):void
{
moveSiblings();
_primaryItem.stopDrag();
_dragStartCoordinates = null;
_siblingsDragStartCoordinates = null;
}
private function dragMouseMoveHandler(event:MouseEvent):void
{
trace("event mouse MOVE MOVE");
moveSiblings();
}
private function dragOut(event:MouseEvent):void { _primaryItem.stopDrag(); }
// expects _dragStartCoordinates and _siblingsDragStartCoordinates
// to be set
private function moveSiblings():void
{
if (!_dragStartCoordinates || !_siblingsDragStartCoordinates) return;
var xDiff:Number = _primaryItem.x - _dragStartCoordinates.x;
var yDiff:Number = _primaryItem.y - _dragStartCoordinates.y;
for each (var sibling:DisplayObject in _dragWithPrimary)
{
sibling.x = _siblingsDragStartCoordinates[sibling].x + xDiff;
sibling.y = _siblingsDragStartCoordinates[sibling].y + yDiff;
}
}
}
}
Upvotes: 1
Reputation:
Thanks hasseg for the code, saved a wee bit of time. Here's my take on it for public use...
package Tools
{
import flash.display.MovieClip;
import flash.events.*;
import flash.geom.Rectangle;
import flash.utils.setInterval;
import flash.utils.clearInterval;
import flash.display.MovieClip;
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.geom.Point;
import flash.utils.Dictionary;
public class DragSync {
private var _dragStartCoordinates:Point = null;
private var _siblingsDragStartCoordinates:Dictionary = null;
private var _primaryItem:Object = null;
private var _dragWithPrimary:Array = null;
public function DragSync(primaryItem:Object,dragWithPrimary:Array)
{
_primaryItem = primaryItem;
_dragWithPrimary = dragWithPrimary;
_primaryItem.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
_primaryItem.addEventListener(MouseEvent.MOUSE_UP, dragMouseUpHandler);
_primaryItem.addEventListener(MouseEvent.MOUSE_MOVE, dragMouseMoveHandler);
}
private function mouseDownHandler(event:MouseEvent):void
{
_dragStartCoordinates = new Point(_primaryItem.x, _primaryItem.y);
_siblingsDragStartCoordinates = new Dictionary(true);
for each (var sibling:DisplayObject in _dragWithPrimary)
{
_siblingsDragStartCoordinates[sibling] = new Point(sibling.x, sibling.y)
}
}
private function dragMouseUpHandler(event:MouseEvent):void
{
moveSiblings();
_dragStartCoordinates = null;
_siblingsDragStartCoordinates = null;
}
private function dragMouseMoveHandler(event:MouseEvent):void
{
moveSiblings();
}
// expects _dragStartCoordinates and _siblingsDragStartCoordinates
// to be set
private function moveSiblings():void
{
if (!_dragStartCoordinates || !_siblingsDragStartCoordinates) return;
var xDiff:Number = _primaryItem.x - _dragStartCoordinates.x;
var yDiff:Number = _primaryItem.y - _dragStartCoordinates.y;
for each (var sibling:DisplayObject in _dragWithPrimary)
{
sibling.x = _siblingsDragStartCoordinates[sibling].x + xDiff;
sibling.y = _siblingsDragStartCoordinates[sibling].y + yDiff;
}
}
}
}
Upvotes: 1
Reputation: 6807
I think defmeta's method is the best one if it's possible to make everything be children of the "main" draggable object -- it's the fastest (in terms of UI response time) and most simple, and requires the least amount of code.
If that is not an option, there are a couple of other methods at your disposal:
Here's an example that implements drag functionality for an object that will also move a bunch of "sibling" objects along with it. In this example,
_siblings
is a Dictionary in which the keys are the other objects that need to be moved..
private var _dragStartCoordinates:Point = null;
private var _siblingsDragStartCoordinates:Dictionary = null;
private function mouseDownHandler(event:MouseEvent):void
{
this.startDrag();
_dragStartCoordinates = new Point(this.x, this.y);
_siblingsDragStartCoordinates = new Dictionary(true);
for (var sibling:DisplayObject in _siblings)
{
_siblingsDragStartCoordinates[sibling] = new Point(sibling.x, sibling.y);
}
stage.addEventListener(MouseEvent.MOUSE_UP, dragMouseUpHandler, false, 0, true);
stage.addEventListener(MouseEvent.MOUSE_MOVE, dragMouseMoveHandler, false, 0, true);
}
private function dragMouseUpHandler(event:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, dragMouseUpHandler, false);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, dragMouseMoveHandler, false);
this.stopDrag();
moveSiblings();
_dragStartCoordinates = null;
_siblingsDragStartCoordinates = null;
}
private function dragMouseMoveHandler(event:MouseEvent):void
{
moveSiblings();
}
// expects _dragStartCoordinates and _siblingsDragStartCoordinates
// to be set
private function moveSiblings():void
{
var xDiff:Number = this.x - _dragStartCoordinates.x;
var yDiff:Number = this.y - _dragStartCoordinates.y;
for (var sibling:DisplayObject in _siblings)
{
sibling.x = _siblingsDragStartCoordinates[sibling].x + xDiff;
sibling.y = _siblingsDragStartCoordinates[sibling].y + yDiff;
}
}
Upvotes: 2
Reputation: 1322
Simple. Put your map and the clickable buttons into a new MovieClip, you could call it interactiveMapContainer or something similar, then call your startDrag method on interactiveMapContainer and you'll still be able to click the buttons once you've dragged it about.
Jakub Kotrla's method will also work very well, although it is slightly more complicated.
Upvotes: 3
Reputation: 283
can you add the movieclips to a parent clip and have the event handler drag the parent?
Upvotes: 0
Reputation: 257
I can't drag anything int SWF you linked, just zoom via mouseWheel.
You can make more than one movieClip dragging at once using events mousedown, mouseMove and mouseUp.
Add event handler for events via Mouse.addListener(object).
Upvotes: 1