zoom zur mausposition

Status
Nicht offen für weitere Antworten.
J

Jazoon5

Gast
Hallo!

ich bin gerade dabei eine Zooming-Methodik zu coden. Dabei bin ich schon recht weit gekommen, das zoomen funktioniert, jedoch wird immer ausgehend vom Punkt 0,0 gezoomt.

Ich möchte das ganze so hinbiegen, dass genau dort hineingezoomt wird wo die Maus sich gerade befindet.
--> zoomen funktioniert per Scrollen

Hier mein derzeitiger code, welcher relevant für die Zooming-aufgaben sein sollte:

Code:
   /**
     * Die Repaint Methode vom JPanel überschreiben
     */
    public void paintComponent(Graphics g)
    {    	
        g2d = (Graphics2D)g;
    	AffineTransform at = new AffineTransform();
    	
    	at.translate(transX, transY);
    	at.scale(scale, scale);
    	
    	g2d.setColor(Color.WHITE);
		g2d.fillRect(0, 0, getWidth(), getHeight());		
		
    	g2d.setTransform(at);
    	map.paintIcon(this, g, 0, 0); 
    }
    
    private class TransformHandler implements MouseListener, MouseMotionListener{
    	private int lastOffsetX;
    	private int lastOffsetY;
    	
    	public void mouseMoved(MouseEvent arg0) { }
    	
		public void mousePressed(MouseEvent arg0) {
			//startPunkt capturen
			lastOffsetX = arg0.getX();
			lastOffsetY = arg0.getY();
		}

		public void mouseDragged(MouseEvent arg0) {
			// neues x und y werden durch die aktuelle Mausposition subtrahierend
			// von der vorherigen Mausposition errechnet
			int newX = arg0.getX() - lastOffsetX;
			int newY = arg0.getY() - lastOffsetY;
 
			// zu den letzten startpunkten wird die neue Distanz durch das draggen addiert
			lastOffsetX += newX;
			lastOffsetY += newY;
 
			// Die neuen Locations der Karte werden upgedated
			transX += newX;
			transY += newY;
			
			// ein Repaint durchführen
			repaint();
		}
		
		public void mouseClicked(MouseEvent arg0) { }
		public void mouseEntered(MouseEvent arg0) {	}
		public void mouseExited(MouseEvent arg0) { }
		public void mouseReleased(MouseEvent arg0) { }
    }
    
    private class ScaleHandler implements MouseWheelListener{

		public void mouseWheelMoved(MouseWheelEvent e) {
			if(e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
				// Einen passende Zoom-skalierung wählen
				// .1 gibt eine passende langsame (flüssige) Zoomphase
				scale += (.1 * -e.getWheelRotation());				
				
				// man darf natürlich nicht ins negative steigen
				// und den scale ganz auf 0 setzen bring auch fehler mit sich!
				scale = Math.max(0.00001, scale); 
				repaint();
			}
		}
    }
}

Hat jemand ne Idee wie ich es schaffen könnte, dass er mir zur Mausposition hinzoomt bzw. herauszoomt?

MfG Jazoon5
 

Marco13

Top Contributor
Hm. Könnte sein, dass es da günstiger wäre, transX/transY als floats zu speichern...
However, sinngemäß: Man muss die Ansicht so verschieben, dass das Zoom-Zentrum im Ursprung liegt, dann die Skalierung ändern, und dann das Zoom-Zentrum (mit der neuen Skalierung) zurückverschieben.... ungefähr so...

transX += zoomCenterX * scale;
transY += zoomCenterY * scale;
scale += (.1 * -e.getWheelRotation());
transX -= zoomCenterX * scale;
transY -= zoomCenterY * scale;

Wobei das zoomCenter beim mousePressed berechent wird als sowas wie

zoomCenterX = (e.getX() - transX) / scale;
zoomCenterY = (e.getY() - transY) / scale;

Ist aber ohne Gewähr - ist schon spät :?

BTW:

int newX = arg0.getX() - lastOffsetX;
// zu den letzten startpunkten wird die neue Distanz durch das draggen addiert
lastOffsetX += newX;

=> lastOffsetX = lastOffsetX + newX
=> lastOffsetX = lastOffsetX + arg0.getX() - lastOffsetX
=> ... :wink:
 
J

Jazoon5

Gast
Sehr gut =)
vielen Dank!

Was mir jetzt noch aufgefallen ist:

Das ganze ist ein JPanel in dem ein SVGIcon (aus der library von SVG Salamander) ist, welches mir eine Landkarte im SVG-Format darstellt. Das ganze kann man natürlich auch verschieben, per drag & drop wie an meinem Code den ich oben gepostet hab ersichtlich ist.

Ist es möglich, das Verschieben so einzuschränken, dass der user nicht "zu weit" verschieben kann?
Wenn z.B. das Bild normal sichtbar ist (nicht hineingezoomt: scaling auf 1:1 oder kleiner), dann soll er nur so weit verschieben können, bis das Bild am Rand des Fensters angelangt... wenn jedoch hineingezoomt ist, dann ist das Bild größer und reicht eigentlich bereits über den Rand (nur sieht man klarerweise den Teil der "hinterm Fensterrand" ist nicht).
--> da soll natürlich auch soweit verschoben werden können, bis eben der user so weit verschieben würde, dass der Rand des Bildes über den Fensterrand kommen würde.
 

Marco13

Top Contributor
Hmja.. wenn man sehr weit rausgezoomt hat, soll man das "mini-Bildchen" nicht aus dem sichtbaren Bereich rausschieben können, und wenn man sehr nah rangezoomt hat, soll man das "Sichtfenster" nicht über den Rand des vergrößerten Bildes hinausschieben können.

Das sind zwei unterschiedliche Fälle, je nachdem, ob das Bild beim aktuellen skalierungsfaktor ganz darstellbar ist oder nicht:

1. Wenn das Bild größer ist als das Fenster, muss man ausrechnen können, in welchen Bereich des Bildes sich das Fenster gerade befindet
2. Wenn das Fenster größer ist als das Bild, muss man ausrechnen können, in welchen Bereich des Fensters sich das Bild gerade befindet

Die transX/transY müssen dann so eingschränkt werden, dass ...
1. ... die Eckpunkte des Fensters nicht außerhalb des Bildes liegen bzw.
2. ... die Eckpunkte des Bildes nicht außerhalb des Fensters liegen

Das klingt erstmal einfach, aber das kann ein bißchen frickelig-fummelig werden, wenn man's dann tatsächlich machen muss. Insbesondere dann, wenn diese Bedinungen auch während des Zoomens erhalten bleiben sollen ... das ist nicht sooo trivial, aber machbar, wenn man sich vorher GENAU überlegt, WAS in den beiden Fällen gemacht werden muss, und man sich "praktische", leicht anwendbare Methoden dafür schreibt...
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen


Oben