0 votes
in SoSci Survey (dt.) by s057478 (175 points)
reopened by s057478

Für spezielle Fragetypen habe ich ein Canvas angelegt, mittels dem man auf einfache Art Freiformen zeichnen kann. Diese Formen möchte ich gerne direkt als Bild (PNG) ablegen. Ic hhabe den Tipp bekommen, dafür den Fragetyp "Datei-Inhalte übertragen" zu verwenden. So könnten die Bilder auch im Hintergrund an den Server übermittelt und dort als Dateien abspeichert werden.
Mittels JavaScript müsste dafür gesorgt werden, dass das Canvas die Daten als PNG liefert.

Nun bin ich nicht der Programmier-Profi und komme mit den Zusammenhängen nicht zurecht.

1.) Canvas-Code
Im HTML-Code des Canvas habe ich

function prepareImg() {
     var canvas = document.getElementById('canv');
     document.getElementById('inp_img').value = canvas.toDataURL();
  }

eingefügt und lt. Anleitung soll in der Datei auch das PHP

<?php
 
if (count($_POST) && (strpos($_POST['img'], 'data:image/png;base64') === 0)) {
     
  $img = $_POST['img'];
  $img = str_replace('data:image/png;base64,', '', $img);
  $img = str_replace(' ', '+', $img);
  $data = base64_decode($img);
  $file = 'uploads/img'.date("YmdHis").'.png';
   
  if (file_put_contents($file, $data)) {
     echo "<p>Der Canvas wurde gespeichert als $file.</p>";
  } else {
     echo "<p>Der Canvas konnte nicht gespeichert werden.</p>";
  } 
   
}
                      
?> 

eingefügt werden. Da bin ich mir schon unsicher, ob der PHP-Code nicht auf der Fragebogenseite platziert werden müsste.

2.) Implementieren des Canvas beim Fragetyp "Datei-Inhalte übertragen"
Weiß ich nicht, wie ich das Canvas im Fragetyp unterbringen soll. Zwar kann ich es per iframe im HTML-Code anbringen, aber das funktioniert zwar zum Malen, aber nicht mit dem Upload. Entweder, weil Fehler im Canvas sind (s.o.) oder weil der Upload so nicht funktionieren kann mangels Verbindung zum Server.

3.) Befüllen der Felder unter "Frage bearbeiten" und Ergänzungen auf der Seite
Außerdem erschließt sich mir gar nicht, wie die Übertragung überhaupt funktioniert (auch nicht mit Audiodaten) und was im konkreten Fall für den Zweck der Übermittlung Bilddaten noch an Code ergänzt werden muss, damit der Fragetyp funktionieren kann. Und was muss auf der Seite bei der Zusammenstellung des Fragebogens noch angebracht werden?

Aber vielleicht gibt es auch eine einfachere Lösung zur Übertragung von Bilddaten, die zum Zwecke einer Fragenbeantwortung am Bildschirm gezeichent werden sollen?

2 Answers

+1 vote
by SoSci Survey (302k points)
selected by s057478
 
Best answer

Wenn, dann wird es richtig gemacht ... danke für die Geduld :)

Warum hat Ihr Code nicht funktioniert? Er hat funktioniert. Nur wurde außerhalb der sichtbaren Zeichenfläche gezeichnet. Denn Ihr Code hat für den Strich die aktuelle Position des Mauszeigers verwendet. Und wenn die Zeichenfläche nicht links oben auf der Seite ist, dann landet der Strich nicht dort, wo man ihn erwartet.

Und nachdem ich es gleich richtig machen wollte, habe ich den Code ein wenig ergänzt (insb. um eine Option, um das Bild zu löschen bzw. einen Strich rückgängig zu machen) und eine Frage-Vorlage für SoSci Survey daraus gemacht. Auch die Übermittlung des Bildes an den Server ist dort natürlich gleich integriert. Zu finden ab sofort als "Einfache Zeichenfläche", wenn Sie mit der Maus über den Fragetyp "Datei-Inhalte übermitteln" fahren.

Eine wichtige EInschränkung gibt es allerdings: Mit einem eventuellen Zurück-Knopf im Fragebogen funktioniert das Ganze nicht.

by s057478 (175 points)
Ich bin begeistert! :-))) In der Danksagung in meiner Masterarbeit werden Sie einen Ehrenplatz erhalten :-)

Eine Frage hätte ich noch (oder soll ich die als eigene Frage neu einstellen?): Im Moment steht in der Auswertung für bei meiner neu angelegten Testfrage nach dem Absenden der Wert "2". Wo kommt der her?

Und ich will ja nicht unverschämt sein, aber ist es prinzipiell auch möglich, mehrere Felder auf eine Seite zu stellen und diese auszählen zu lassen so das ich für z.b. 4 gemalte Kästchen als Wert zu dieser Frage 4 erhalte?
by SoSci Survey (302k points)
Der Datensatz selbst speichert nur, ob Daten übertragen wurden. Was die 2 bedeutet, sehen Sie in der Variablen-Übersicht.

Die Vorlage sollte (!) so ausgelegt sein, dass Sie auch mehrere Zeichenflächen auf der Seite platzieren können ohne, dass sich diese in die Quere kommen. Allerdings ist es dann mit dem Übermitteln und dem "Weiter" nicht so ganz einfach. Vermutlich müssten Sie für jede Zeichenfläche noch eine Variable speichern, ob überhaupt etwas gemalt wurde (relativ einfach). Und nur wenn ja, dann sollen am Ende die Daten übermittelt werden.

Mit ein wenig PHP-Code auf der folgenden Fragebogen-Seite können Sie dann die Anzahl der 2er abzählen. Die Details klären wir dann aber in einer neuen Frage ;)
by s057478 (175 points)
Danke für den Hinweis. Ich habe eine neue Frage "Mehrere auf einer Seite platzierte Zeichenflächeninhalte übertragen und auszählen" eingestellt.
+1 vote
by SoSci Survey (302k points)

Keine Sorge ... der Einsteig in die Programmierung ist immer mit einer steilen Lernkurve verbunden. Aber rückblickend ist es dann nur halb so schlimm :)

Als erstes benötigen Sie den Canvas direkt im Fragebogen, nicht in einem iFrame. Das sollte sich mit einem Textbaustein "HTML-Code" recht gut lösen lassen.

Dann verwenden Sie bereits die Funktion toDataURL(). Diese wandelt das Bild in einen Text um. Was Sie aber für die Frage "Dateiinhalte übertragen" benötigen ist ein BLOB (ein Binärobjekt). Das bekommen Sie mittels toBlob().

Und dieses können Sie dann an die Frage "Dateiinhalte übertragen" übergeben.

Jetzt brauchen Sie nur noch einen Auslöser. Also eine Bedingung, wann das Bild als BLOB ausgegeben und an den Server übermittelt werden soll. Der naheliegende "Weiter"-Knopf ist dafür nur bedingt geeignet, denn er will gleich zur nächsten Seite. Aber davor soll ja das Bild übermittelt werden.

Mit SoSciTools.questionnaire.attachCheck() können Sie aber eine Funktion definieren, die beim Klick auf "Weiter" erstmal ausgeführt werden soll. Das könnte dann wie folgt aussehen (einzutragen in der Frage bei "Zusätzlicher HTML-Code"):

<script type="text/javascript">
var blobSent = false;
SoSciTools.questionnaire.attachCheck(function() {
    var canvas = document.getElementById('canv');
    var imageBlob = canvas.toBlob();
    // Transfer the data
    %q.id%.sendBLOB(imageBlob);
    blobSent = true;
    return true;
});
</script>

Vermutlich wird das nicht auf Anhieb funktionieren (pardon ... das wäre zu einfach) - aber wenn Sie es schonmal damit versuchen, können Sie zumindest schonmal in der JavaScript-Fehlerkonsole des Browsers nachsehen, warum es nicht funktioniert und einen Pretest-Link (bitte direkt zur Seite mit dem Canvas) posten, damit wir einen Blick darauf werfen können.

by SoSci Survey (302k points)
PS: Posten Sie auch gerne einmal den Link zu dem Zeichenbrett-Script, welches Sie verwenden. Wenn das etwas Hübsches ist, können wir das gerne einmal als Vorlage in SoSci Survey aufnehmen (so wie den Audio-Recorder). Sie sind sicher nicht die einzige, die so eine Funktion benötigt.
by s057478 (175 points)
edited by s057478
Erst mal Danke für die Ermutigung. Die kann ich im Moment gut gebrauchen ;-) . Ich denke auch, dass eine solche Funktion auch für Andere nützlich sein kann. Hier zunächst mal der Canvas-Code (Ob es hübsch ist, überlasse ich Ihnen. Funktionell reicht es aus für das, was ich durchführen möchte):

<!DOCTYPE html>
<html><head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8">
        <title>Malbox</title>
        <style type="text/css" media="screen">
            body { background:#e6f2ff; color:#FFF; text-align:left; font-size:90%; font-family:Verdana, Geneva, Arial, Helvetica, sans-serif; margin:0; padding:0; }
            canvas { cursor:crosshair; background:#FFF; margin:16px; }
            p { margin:16px; }
      canvas { border: 1px solid black; }
    </style>

    </head><body><canvas id="Malflaeche" width="300" height="300" style="position: absolute;"></canvas>

<script>
(function () {
var el = document.getElementById('Malflaeche');
var ctx = el.getContext('2d');
var isDrawing;


el.onmousedown = function(e) {
  isDrawing = true;
  ctx.lineWidth = 3;
  ctx.lineJoin = ctx.lineCap = 'round';
   ctx.shadowBlur = 5;
   ctx.shadowOffsetX =-5
    ctx.shadowOffsetX =-5
  ctx.shadowColor = 'rgb(0, 0, 0)';
  ctx.moveTo(e.clientX, e.clientY);
};
el.onmousemove = function(e) {
  if (isDrawing) {
    ctx.lineTo(e.clientX, e.clientY);
    ctx.stroke();
  }
};
el.onmouseup = function() {
  isDrawing = false;
};
})();
 var canvas = document.getElementById('malflaeche');

canvas.toBlob(function(blob) {
  var newImg = document.createElement('img'),
      url = URL.createObjectURL(blob);

  newImg.onload = function() {
    // no longer need to read the blob so it's revoked
    URL.revokeObjectURL(url);
  };

  newImg.src = url;
  document.body.appendChild(newImg);
});

    </script>

</body></html>


Leider habe ich ihn auf der SoSCi Survey-Seite zwar platzieren können, aber das Malen funktioniert dort nicht und der Rahmen sitzt noch "schief".
Im Backend: https://www.soscisurvey.de/admin/index.php?o=Questionnaire&a=edit&id=361668
Im Frontend: https://www.soscisurvey.de/preferLU2019/?q=base&admin&debug&page=13&l=ger

Da ich noch nix malen kann, kann ich auch noch nichts aufnehmen.


Ob der von Ihnen angegebene Zusatzcode bei der Frage hier https://www.soscisurvey.de/admin/index.php?o=question&section=939596&question=6434038 sitzen muss, oder auf der Seite ist mir auch noch unklar.

Würde mich freuen, wenn Sie mir weiterhelfen könnten.

**Ach, beinah hätte ich es vergessen, die Fehlermeldung derzeit ist:**

TypeError: canvas is null[Weitere Informationen] preferLU2019:448:1
<anonym>
https://www.soscisurvey.de/preferLU2019/:448:1
by SoSci Survey (302k points)
Erstmal muss der Canvas funktionieren... dann können wir uns um die Übertragung zum Server kümmern.

Also ... Eine HTML-Seite (und damit auch ein Fragebogen) besteht aus einem <head>-Teil und einem <body>-Teil. Und zwar unr einer davon. Was Sie als HTML-Code einbinden, landet automatisch im <body>-Teil.

Das heißt: Den <style>-Teil aus Ihrm Code, der in den <head> gehört, müssen Sie entweder im Fragebogen-Layout einbinden oder per PHP-Code mit dem Befehl pageCSS()

pageCSS('
    canvas { cursor:crosshair; background:#FFF; margin:16px; }
    canvas { border: 1px solid black; }
');

Im HTML-Code bleibt dann nur noch das, was bei Ihnen aktuell zwischen <body> und </body> steht.

> TypeError: canvas is null[Weitere Informationen] preferLU2019:448:1
<anonym>

Wenn Sie mal in Ihren HTML-Code sehen, hat das <canvas>-Element dort die Kennung (id) "Malflaeche". Also müssten Sie den Code aus meinem obigen Posting wie folgt abändern (s. dritte/vierte Zeile):

<script type="text/javascript">
var blobSent = false;
SoSciTools.questionnaire.attachCheck(function() {
    var canvas = document.getElementById('Malflaeche');
    var imageBlob = canvas.toBlob();
    // Transfer the data
    %q.id%.sendBLOB(imageBlob);
    blobSent = true;
    return true;
});
</script>

> Ob der von Ihnen angegebene Zusatzcode bei der Frage hier ...  sitzen muss, oder auf der Seite ist mir auch noch unklar.

Setzen Sie ihn direkt in die Frage, denn sonst wird das %qID% nicht automatisch durch die Kennung der Frage ersetzt. Sie können darübr auch gleich Ihren HTML-Code für die Malfläche einfügen.

Woher stammt der Code denn, den Sie verwenden?
by s057478 (175 points)
edited by s057478
Nun habe ich die Struktur besser verstanden- danke. Mit den Änderungen ist die Fehlermeldung weg, aber leider funktioniert das Zeichnen noch nicht:

https://www.soscisurvey.de/preferLU2019/?q=base&admin&debug&page=13&l=ger

Den Canvas-Code habe ich mir aus verschiedenen Quellen zusammengeschraubt ;-), hauptsächlich von diesen:
https://www.mediaevent.de/javascript/canvas.html
https://developer.mozilla.org/de/docs/Web/API/HTMLCanvasElement/toBlob

Weitere Quellen:
https://developer.mozilla.org/de/docs/Web/Guide/HTML/Canvas_Tutorial/Grundlagen
bezogen sich jedoch auf Zeichnen, nicht auf Freihandmalen und die beiden hier auch:
https://docs.oracle.com/javafx/2/canvas/jfxpub-canvas.htm und
http://www.codeadventurer.de/?p=1501
weshalb ich diese Anleitungen nicht verwendet habe.

Und die Anleitung hier war mir zu komplex:
http://perfectionkills.com/exploring-canvas-drawing-techniques/

Da gibt es offenbar viele Wege, um das Freihandzeichnen umzusetzen. Da der erstellte Code aber im Browser funktioniert hat, weiß ich nicht, woran es jetzt liegt, dass es im Fragebogen nicht geht. Ist die Ausführung des Scripts vielleicht in Teilen unterbunden?

Und hier war dann noch ein PHP-Empfangsscript enthalten:
https://www.askingbox.de/tutorial/html5-canvas-als-bild-an-server-senden-und-speichern
das aber in der SosciSurvey-Umgebung vermutlich nicht erlaubt ist - oder?
by SoSci Survey (302k points)
Ich bräuchte bitte einen richtigen Pretest- oder Vorschau-Link, danke:
https://www.soscisurvey.de/help/doku.php/de:survey:pretest#online-pretest

> Und hier war dann noch ein PHP-Empfangsscript enthalten:
> das aber in der SosciSurvey-Umgebung vermutlich nicht erlaubt ist - oder?

Das ist nicht nur nicht erlaubt, sondern auch überflüssig ... glauben Sie mir: Damit die Dateien am Ende noch zum richtigen Fall (CASE) gespeichert werden, ist noch ein gutes Stück mehr erforderlich. Deshalb kümmert sich ja die Frage "Datei-Inhalte übertragen" darum :)
by s057478 (175 points)
O.K.. Danke dafür: :). Hier erst einmal der Pretest-Link:
https://www.soscisurvey.de/preferLU2019/?act=d5lkcPSSvjW77P0w6ilItPkW
by SoSci Survey (302k points)
Danke - der Fehler ist leider nicht so schnell zu finden, wie ich gehofft hatte. Ich muss erstmal ein Testprojekt dafür aufsetzen, um die Abläufe im JavaScript genauer unter die Lupe zu nehmen. Mit etwas Glück habe ich morgen aber eine Lösung.
by s057478 (175 points)
Das wäre super :-)

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

...