Scrollen und Ziehen mit einem Navigator

 

Da in dem vorgegebenen Container immer nur ein Ausschnitt des Bildes gezeigt wird, ist es sinnvoll, in einer kleinen Darstellung daneben, das ganze Bild darzustellen und den gerade sichtbaren Ausschnitt extra hervorzuheben. Dadurch erhält man eine bessere Vorstellung von dem Detail in Relation zum Ganzen. Aus dem Photoshop und anderen Grafikprogrammen kennt man den Navigator, der auch zum Wählen des Ausschnitts verwendet werden kann.

Im nachfolgenden Beispiel kann über das kleine Rechteck im Navigator der Ausschnitt im ScrollPane-Container verschoben werden. Wenn man im Container den Inhalt scrollt oder zieht wird umgekehrt im Navigator das Ausschnittsrechteck entsprechend verschoben.
 

Skript (scrollpane_navigator.fla)

Das nachstehende Skript wurde der Adobe-Hilfe für ScrollPane entnommen und überarbeitet.
Die Grenzen werden exakter berechnet und es wird an Stelle von startDrag ein MOUSE_MOVE-Eventhandler verwendet, der unmittelbarer auf die Mausbewegungen reagiert.

Die Erklärungen sind direkt als Kommentar zum Skript hinzugefügt.

import flash.events.*;
import flash.geom.*;
import fl.containers.ScrollPane;
import fl.events.ScrollEvent;

// globale Variablen festlegen
var sampleImagePath:String="http://www.dma.ufg.ac.at/assets/23033/intern/linz_altstadt.jpg"; // URL des Bildes
var sp:ScrollPane; // ScrollPane-Container für das Bild
var previewWindow:Sprite=new Sprite(); // Navigatorfenster
var previewWindowSize:Number=100; // Breite des Navigatorfensters
var previewPositioner:Sprite; // Ausschnittsrechteck im Navigator
var deltaX:Number; // speichert den x-Versatz zur x-Mausposition des Ausschnittsrechtsecks beim Ziehen
var deltaY:Number; // speichert den y-Versatz zur y-Mausposition des Ausschnittsrechtsecks beim Ziehen
var margin:Number=10; // Randbreite zur Bühne

// Scrollpane-Container erzeugen
sp=new ScrollPane();
sp.move(margin,margin);
// festlegen der Größe mit den Rändern
sp.setSize(stage.stageWidth-previewWindowSize-3*margin,stage.stageHeight-2*margin);
sp.source=sampleImagePath;
// nach dem Laden des Inhalts wird der Navigator erzeugt
sp.addEventListener(Event.COMPLETE,createPreviewWindow);
// Eventhandler, der laufend beim Scrollen und Ziehen des Inhalts aufgerufen wird
sp.addEventListener(ScrollEvent.SCROLL,repositionPreview);
sp.scrollDrag=true;// das Ziehen wird ermöglicht
addChild(sp);

// erstellen des Navigators
function createPreviewWindow(e:Event):void {
previewWindow=new Sprite();
// positionieren
previewWindow.x=sp.width+2*margin;
previewWindow.y=margin;
// weiße Füllung, schwarze Kontur
previewWindow.graphics.beginFill(0xFFFFFF);
previewWindow.graphics.lineStyle(1,0,1);
// die Breite ist vorgegeben, die Höhe errechnet sich aus der Proportion des geladenen Bildes
previewWindow.graphics.drawRect
(0,0,previewWindowSize,Math.ceil(previewWindowSize*sp.content.height/sp.content.width));
addChild(previewWindow);

// Bitmap für die verkleinerte Gesamtansicht des Bildes
var bitmapData:BitmapData;
bitmapData=new BitmapData(sp.content.width,sp.content.height); // Größe wird festgelegt
bitmapData.draw(sp.content); // der Inhalt des Containers wird in die bitmapData gezeichnet
var bitmap:Bitmap=new Bitmap(bitmapData); // mit der bitmapData wird eine Bitmap angelegt
// festlegen der Bitmapgröße in der Größe des Navigators
bitmap.width=previewWindow.width;
bitmap.height=previewWindow.height;
bitmap.alpha=0.5; // Deckkraft reduzieren
previewWindow.addChild(bitmap); // die Bitmap ist ein Teil des Navigators

// Ausschnittsrechteck im Navigator erstellen
previewPositioner=new Sprite();
previewPositioner.graphics.beginFill(0xFFFFFF,0.5);
previewPositioner.graphics.lineStyle(1,0,0.5);
// Größe des Ausschnittrechtsecks berechnen
// getHorizontalAspect() und getVerticalAspect() liefern das Verhältnis
// von ScrollPane-Containerbreite/höhe und der Breite/Höhe des Inhalts
previewPositioner.graphics.drawRect
(0,0,getHorizontalAspect()*previewWindow.width,getVerticalAspect()*previewWindow.height);
// bei MOUSE_DOWN soll das Ausschnittsrechteck verschiebbar werden
previewPositioner.addEventListener(MouseEvent.MOUSE_DOWN,dragPreviewPositioner);
// bei MOUSE_UP wird die Verschiebemöglichkeit beeendet
previewPositioner.addEventListener(MouseEvent.MOUSE_UP,dropPreviewPositioner);
// positionieren in der linken oberen Ecke des Navigators
previewPositioner.x=previewWindow.x;
previewPositioner.y=previewWindow.y;
// zur Displaylist des Mainmovies hinzufügen
addChild(previewPositioner);
}

// ziehen des Ausschnittrechtecks ermöglichen
function dragPreviewPositioner(e:MouseEvent):void {
// speichern des Versatzes zw. Mausposition beim Klick und der linken, oberen Ecke des Ausschnittrechtecks
deltaX=e.stageX-previewPositioner.x;
deltaY=e.stageY-previewPositioner.y;
// Eventhandler aktivieren,
// der bei MOUSE_MOVE das Ausschnittsrechteck und den Inhalt des ScrollPane-Containers aktualisiert

previewPositioner.addEventListener(MouseEvent.MOUSE_MOVE,repositionScrollPane);
}

// ziehen des Ausschnittrechtecks beenden
function dropPreviewPositioner(e:MouseEvent):void {
previewPositioner.removeEventListener(MouseEvent.MOUSE_MOVE,repositionScrollPane);
}

// Aktualisierung von Ausschnittsrechteck und Inhalt des ScrollPane-Containers
function repositionScrollPane(e:MouseEvent):void {
// neue Position des Ausschnitts durch die aktuelle Mausposition und den gespeicherten Versatz festlegen
previewPositioner.x=e.stageX-deltaX;
previewPositioner.y=e.stageY-deltaY;
// prüfen, ob das Ausschnittsrechteck die Navigatorränder überschreitet
// wenn ja, Auuschnittsrechteck an dem entsprechenden Navigatorrand ausrichten
// zuerst für die x-Richtung ...

if (previewPositioner.x < previewWindow.x) {
previewPositioner.x=previewWindow.x;
} else if (previewPositioner.x > previewWindow.x+previewWindow.width-previewPositioner.width) {
previewPositioner.x=previewWindow.x+previewWindow.width-previewPositioner.width;
}
// ... anschließend für die y-Richtung
if (previewPositioner.y < previewWindow.y) {
previewPositioner.y=previewWindow.y;
} else if (previewPositioner.y>previewWindow.y+previewWindow.height-previewPositioner.height) {
previewPositioner.y=previewWindow.y+previewWindow.height-previewPositioner.height;
}
// Inhalt im ScrollPane-Container aktualisieren
// die horzontale Scrollposition ist ein Bruchteil der maximalen horizontalen Scrollposition

sp.horizontalScrollPosition = (previewPositioner.x-previewWindow.x)/
(previewWindow.width-previewPositioner.width)*sp.maxHorizontalScrollPosition;
// die vertikale Scrollposition ist ein Bruchteil der maximalen vertikalen Scrollposition
sp.verticalScrollPosition = (previewPositioner.y-previewWindow.y)/
(previewWindow.height-previewPositioner.height)*sp.maxVerticalScrollPosition;
e.updateAfterEvent(); // Bühne aktualisieren
}

// Aktualisierung des Ausschnittrechtecks im Navigator, wenn der Inhalt des ScrollPane-Containers verschoben wird
function repositionPreview(e:ScrollEvent):void {
previewPositioner.x = previewWindow.x + (previewWindow.width-previewPositioner.width)*
(sp.horizontalScrollPosition/sp.maxHorizontalScrollPosition);
previewPositioner.y = previewWindow.y + (previewWindow.height-previewPositioner.height)*
(sp.verticalScrollPosition/sp.maxVerticalScrollPosition);
}

// Hilfsfunktionen für die Berechnung der Größe des Ausschnittrechtecks im Navigator

// getHorizontalAspect() liefert das Verhältnis von ScrollPane-Containerbreite und der Breite des Inhalts
function getHorizontalAspect():Number {
return sp.width/sp.content.width;
}
// getVerticalAspect() liefert das Verhältnis von ScrollPane-Containerhöhe und der Höhe des Inhalts
function getVerticalAspect():Number {
return sp.height/sp.content.height;
}