Interpreter Problem bei Prototype Klasse

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Interpreter Problem bei Prototype Klasse

    Hallo Gemeinde,

    leider hänge ich gerade an einer Sache, bei der ich hoffe von Euch den weiterbringenden ultimativen Tipp zu bekommen. Es geht um Folgendes:

    Ich habe eine Prototype / Javascript Klasse, welche asynchron alle Thumbnails eines Albums einer Galerie ermittelt. Es wird ein JSON String zurückgeliefert, welcher letztendlich in ein Objekt aufgelöst wird. Anhand des Objektes erstelle ich pro Bild ein DIV Element, welches das jeweilige Thumbnail enthält. Nachdem alle DIV Elemente erstellt wurden, benötige ich die gesamte Breite aller DIV Elemente, um sie in einer Slide-Show darzustellen. An sich alles machbar und funktioniert soweit auch.

    Es gibt lediglich ein Problem beim ermitteln der gesamten Breite. Zunächst aber mal der Code in gekürzter Fassung ...

    Code:
    var Gallery = Class.create({
        
        albumID : 0,
        itemCount : 0,
    
        initialize : function(albumID) {
            this.albumID = albumID;
            new Ajax.Request('index.php?action=Foo&do=Bar&albumID='+albumID, {
                method : 'post',
                onComplete : function(transport) {
                    var data = transport.responseText.evalJSON(true);
                    ...
                }
            });
        },
    
        createImageContainer : function(imagePath, image) {
            var itemDiv = new Element('div', {
                'class' : 'foo',
                'id' : 'item-' + this.itemCount
            });
    
            var itemImage = new Element('img', {
                'src' : imagePath + image['src'],
                'alt' : image['caption']
            });
    
            itemDiv.appendChild(itemImage);
            $('imageContainer').appendChild(itemDiv);
        },
    
        setMaxWidth : function() {
            var maxWidth = 0;
    	$$('div[id*="item-"]').each(function(item) { 
    		maxWidth = maxWidth + item.getWidth();
    		alert(maxWidth); 
    	});
    
            $('imageContainer').setStyle({
                width: maxWidth + 'px'
            });
        }
    });
    Das Augenmerk gilt der Funtion setMaxWidth. Diese Funtion liest alle erstellten DIV Elemente aus und ermittelt die Breite und addiert diese zur Gesamtbreite zusammen. Solang ich das alert() in dieser Funktion belasse, funktioniert alles wie gewünscht. Wenn ich das alert() rausnehme bekomme ich eine maximale Breite von lediglich 300 Pixeln, obwohl die Breite über 2000 Pixel hinaus gehen müsste.

    Ich habe es schon mit der window.setTimeout() Funktion probiert, um ein Delay im Funktionsablauf zu erzeugen. Aber klappt auch nicht. Gibt es hier einen Lösungsansatz?

    Danke schon mal für die möglichen Antworten.
    MM Newmedia | MeinBlog

  • #2
    Lösung

    Da war der Interpreter wohl ein wenig zu langsam. Die volle Breite des dynamisch erstellten DIV Elements war zum Zeitpunkt, an dem die volle Breite des DIV Elements gemessen werden sollte, noch gar nicht vorhanden, da das Element noch gar nicht vollständig im DOM vorhanden war.

    Folgende Lösung:
    Code:
    var Gallery = Class.create({
        
        albumID : 0,
        itemCount : 0,
        maxWidth : 0,
    
        initialize : function(albumID) {
            this.albumID = albumID;
            
            $('itemList').observe('DOMNodeInserted', function(event) {
    	    this.maxWidth += Event.element(event).getWidth();
    	});
    
            new Ajax.Request('index.php?action=Foo&do=Bar&albumID='+albumID, {
                method : 'post',
                onComplete : function(transport) {
                    var data = transport.responseText.evalJSON(true);
                    ...
                    $('imageContainer').setStyle({ width : this.maxWidth + 'px' });
                }
            });
        },
    
        createImageContainer : function(imagePath, image) {
            var itemDiv = new Element('div', {
                'class' : 'foo',
                'id' : 'item-' + this.itemCount
            });
    
            var itemImage = new Element('img');
            itemImage.observe('load', function() {
                itemDiv.style.minWidth = this.getWidth() + 'px';
            }
            itemImage.src = imagePath + image['src'];
            itemImage.alt = image['caption'];
    
            itemDiv.appendChild(itemImage);
            $('imageContainer').appendChild(itemDiv);
        },
    });
    Bei der Erstellung des Image Elements wird noch vor dem Festlegen des src Attributes ein EventListener festgelegt, der, sobald das Bild geladen ist, die Breite des DIV Elements festlegt, in welches das IMG Element später eingefügt wird.

    Das DIV Element imageContainer bekommt bei der Initialisierung der Klasse einen EventListener aufgedrückt. Wie in der W3C Recommendation beschrieben, ist das Event DomNodeInserted dafür wie geschaffen.

    Somit lässt sich dann auch die komplette Breite des DIV Elementes sauber ermitteln. Da haben wir wieder was dazugelernt. *hehe*
    MM Newmedia | MeinBlog

    Kommentar


    • #3
      Ich weiss nicht genau, was das Problem bei dir war, denn es ist zu wenig relevanter Code um das sagen zu können, aber du solltest bei deinem Problem auf jeden Fall ohne DomNodeInserted auskommen können.
      Du musst die Breite einfach synchron (wohl in deinem Fall im oncomplete) und nicht asynchron machen.

      Kommentar


      • #4
        Hi jmc,

        was ist der Grund für den Verzicht von DOMNodeInserted?

        Das Problem war, dass, sobald ich es synchron gemacht habe und die Breite des DIV Elements, welches das Bild sowie padding und margin Werte enthält, ermitteln wollte, keine vollständigen Werte bekommen habe. Es wurden hier lediglich die für das DIV Element festgelegten margin und padding Werte ermitteln, aber nicht die Breite des Bildes, welches sich innerhalb des DIV Elements befindet.

        Ich tippe mal, dass das Bild noch nicht vollständig geladen war. Zumindest konnte ich ähnliches an mehreren Stellen im Netz lesen, da ich wohl nicht der einzige mit diesem Problem war.

        Ich habe die jetzige Lösung nur im Firefox getestet. Wahrscheinlich wird mir der IE das DOMNodeInserted Event um die Ohren hauen. *narf*
        MM Newmedia | MeinBlog

        Kommentar


        • #5
          Dieser Event wird je nach Browser sehr Ressourcenaufwendig verarbeitet und du wirst bei einigen Browsern Probleme kriegen (ehrlich gesagt weiss ich aber nicht welche ihn alle unterstützen und welche nicht).
          Es wird unter Umständen auch zu oft aufgerufen.
          Dass zu Beginn nicht bekannt ist wie gross das Bild ist ist wohl relativ klar.
          Deshalb kannst du sowas machen:
          Code:
          myImg = new Image();
          myImg.src = URL;
          myImg.onload = function(){
           alert(this.width);
           // create DOMElement and add width
          }

          Kommentar


          • #6
            Ja habe es gerade schmerzlich erfahren.
            Weder IE noch Safari interpretieren dieses Event richtig. Naja ... ich werde dann auf die onload Variante zurückgreifen.

            Danke für den Tipp.
            MM Newmedia | MeinBlog

            Kommentar


            • #7
              Wieso lässt du dir nicht auch noch die angeben von der Höhe und der breite des Bildes über json wiedergeben?

              Dann hast du nicht mehr das Problem.

              mfg jura
              [FONT=Comic Sans MS]Hab ich dir erfolgreich geholfen? Wenn ja, dann hilf mir auch und bewerte mich auf php-resource.de[/FONT]
              [FONT=Comic Sans MS]
              [/FONT][FONT=Comic Sans MS]Go and help me[/FONT]

              Kommentar


              • #8
                Moin Jura,

                weil ich über JSON lediglich die Dimensionen des Bildes selbst bekomme. Das DIV Element, welches das Bild enthält, hat aber noch margin und padding Werte. Rein theoretisch könnte ich die einfach zu den Dimensionen des Bildes addieren. Was aber, wenn jemand das CSS Stylesheet ändert und die padding und margin Werte nach seinen Belieben anpasst? Die Variante per getWidth() ist dann einfach sicherer, weil sie die komplette Breite des DIV Elements ausliest.
                MM Newmedia | MeinBlog

                Kommentar


                • #9
                  Jo das habe ich verstanden.
                  Aber dein Problem war doch, dass du die Breite der Div's nicht direkt auslesen konntest bevor die Bilder geladen haben?

                  Wieso benutzt du nicht die Dimensionen und gibst den DIV's diese?
                  Damit hättest du doch die Breite+Margin/Padding wenn du sie wieder ausliest.

                  mfg jura
                  [FONT=Comic Sans MS]Hab ich dir erfolgreich geholfen? Wenn ja, dann hilf mir auch und bewerte mich auf php-resource.de[/FONT]
                  [FONT=Comic Sans MS]
                  [/FONT][FONT=Comic Sans MS]Go and help me[/FONT]

                  Kommentar


                  • #10
                    Zitat von CiaoSen Beitrag anzeigen
                    Jo das habe ich verstanden.
                    Aber dein Problem war doch, dass du die Breite der Div's nicht direkt auslesen konntest bevor die Bilder geladen haben?

                    Wieso benutzt du nicht die Dimensionen und gibst den DIV's diese?
                    Damit hättest du doch die Breite+Margin/Padding wenn du sie wieder ausliest.

                    mfg jura
                    Das wird ja jetzt quasi auch so gemacht.
                    Sobald das Bild ermittelt und die Dimensionen bekannt sind, wird dem DIV Element die Breite der einzufügenden Grafik gegeben. Dies funktioniert aber erst, wenn die Grafik wirklich geladen ist. Hier lag das Problem. Erst dann haben die dynamisch erstellten DIV Elemente die Breite des Bildes und können mit der Prototype Methode getWidth() erfasst werden. Also so, wie es jmc erklärt hat, funktioniert es problemlos über die gängigsten Browser hinweg.
                    MM Newmedia | MeinBlog

                    Kommentar

                    Lädt...
                    X