# Draggable richtig ausrichten



## ObiKenobi (1. Jun 2012)

Hallo,

ich habe ein Javascript geschrieben in welchem ich Draggable Objekte defintiert hab und ein Droppable (canvas) auf das die Draggable gemalt werden sollen. 

Beim Droppen soll das Element das "gedraggt" wurde genauso gedroppt werden wie es auf das Canvas gezogen wurde.

Ich habe das versucht mit .positionedOffset(); zu realisieren aber das führt nur dazu dass das Element unter dem Mauszeiger "irgenwo" abgelegt wird.

Abe wie bekomm ich es hin dass das Draggable von der mitte an dorthin gemalt wird wo der mauszeiger is?

Mein Code :


```
<div id="toolbar">
    <div id="tabmenu">
        <div id="tab_datasheet1" class="tab active">Terrain</div>
        <div id="tab_datasheet2" class="tab">Objects</div>
        <div id="tab_datasheet3" class="tab">Nyan</div>
    </div>
    <div id="datasheet1" style="margin:5px"></div>
    <div id="datasheet2" style="display:none"></div>
    <div id="datasheet3" style="display:none">
    </div>
</div>
</div>
<script type="text/javascript">
  	mapbackground.each(function(item){
		var image = new Image();
		image.src = './application/images/mapbackground/' + item;
		$('datasheet1').insert({'bottom': image });
		new Draggable(image, {revert: true});
	});
	
	mapobjects.each(function(item){
		var image = new Image();
		image.src = './application/images/mapobjects/' + item;
		$('datasheet2').insert({'bottom': image });
		new Draggable(image, {revert: true});
	});
	
		var image = new Image();
		image.src = 'nyancat.gif';
		$('datasheet3').insert({'bottom': image });
		new Draggable(image, {revert: true});


	Droppables.add('droppable', { 
	hoverclass: 'hover', 
	onDrop: function(dragged, dropped, event) { 
		$('droppable').highlight();
		var arr = dragged.positionedOffset();
		alert("offsetLeft : " + arr[0] );
		alert("offsetTop : " + arr[1] );
		var image = new Image();
  		ctx.drawImage(dragged, this,this);}
  });
</script>
```

Ich nutze Scriptacioulous und Prototype


----------



## Evil-Devil (1. Jun 2012)

Ui, Scriptacolus/Prototype Dragable...

An sich ist dein Ansatz schon korrekt.
Du benötigst zunächst die Drop Position und die Größe des Dragable.

Beim Drop setzt du den Offset des Dragable auf Mausposition - Halbe Weite / Höhe. Allerdings musst du bei der Mausposition das Offset des Canvas abfragen bzw. umrechnen. Und ich empfehle dir nicht erst beim droppen einen neuen Container anzulegen sondern schon vorher die Kopie zu erzeugen bzw. erzeugen zu lassen. Dann ist es relativ einfach 

Müsste mal schauen...hab da glaub noch ein gutes Beispiel zu herumliegen.


----------



## ObiKenobi (1. Jun 2012)

Hallo,

hab mal weiterprogrammiert. Das ganze sieht jetzt folgendermaßen aus funktioniert aber (leider) immer noch nicht so ganz.

War der überzeugung das durch das "Droppable - Mauszeiger" erzielt wird dass ich das objekt "quasi" auf meinen Mauszeiger verschiebe aber hat leider nicht geklappt...


```
mapbackground.each(function(item){
		var image = new Image();
		image.src = './application/images/mapbackground/' + item;
		$('datasheet1').insert({'bottom': image });
		new Draggable(image, {revert: true});
	});
	
	mapobjects.each(function(item){
		var image = new Image();
		image.src = './application/images/mapobjects/' + item;
		$('datasheet2').insert({'bottom': image });
		new Draggable(image, {revert: true});
	});
	
		var image = new Image();
		image.src = 'nyancat.gif';
		$('datasheet3').insert({'bottom': image });
		new Draggable(image, {revert: true});
	


  
  var IE = document.all?true:false;

	if (!IE) document.captureEvents(Event.MOUSEMOVE)
	document.onmousemove = getMouseXY;

	var mouseX = 0;
	var mouseY = 0;
	var droppableLeft = Position.page($('droppable'))[0];
    var droppableTop = Position.page($('droppable'))[1];

	function getMouseXY(e) {

	if (IE) { // grab the x-y pos.s if browser is IE
	mouseX = event.clientX + document.body.scrollLeft;
	mouseY = event.clientY + document.body.scrollTop;
	}

	else {  // grab the x-y pos.s if browser is NS
	mouseX = e.pageX;
	mouseY = e.pageY;
	}  
	
	if (mouseX < 0){mouseX = 0;}
if (mouseY < 0){mouseY = 0;}  

mouseX = mouseX - droppableLeft;
mouseY = mouseY - droppableTop;
document.Show.MouseX.value = mouseX;
document.Show.MouseY.value = mouseY;
return true;
}


 
	Droppables.add('droppable', { 
	hoverclass: 'hover', 
	onDrop: function(dragged, dropped, event) { 
		$('droppable').highlight();
		var arr = dragged.positionedOffset();
		alert("offsetLeft : " + arr[0] + "  offsetTop : " + arr[1]);
		
		arr[0] = arr [0] - (arr[0] - mouseX);
		arr[1] = arr [1] - (arr[1] - mouseY);

		alert("offsetLeft : " + arr[0] + "  offsetTop : " + arr[1]);
		
  		ctx.drawImage(dragged, arr[0],arr[1]);}
  });
```

EDIT :

Mir ist aufgefallen das ich das ja unterschiedlich behandeln muss, heißt wenn das Objekt links von der Maus is muss ich es ja nach rechts verschieben und wenn es rechts von der Maus is nach ... bin gerade ziemlich übel am Experimentieren aber hab immer noch nichts Brauchbares hinbekommen....



```
Droppables.add('droppable', { 
	hoverclass: 'hover', 
	onDrop: function(dragged, dropped, event) { 
		$('droppable').highlight();
		var arr = dragged.positionedOffset();
		var difX = arr[0] - mouseX;
		var difY = arr[1] - mouseY;
		alert("offsetLeft : " + arr[0] + "\noffsetTop : " + arr[1]+ "\n MouseX: " + mouseX + "\n MouseY: " + mouseY);
		
				if(arr[0] > mouseX){
		
			arr[0] = arr [0] - difX;
			
		} else if(arr[0] < mouseX){		
		
			arr[0] = arr [0] + difX;		
		}
		
		if(arr[1] > mouseY){
			
			arr[1] = arr [1] - difY;
			
		} else if (arr[1] < mouseY){
			
			arr[1] = arr [1] + difY;			
		}


		alert("offsetLeft : " + arr[0] + "\noffsetTop : " + arr[1]);
		
  		ctx.drawImage(dragged, arr[0],arr[1]);}
  });
```


----------



## Evil-Devil (1. Jun 2012)

Hö?

Du greifst doch mit der Maus nach einem Objekt und ziehst es auf dein Canvas. Und da wo du die Maustaste wieder loslässt platzierst du es. Die Positionen musst du dir entsprechend vom Event und den einzelnen Objekten errechnen


Hab nach einem Beispiel geschaut. Das einzige das ich noch aus einem Projekt herumliegen habe läuft ohne Scriptaculos. Zwar mit Prototype, aber das nützt dir somit denke ich nichts.

Die Demo Seite hier hast du wahrscheinlich schon angeschaut, oder?
Draggable &mdash; Scriptaculous Documentation


----------



## ObiKenobi (1. Jun 2012)

Evil-Devil hat gesagt.:


> Hö?
> 
> Du greifst doch mit der Maus nach einem Objekt und ziehst es auf dein Canvas. Und da wo du die Maustaste wieder loslässt platzierst du es. Die Positionen musst du dir entsprechend vom Event und den einzelnen Objekten errechnen
> 
> ...




Hey Evil-Devil,

ich weiß nich ob wir aneinander vorbeireden oder ich dich schlicht und einfach nicht verstehe, aber das problem ist, das auf das Canvas malen funktioniert ja soweit, das Draggen und Droppen auch.

Das problem ist das der das Item nicht genau am Mauszeiger ausrichtet sondern das Objekt immer verschoben ist, also entweder leicht links nebendran oder obendrüber oder oder...

Und ich hab bissher immer noch keine Idee wie ich das problem behebe. Ich hab das versucht anhand deiner Tipps zu realisieren aber das hats nicht unbedingt geändert... 

Eine idee?


----------



## Evil-Devil (2. Jun 2012)

Vielleicht verstehe ich auch das Problem mit dem leicht verschoben nicht richtig. Hast du dazu ein Bild?

Weil über die Offsets + Maus Position im Canvas sollte es sich genau so ausrichten lassen wie du es haben willst.


----------



## ObiKenobi (2. Jun 2012)

Evil-Devil hat gesagt.:


> Vielleicht verstehe ich auch das Problem mit dem leicht verschoben nicht richtig. Hast du dazu ein Bild?
> 
> Weil über die Offsets + Maus Position im Canvas sollte es sich genau so ausrichten lassen wie du es haben willst.



Hi, sicher, wollt ich diir gestern schon posten hab ich aber irgendwie verpennt^^

Map Editor


----------



## Evil-Devil (4. Jun 2012)

Ah cool - ein HTML 5 Canvas. Ich bin die ganze Zeit von non HTML5 ausgegangen.

Ok - egal. Du zeichnest dein Image doch über drawImage() oder?
In dem Falle benötigst du außer den Mauspositionen nur die Ausmaße des Bildes.

Image X = Maus X - Bildbreite / 2
Image Y = Maus Y - Bildbreite / 2

Alternativ könntest du auch ein Grid anlegen und abfragen in welchem Grid Element die Grafik gezogen wird.





Args...seh gerade im Quelltext das hier zwei Dinge aufeinander treffen. Non HTML5 mit HTML5 Canvas...

Willst du also nun auf dem Canvas zeichnen oder willst du physisch etwas droppen? Bei letzteren bräuchtest du imho kein HTML5 Canvas Objekt.

Und gleichgültig davon, du hast die X/Y Koords der Maus und benötigst weiterhin die Bildbreite / 2 zur Positionierung.

Also entweder um an X/Y direkt mit drawImage() zu zeichnen oder um halt das Objekt absolut mit top/left Angaben positionieren.

Hoffe das hilft dir weiter 

[edit]
Die Verschiebung am Mauszeiger von wenigen Pixeln kann ich leider nicht erklären. Das Canvas selbst hat ja keinen Border - es könnte höchstens sein, dass die X/Y/Offset Positionen vom DIV zurückgegeben werden und nicht vom Canvas oder eine Kombination aus beidem :/
[/edit]


----------



## ObiKenobi (4. Jun 2012)

Hi!

Erstmal vielen vielen Dank, ich bin mienem problem einen rieeeeesen schritt auf die Spur gekommen jetzt tut er ENDLICH (halbwegs) das was er tun soll...

Das mit dem Bildgröße / 2 sorgt glücklicherweise (oder leider?!) dafür das dass Objekt genau an der Mitte des Mauszeigers gemalt wird.

Ich hab dir mal ein Bild gemalt um dir zu verdeutlichen was genau es tun soll...

Und um mich zu entschuldigen, ich jongliere seit tagen mit Variablen umher und spiel herum und komme nach wie vor nicht auf das gewünschte ergebnis sonst hätte ich mich nicht an euch gewendet 







Hoffe das Bild verdeutlicht was ich erreichen möchte.

Das "Bildchen" soll genau an die Stelle gemalt werden an das es gezogen wurde. Heißt ganz egal wo der Mauszeiger ist ob oben links oder unten rechts oder mitte oder was weiß ich das bild soll genauso wie "gezogen" auf das Canvas gemalt werden.

Dein Ansatz, für den ich sehr dankbar bin und falls das andre nicht möglich ist auch von mir so übernommen wird führt ja "nur" dazu dass das Bild mittig am Mauszeiger ausgerichtet wird.

Brach ich jetzt doch die Differenz zwischen OffsetTop und OffsetLeft und dem jeweiligen Mauszeiger Koordinaten?


Danke im vorraus für deine (nun hoffentlich letzte Hilfe)


----------



## Evil-Devil (4. Jun 2012)

Ich sehe kein Bildchen ^^"

Genau in der Mitte von Mauszeiger? Hö? Das sollte bei Zielposition = Maus - Bildgröße / 2 nicht passieren.

Schon mal probiert was passiert, wenn du manuell Werte zum platzieren übergibst bzw. die finalen Werte einfach mit einem festen Wert überschreibst?


----------



## ObiKenobi (4. Jun 2012)

Evil-Devil hat gesagt.:


> Ich sehe kein Bildchen ^^"
> 
> Genau in der Mitte von Mauszeiger? Hö? Das sollte bei Zielposition = Maus - Bildgröße / 2 nicht passieren.
> 
> Schon mal probiert was passiert, wenn du manuell Werte zum platzieren übergibst bzw. die finalen Werte einfach mit einem festen Wert überschreibst?




Okay, sorry fehlinfo... 

Hab selbst einen fehler gemacht das Problem is eher trivial und kann gerade nicht genau erklären woher er diesen minimal unterschiedlichen Wert hat.

Und zwar passt es jetzt in der X-Koordinate aber das Bildchen hüpft beim "zeichnen" immer ein stückchen in der Y-Koordinate nach unten, würde sagen das es Grundsätzlich 10 Pixel sind...sehr seltsame angeelgenheit...

Hättest du eine Idee woran das liegen könnte?

Hab es jetzt im übrigen etwas anders gelöst als du vorgeschlagen hast (sonst hat er es tatsächlich immer Zentriert am Mauszeiger ausgerichtet)

Jetzt :

```
// Hüpft?		
arr[0] =  arr[0] - dragged.width   / 2;
arr[1] =  arr[1] - dragged.height / 2;
```

Dein Vorschlag :


```
// Führt zu Zentrierung am Mauszeiger		
arr[0] =  mouseX - dragged.width   / 2;
arr[1] =   mouseY  - dragged.height / 2;
```

Habs aufn Server geladen dann kannst dus Bewundern wenn du möchtest ;(


----------



## Evil-Devil (5. Jun 2012)

Die Offset Werte...woher beziehst du die?

Weil wenn man zb. ein Element in die oberste Ecke schiebt, also Außenkante an Innenkante des Canvas, dann spricht der von 
MouseX 33
MouseY 24
OffsetTop 55
OffsetLeft 33

Die Offsets sollten imho denen der Mausposition entsprechen bzw. 0 sein. Je nachdem wie dein Event-Handling ist.. Bist du sicher, dass du die Offsets vom Canvas erhälst?

@springen: Ja, ich hab´s gesehen. Bis auf den Sprung schon ein feiner Editor 


[edit]Ich glaub ich habs.
Du nutzt ja PointerX/Y zur Positionsbestimmung. Das gibt dir aber immer den absoluten Wert ausgehend vom Body Tag zurück. Was du benötigst wäre die Position innerhalb des Canvas Objektes.
Und mit Prototype v1.7 API documentation | Event.findElement und Prototype v1.7 API documentation | Element.Offset#relativeTo sollte man den korrekten Abstand zum Außenrand des Canvas ermitteln können 

Evtl. gibt es auch im Dragable bereits passende Hilfsfunktionen. danach hab ich nun nicht geschaut.
[/edit]


----------

