0 votes
in SoSci Survey (dt.) by s109993 (12.0k points)
edited by s109993

Guten Morgen,

für ein Projekt brauch ich eine API, die Mathematische Formeln in SoSci ermöglicht. Dafür habe ich bis jetzt MathType verwendet. Zusätzlich bräuchte ich jetzt aber noch eine API, die den User geometrische Formen "zeichnen" lässt. Hier habe ich gerade GeoGebra gefunden:
Die Frage ist jetzt, wie kann ich die Zeichenfläche am Besten als Bild abspeichern? bzw. ist das überhaupt möglich?

Pretest Link: https://ofb.iea-hamburg.de/ceco/?act=9XdryDKWw3A7G1GneDzDASHd

Viele Grüße

1 Answer

0 votes
by SoSci Survey (330k points)

wie kann ich die Zeichenfläche am Besten als Bild abspeichern?

Das <canvas>-Objekt können Sie wie folgt adressieren:

document.getElementsByTagName("canvas")[1]

Vorausgesetzt, dass der Seitenaufbau, welcher durch das Tool erfolgt, keine weiteren Elemente mit dem Tag-Namen verwendet und die Reihenfolge erhalten bleibt. Aber die Wahrscheinlichkeit scheint mir hoch.

Wenn Sie nun testweise in SoSci Survey einmal unter Neue Frage -> Datei-Inhalte übertragen -> Einfache Zeichenfläche die entsprechende Vorlage anlegen, haben Sie dort ab // File transfer part das JavaScript, um den BIldinhalt als Bild an den Server zu schicken. Können Sie damit arbeiten?

by s109993 (12.0k points)
Danke für Ihre fixe Antwort.
Nur halb, ich habe den Teil unter File transfer gefunden, nur bezüglich der Anpassungen bin ich mir unsicher. Den Question Platzhalter habe ich direkt mit meiner internen Variable ersetzt und document.getElementsByTagName("canvas")[1] ganz unten bei new Scribbler(). Aber das war mehr geraten... geht bisher auch noch nicht.


// API wir eingesetzt
<div id="ggb-element"></div>

<script>  
    var ggbApp = new GGBApplet({"appName": "geometry", "width": 800, "height": 600, "showToolBar": true, "showAlgebraInput": true, "showMenuBar": true }, true);
    window.addEventListener("load", function() {
        ggbApp.inject('ggb-element');
    });

 // File transfer part
  function sendImage() {
    var imageBlob = canvas.toBlob("A001_04".sendBLOB);
    state = "sent";
    return true;
  }

  // Function to be called when the blob is to be send
  function blobGetter(blobHandler) {
    // Only send something when changed since init or sent
    if (state !== "changed") {
      return false;
    }
    canvas.toBlob(blobHandler);
    state = "sent";
    return true;
  }


  // Alway send on form submission
  window.addEventListener("load", function() {
    "A001_04".registerOnSubmit(blobGetter);
  });
}

new Scribbler("A001_04", document.getElementsByTagName("canvas")[1]);
</script>
by SoSci Survey (330k points)
Sie haben oben das function Scribbler() gelöscht, oder? Das ist die Definition der Klasse, die Sie unten aufrufen möchten. Lassen Sie die folgenden drei Zeilen zu Beginn bitte einmal stehen:

<script>
function Scribbler(qID, canvas) {
  var state = "new";  // new, init, changed, sent

Das Ganze natürlich weiterhin im Rahmen einer Frage "Datei-Inhalte übertragen".

Und lassen Sie ruhig die Platzhalter %q.id% im Code stehen. Zumal das mit den Anführungszeichen im addEventListener() so nicht stimmt.
by s109993 (12.0k points)
Nur damit ich das richtig verstehe:

>> Das Ganze natürlich weiterhin im Rahmen einer Frage "Datei-Inhalte übertragen".

Ich verwende diesen Fragetype, um die Bilder im Canvas der API abzuspeichern.

Dafür lösche ich im Script des Fragetypes alles raus, außer den Bereich unter "File transfer part"  und die oberen zwei Zeilen, welche die Klasse definieren.

Zudem ändere ich die underste Zeile des Script zu "new Scribbler("%q.id%", document.getElementsByTagName("canvas")[1]);"

Wie sieht dann die Seite bei Fragebogen zusammenstellen aus?
 
- replace('%q.id%', 'A004');
- API wird eingebunden
- Frage wird eingebunden über question("A004");
by SoSci Survey (330k points)
> Wie sieht dann die Seite bei Fragebogen zusammenstellen aus?

Der Platzhalter %q.id% wird von der Frage selbst gesetzt. Es sollte also ausreichen, die API einzubinden und darunter die Frage. Und dann wird es vermutlich noch die ein oder andere Kleinigkeit geben, die ich übersehen habe. Aber das sollte sich aus der Fehlerkonsole im Browser ergeben.
by s109993 (12.0k points)
hm, soweit so gut. Ich habe die Anpassungen so durchgeführt.

############################
- API wird eingebunden:
############################

<meta name=viewport content="width=device-width,initial-scale=1">  
<meta charset="utf-8"/>
<script src="https://www.geogebra.org/apps/deployggb.js"></script>
<div id="ggb-element"></div>

<script>  
    var ggbApp = new GGBApplet({"appName": "geometry", "width": 800, "height": 600, "showToolBar": true, "showAlgebraInput": true, "showMenuBar": true }, true);
    window.addEventListener("load", function() {
        ggbApp.inject('ggb-element');
    });

</script>

###########################
-Frage wird eingebunden:
Script in der Frage:
###########################

<script>
function Scribbler(qID, canvas) {
  var state = "new";  // new, init, changed, sent
 
  
  // File transfer part
  function sendImage() {
    var imageBlob = canvas.toBlob(%q.id%.sendBLOB);
    state = "sent";
    return true;
  }

  // Function to be called when the blob is to be send
  function blobGetter(blobHandler) {
    // Only send something when changed since init or sent
    if (state !== "changed") {
      return false;
    }
    canvas.toBlob(blobHandler);
    state = "sent";
    return true;
  }


  // Alway send on form submission
  window.addEventListener("load", function() {
    %q.id%.registerOnSubmit(blobGetter);
  });
}

new Scribbler("%q.id%", document.getElementsByTagName("canvas")[1]);
</script>


Leider wird noch nichts abgespeichert. In der Ablage erscheint noch ein Missinwert. Die Konsole gibt auch keine Fehlermeldung wieder, an der ich mich orientieren könnte. Der Pretest Link ist noch derselbe: https://ofb.iea-hamburg.de/ceco/?act=9XdryDKWw3A7G1GneDzDASHd

Vielleicht entdecken Sie ja noch einen Fehler.

Viele Grüße
by SoSci Survey (330k points)
Fügen wird doch mal ein wenig Debugging-Code ein:

function blobGetter(blobHandler) {
    console.log("blobGetter", blobHandler);
    // Only send something when changed since init or sent

Und hier auch:

function sendImage() {
    console.log("sendImage");
    var imageBlob = canvas.toBlob(%q.id%.sendBLOB);

Dann können wir schonmal prüfen, ob die Funktionen überhaupt aufgerufen werden.
by s109993 (12.0k points)
Nachdem ich den Debugging Code eingefügt habe, zeigt mir die Konsole keine Auffälligkeiten an bzw. kein Hinweis auf die beiden Funktionen. Wenn ich auf "Weiter" klicke, taucht in der Konsole allerdings für eine Sekunde etwas aus, das nach "Blob" aussieht- aber leider zu schnell wieder weg um etwas zu erkennen.
by s109993 (12.0k points)
edited by s109993
Up :)

Mein Problem ist nach wie vor dasselbe. Auch verstehe ich nicht, wie ich die Zeichenfläche des API und die Frage vom Fragetype verbinden kann, das der oben genannte Code greift.

In der Console habe ich folgendes gefunden, nachdem ich auf "weiter" geklickt habe.

blobGetter ƒ (a,c){SoSciTools.submitButtonsHide();c&&(g=c);var b=new FormData;b.append("ajax","transfer");b.append("i",p);b.append("file01",a);b.append("data",JSON.stringify([{k:r,blob:"file01"}]));
e.open("POST"…
by SoSci Survey (330k points)
Thanks :)

> In der Console habe ich folgendes gefunden, nachdem ich auf "weiter" geklickt habe.

Gut, das ist die Ausgabe von
console.log("blobGetter", blobHandler);

Die Funktion wird also schonmal aufgerufen. Sehr schön.

Nun steht in Ihrer Methode blobGetter() ja folgendes:

 if (state !== "changed") {
      return false;
  }

Als nächstes wäre also zu klären, was in der Variable state steht - schreiben Sie also vor diese Zeilen bitte:

console.log("state",  state);

Die "state" Variable sollte vom Zeichenfeld auf "changed" gesetzt werden, wenn sich am Inhalt etwas ändert. Wenn Sie das nicht unterbringen können, dann können Sie die drei Zeilen auch mal auskommentieren, damit gar nicht erst geprüft wird, ob etwas am Bild geändert wurde.
by s109993 (12.0k points)
Nachdem ich console.log("state",  state); eingebaut habe, erscheint nach beim Klick auf "Weiter" "state new" in der Console. Ohne den Klick auf Weiter, habe ich keine Veränderungen in der Konsole.
Ich habe daraufhin versucht, den console.log Befehl direkt einzugeben. Das gibt mir "state is not defined" zurück.

Nachdem ich folgende drei Zeilen auskommentiert habe:
// console.log("state",  state);
//   if (state !== "changed") {
//   return false;
//   }

bekomme ich folgende Fehlermeldung in der Konsole, nachdem ich auf "Weiter" klicke;

?act=2dzByaqm9SNk2KgRsPxA52tD:443 Uncaught TypeError: Cannot read property 'toBlob' of undefined
    at blobGetter (?act=2dzByaqm9SNk2KgRsPxA52tD:443)
    at QuestionTransfer.min.js?i=1268:3
    at HTMLFormElement.e (SoSciTools.min.js?i=1287c:99)
by SoSci Survey (330k points)
Gut, wir kommen voran.

>  erscheint nach beim Klick auf "Weiter" "state new" in der Console

Das war das erste Problem: Das Zeichenfeld hatte die Variable "state" nicht geändert (woher sollte es auch davon wissen) und der Code dachte deshalb, er hätte nichts zu übermitteln.

Also weiter mit dem nächsten Problem...

> Cannot read property 'toBlob' of undefined

Das bezieht sich auf diese Zeile:

var imageBlob = canvas.toBlob(%q.id%.sendBLOB);

Und die beschwerde lautet, dass die Variable canvas keine Zeichenfläche beinhaltet. Wir hatten ganz oben mal über folgende Zeile geschrieben:

document.getElementsByTagName("canvas")[1]

Genau das funktioniert im Moment wohl noch nciht so ganz. Fügen Sie zum Testen ganz am Ende (unter dem new Scribbler) mal bitte folgendes ein:

console.log(document.getElementsByTagName("canvas"));
console.log(document.getElementsByTagName("canvas")[0]);
console.log(document.getElementsByTagName("canvas")[1]);
by s109993 (12.0k points)
Der Output in der Konsole ist folgender :
HTMLCollection(2)
0: canvas
1: canvas
length: 2
__proto__: HTMLCollection

Beide Canvas lassen sich aufklappen, wobei 1: canvas sich auf die Fläche der API bezieht (wird blau hinterlegt, wenn ich ihn in der Konsole anklicke).

Hier auch nochmal der Pretest Link auf die Seite, falls das irgendwie weiterhilft:
https://ofb.iea-hamburg.de/ceco/?act=64fds5yRZFSf9vZ8Ji4VNJPi
by SoSci Survey (330k points)
Hmmm ... dann sollte die Variable eigentlich korrekt geladen werden.

Könnten Sie direkte unter dem

function Scribbler(...

bitten noch ein console.log() setzen:

console.log("Pos1", canvas);

Außerdem nochmal die Kontrolle der Variable in sendImage()

function sendImage() {
    console.log("sendImage", canvas);
    var imageBlob = canvas.toBlob(%q.id%.sendBLOB);
by s109993 (12.0k points)
Sehr gerne!

console.log("Pos1", canvas);
--> führt zu "Uncaught ReferenceError: canvas is not defined"

Falls ich nichts übersehen habe, führt  console.log("sendImage", canvas);
zu keinem Eintrag in der Konsole.

Zusätzlich sind aber auch zwei Einträge mit "undefined" in der Konsole zu sehen. Hier weiß ich nicht woher genau die kommen.
by SoSci Survey (330k points)
> Zusätzlich sind aber auch zwei Einträge mit "undefined" in der Konsole zu sehen. Hier weiß ich nicht woher genau die kommen.

Ich schon ... das sind die beiden nächsten Zeilen hier:
console.log(document.getElementsByTagName("canvas"));
console.log(document.getElementsByTagName("canvas")[0]);
console.log(document.getElementsByTagName("canvas")[1]);

Das erste funktioniert, die zweite und dritte Zeile nicht ... wenn ich die Zeilen nach dem vollständigen Laden der Seite in die Konsole eintrage, funktioniert es.

Das spricht dafür, dass die Zeichenflächen zum Zeitpunkt der Ausführung noch nicht fertig initialisiert sind. Dasgegen sollte es helfen, wenn man den Aufruf eine Sekunde verzögert.

Bitte ergänzen Sie hier ein paar Zeilen:

  // Send on form submission
  window.addEventListener("load", function() {
    window.setTimeout(function() {
      A004.registerOnSubmit(blobGetter);
    }, 1000);
  });
by s109993 (12.0k points)
Ich habe den oberen Code für diesen hier eingesetzt- nicht sicher, ob das richtig war. Ich konnte allerdings keinen Unterschied in der Konsole feststellen. Auch nicht, als ich den timeout erhöht habe.

  // Alway send on form submission
   window.addEventListener("load", function() {
   %q.id%.registerOnSubmit(blobGetter);
  });
by SoSci Survey (330k points)
> Ich habe den oberen Code für diesen hier eingesetzt-

Das wäre richtig gewesen, aber soweit ich auf der Seite sehen, haben Sie den Code ganz oben zusätzlich ergänzt. Oben bitte entfernen ziemlich gegen Ende den von Ihnen genannten Code ersetzen.
by s109993 (12.0k points)
Entschuldigen Sie, da hatte ich nach der Änderung vergessen zu speichern.
Der Code sitzt jetzt an der richtigen Stelle. Allerdings kann ich trotzdem keine Änderung erkennen- bzw. beide "undefined" sind noch da.
by SoSci Survey (330k points)
Hmmm ... stimmt. Okay, neuer Plan. Ersetzen Sie den Code oben wieder durch den vorigen und verzögern Sie den Scribbler-Aufruf ganz am Ende:


window.addEventListener("load", function() {
    window.setTimeout(function() {
      new Scribbler("A004", document.getElementsByTagName("canvas")[1]);
    }, 1000);
});

Die console.log() direkt darunter können Sie entfernen.

Das nächste mal beauftragen Sie die Integration direkt bei mir - ich denke, es geht schneller, wenn ich mich für eine Stunde in dem Projekt einlogge und die Programmierung übernehme ;)
by s109993 (12.0k points)
Wir können das gerne auch auf diesem Weg machen, wenn das Ihnen lieber ist.

Ich habe den Code ergänzt, Console zeigt keine Auffälligkeiten, aber Bilder werden auch noch nicht abgespeichert.

Sorry, dass ich hier so unwissentlich agiere- aber wie Sie sich sicher vorstellen können, bin ich nicht wegen meinen JS Fähigkeiten angestellt worden ;)
by SoSci Survey (330k points)
Wollen Sie mir auf dem Server einen Login auf die E-Mail-Adresse info@soscisurvey.de einrichten und diesem Login das Projekt freigeben? Wenn Sie mir anschließend eine kurze Mail senden, in welchem Fragebogen auf welcher Seite ich den Code finde, schau ich mal rein.

Passwort brauchen Sie nicht verschicken, das kann ich über die Mailadresse selbst (zurück-)setzen.
by s109993 (12.0k points)
Gerne, ich habe Ihnen eine Mail dazu geschrieben, allerdings mit meinem persönlich Log In. Ich kann leider nicht ohne weiteres neue Email Adressen freigeben. Ich hoffe, dass geht trotzdem.

Willkommen im Online-Support von SoSci Survey.

Hier bekommen Sie schnelle und fundierte Antworten von anderen Projektleitern und direkt von SoSci Survey.

→ Eine Frage stellen


Welcome to the SoSci Survey online support.

Simply ask a question to quickly get answers from other professionals, and directly from SoSci Survey.

→ Ask a Question

...