• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

[FRAGE] Thema elementFromPoint()

mikdoe

Moderator
Hi!
Habe folgende Funktion, die mir das <li> unter einer Bildschirmposition ermitteln soll:
HTML:
function gib_mittiges(data) {
	var xpos = parseInt(jQuery(data['intern']['kalender_obj']).width()/2+jQuery(data['intern']['kalender_obj']).offset().left,10);
	var ypos = parseInt(jQuery(data['intern']['kalender_obj']).offset().top+10,10);
	var receiver = document.elementFromPoint(xpos,ypos);
	while (receiver.nodeName != 'LI' && receiver.parentNode) {	// nur das <li> Element hat die gesuchte ID
		receiver = receiver.parentNode;
	}
	if (receiver.nodeName == 'LI') {
		var dateobj = new Date();
		dateobj.setTime(receiver.date.getTime());
		return dateobj;
	}
	return;
}
Funktioniert an sich top!
Aber folgendes Problem: Wenn die Seite gescrollt wurde, trifft es nicht mehr die richtige Position. Soweit ich das richtig verstanden habe, ermittelt jQuery's .offset() die feste relative Position im Dokument, .elementFromPoint() hingegen möchte aber die relative Position zur sichtbaren oberen linken Ecke.

Eine Lösung dafür ist wahrscheinlich hier beschrieben: document.elementFromPoint – a jQuery solution - zehnet.de

Aber meine Kenntnisse reichen nicht, das in meine function zu integrieren. Das ist gekapselter Code in (function ($){}) und ich weiß nicht, wie man sowas anschließend aufruft. Außerdem steht in Kommentar 7 etwas zum IE8 und ich weiß nun nicht, ob das in der dort angegebenen Funktion schon eingebaut wurde. Den IE8 möchte ich gern auch unterstützen.

Daher bitte ich um Hilfe, meine function gib_mittiges(){} zu erweitern. Kann mir das bitte jemand einbauen? Vielen Dank!
 
Nein, nicht die Position unter der Maus sondern das Element, das in der horizontalen Mitte von data['intern']['kalender_obj'] liegt.
 
Fast. Schau mal bitte:
HTML:
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script>
$(function () {
  $('.schalter').click(function () {
    var l = $('.x').offset().left+($('.x').width()/2);
    var t =$('.x').offset().top+($('.x').height()/2);
    var overEle = document.elementFromPoint(l,t);
    $(overEle).css({backgroundColor: 'green'});
  });
});
</script>
<style type="text/css">
.x { width: 100%; height: 100px; overflow-y: hidden; overflow-x: scroll;}
.x > .y{ width: 4000px;}
.x > .y > .z {
  width: 100px;
  height: 100px;
  background-color: red;
  margin: 0;
  border: 1px solid #000;
  float: left;
}
.schalter { cursor:pointer; }
</style>
<meta charset="utf-8">
<title>Test elementFromPoint</title>
</head>
<body>
 <div class="x">
      <div class="y">
        <div class="z"></div>
        <div class="z"></div>
        <div class="z"></div>
        <div class="z"></div>
        <div class="z"></div>
        <div class="z"></div>
        <div class="z"></div>
        <div class="z"></div>
        <div class="z"></div>
        <div class="z"></div>
        <div class="z"></div>
        <div class="z"></div>
        <div class="z"></div>
        <div class="z"></div>
        <div class="z"></div>
        <div class="z"></div>
        <div class="z"></div>
        <div class="z"></div>
      </div>
    </div>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
</body>
</html>
Beim Aufruf ist die Leiste mit den Kästchen sichtbar. Drück mal irgendwo auf Mitte. Klappt? Mittleres Kästchen wird grün? Ja, bei mir auch.
Jetzt bitte Seite neu laden.
Jetzt scrollst du soweit runter bis die rote Leiste nicht mehr zu sehen ist.
Jetzt drückst wieder irgendwo auf Mitte. Was jetzt passieren soll: Es sollte oben das mittige Kästchen grün werden, genau wie gerade eben auch.
Stattdessen wir das ganze Bild grün.
Genau da liegt mein Problem.
 
So wirklich scrollen kann man die Seite aber dann nicht mehr...

Code:
$(function () {
  $('.schalter').click(function () {
    var oldScroll = document.documentElement.scrollTop;
    document.documentElement.scrollTop = 0;
    var l = $('.x').offset().left+($('.x').width()/2);
    var t =10+($('.x').height()/2);
    
    var overEle = document.elementFromPoint(l,t);
    $(overEle).css({backgroundColor: 'green'});
    document.documentElement.scrollTop = oldScroll;
  });
});
 
Korbinian, vielen Dank! Technisch funktioniert es.
Aber der roten Streifen blitzt beim Klick ganz kurz am oberen Bildschirmrand auf. Ist das unumgänglich oder kann man da noch was machen?
 
Das kommt wahrscheinlich daher, dass man kurzzeitig nach oben springt und dann wieder runterspringt (im FF ist das bei mir aber nicht sichtbar).

Als Alternative könntest du natürlich auch per Hand alle Elemente durchgehen und schauen, welches in der Mitte liegt:
Code:
<!DOCTYPE html>

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Fenstertitel</title>
<script type="text/javascript" src="//kkjs.kkapsner.de/modules/kkjs.load.js"></script>
<style type="text/css">
#scroller {
	overflow: auto;
	border: 2px solid black;
	white-space: nowrap;
	position: relative;
}
.element {
	width: 200px;
	height: 200px;
	display: inline-block;
	background-color: blue;
	border: 1px dashed gray;
	border-width: 0 1px;
}
.element.middle {
	background-color: red;
}
</style>
</head>
<body>
<div id="scroller"><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div></div>

<script type="text/javascript">
kkjs.event.add(kkjs.$("scroller"), "scroll", function(){
	kkjs.css.className.remove(kkjs.css.$(".middle", {node: this}), "middle");
	var x = this.scrollLeft + this.clientWidth / 2;
	kkjs.css.$(".element", {node: this}).forEach(function(el){
		if (el.offsetLeft < x && el.offsetLeft + el.offsetWidth >= x){
			kkjs.css.className.add(el, "middle");
		}
	});
}).fireEvent("scroll");
</script>
</body>
</html>
- könnte in dem Fall sogar eventuell robuster sein.
 
Korbinian, das soll für meinen Endloskalender sein. Da wollte ich eigentlich keinen Event an das Scrollen binden. Der Browser hat eh schon genug zu tun. Das wäre auch oversized, denn ich brauche das mittige Element nur, wenn auf der Seite bestimmte Links angeklickt werden. Und dafür dauernd einen Event mitlaufen lassen wäre mir etwas viel.

Aber ich hatte die Nacht eine Idee: Wie wäre es, wenn man von der sichtbaren Breite des Elternelements die Mitte nimmt und dann schaut, von welchem Kindelement die linke obere Ecke gerade noch <= Mitte liegt? Dann hätte man auch das mittige Element.
Hab das eben mal versucht aber ich scheitere an der sichtbaren Breite des Elternelements. Die JQuery width sowie die offsetWidth liefern alle nur die tatsächliche Breite. Vorteil dieser Methode: Man braucht elementFromPoint() garnicht mehr.

Kann mir da jemand auf die Sprünge helfen?
 
Ich glaube, ich habs doch hinbekommen:
HTML:
<!DOCTYPE html>

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Fenstertitel</title>
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<style type="text/css">
#scroller {
	overflow: auto;
	border: 2px solid black;
	white-space: nowrap;
	position: relative;
}
.element {
	width: 200px;
	height: 200px;
	display: inline-block;
	background-color: blue;
	border: 1px dashed gray;
	border-width: 0 1px;
}
.element.middle {
	background-color: red;
}
</style>
</head>
<body>
<div id="scroller">
	<div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div><div class="element"></div>
</div>
<div id="mitte" style="width:100%;text-align:center;border:1px red solid;"><span style="font-size:25px;">^</span><br>ungefähre Mitte</div>

<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>
<input type="button" class="schalter" value="Mitte"/>
 <br> <br> <br> <br> <br> <br> <br> <br> <br> <br>

<script>
jQuery('.schalter').click(function () {
	var obj = gib_mittiges('scroller','element');
	jQuery(obj).addClass('middle');
});
function gib_mittiges(elem,klasse) {
	var eltern_mitte = parseInt(document.getElementById(elem).offsetWidth,10)/2;
	var mitte_obj = new Object;
	jQuery('.'+klasse).each(function() {
		var xpos = parseInt(jQuery(this).offset().left,10);
		if (xpos <= eltern_mitte) { mitte_obj = this; }
		else { return false; }	// Schleife abbrechen
	});
	return mitte_obj;
}
</script>

</body>
</html>
Mein Fehler lag darin, dem Elternelement per CSS eine feste Breite gegeben zu haben. Dann funktioniert das hier nicht.
 
Das mit dem onscroll war auch nur, damit man das sofort sieht. Dein jetziger Ansatz ist ja, im Grunde genommen, das Gleiche.

Mein Fehler lag darin, dem Elternelement per CSS eine feste Breite gegeben zu haben. Dann funktioniert das hier nicht.
Ich hab' das gerade ausprobiert und bei funktioniert das ohne Änderung des JS-Codes...

PS: deine parseInt()s sind überflüssig, da sowohl .offsetWidth als auch .offsetLeft (worauf .offset() meines Wissens nach beruht) Integers zurückliefern.
 
Der ganz neue Code im Gerippe aus dem Code in #7 ergab bei mir immer eine Breite von 4000 für das Elternelement. Egal, ob ich X oder Y abgefragt hatte.
 
Bei .x hätte eigentlich die richtige Breite kommen müssen...

... bei dem letzten Code kann man dem #scroller aber eine Breite geben und es passt.
 
Ja, ich weiß jetzt auch nicht mehr ganz genau, warum es so war, hab den Versuchscode gelöscht. Bin mit dem Code aus #15 jetzt sehr zufrieden und ein bisschen stolz, dass ich meine Idee doch noch ganz allein umsetzen konnte. Solche Sachen gehen mir nicht so leicht von der Hand.
 
Zurück
Oben