Seite 1 von 2

Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Montag 3. Juni 2024, 11:35
von Patrick1990
Hallo,
ich habe etwas mit Flask gearbeitet und stehe an einer Stelle, an der ich nicht weiter komme.
Dazu habe ich ein Minimalbeispiel erstellt.
Ich würde gern etwas in einem HTML-Canvas zeichen und die Zeichnung in Abhängigkeit von Slider-Werten verändern.
Das Auslesen der Slider-Werte und die direkte Weiterleitung an Python habe ich schon implementiert. Auf dieser Basis werden mittels Python Koordinaten neu berechnet und an die HTML Zeichnung zurückgegeben. Die Rückgabe funktioniert allerdings nicht und ich weiß auch nicht, wie ich es lösen soll.
Zudem habe ich noch einige Fragen bzgl. Javascript, aber die passen dann besser in ein anderes Forum.
Im Minimalbeispiel sollen die aktuellen Slider-Werte von Python an das HTML-Canvas gesendet und angezeigt werden.
Könnt ihr mir da weiter helfen?

app.py

Code: Alles auswählen

from flask import Flask, render_template, request
import json



app = Flask(__name__)

dict_default = {}
dict_default['A'] = 0.1
dict_default['B'] = 0.2
dict_default['C'] = 0.3

@app.route('/', methods=['GET', 'POST'])
def index():
    print('Startseite')
    print(dict_default)
    return render_template('index.html', dict_default=dict_default, dict_default_json=json.dumps(dict_default))


@app.route('/update', methods=['POST', 'GET'])
def update():
    print('Update')
    data = json.loads(request.data)
    for key, value in data.items():
        dict_default[key] = value
    print(dict_default)
    return render_template('index.html', dict_default=dict_default, dict_default_json=json.dumps(dict_default))


if __name__ == '__main__':
    app.run(debug=True, port=5000)

index.html

Code: Alles auswählen

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<form>
    <p>
        <canvas id="canvas1" width="200" height="200"></canvas>
    </p>

    {% for key, value in dict_default.items() %}
        <p>
            <label>{{ key }}: <span class="bold" id="{{ 'val' ~ loop.index }}"> {{ value }} </span></label>
            <input type="range" min="0" max="1" value="{{ value }}" step="0.1" class="myslider" id="{{ 'rs' ~ loop.index }}">
    {% endfor %}

</form>

<meta id="my-data" data-default="{{ dict_default_json }}">


<script>
    function createVariablesSlider(json_count){
        var rangeslider = [];
        for (var i = 1; i <= json_count; ++i) {
          rangeslider[i] = document.getElementById('rs'.concat(i.toString()));
        }
        return rangeslider;
    }
    function createVariablesOutput(json_count){
        var output = [];
        for (var i = 1; i <= json_count; ++i) {
          output[i] = document.getElementById('val'.concat(i.toString()));
        }
        return output;
    }

    const Http = new XMLHttpRequest();
    var json_default = $('#my-data').data("default");
    var json_count = Object.keys(json_default).length;
    var current;
    const sliders = document.getElementsByClassName("myslider");

    const canvas = document.getElementById("canvas1");
    const ctx = canvas.getContext("2d");
    var boxwidth = canvas.width;
    var boxheight = canvas.height;

    ctx.clearRect(-canvas.width/2, -canvas.height/2, canvas.width, canvas.height);
    ctx.fillText('A: ' + json_default['A'], 100, 60)
    ctx.fillText('B: ' + json_default['B'], 100, 80)
    ctx.fillText('C: ' + json_default['C'], 100, 100)


    rangeslider = createVariablesSlider(json_count);
    output = createVariablesOutput(json_count);


    // Loop?
    rangeslider[1].oninput = function() {
        current = this.value;
        output[1].innerHTML = current;
        Http.open('POST', '/update');
        var obj = new Object();
        // Loop?
        obj.A = sliders[0].value;
        obj.B = sliders[1].value;
        obj.C = sliders[2].value;
        Http.send(JSON.stringify(obj));
    }
    rangeslider[2].oninput = function() {
        current = this.value;
        output[2].innerHTML = current;
        Http.open('POST', '/update');
        var obj = new Object();
        // Loop?
        obj.A = sliders[0].value;
        obj.B = sliders[1].value;
        obj.C = sliders[2].value;
        Http.send(JSON.stringify(obj));
    }
    rangeslider[3].oninput = function() {
        current = this.value;
        output[3].innerHTML = current;
        Http.open('POST', '/update');
        var obj = new Object();
        // Loop?
        obj.A = sliders[0].value;
        obj.B = sliders[1].value;
        obj.C = sliders[2].value;
        Http.send(JSON.stringify(obj));
    }



</script>

</body>
</html>

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Montag 3. Juni 2024, 13:46
von Sirius3
`jquery` würde ich ja in neuem Javascript-Code nicht mehr verwenden (also neu im Sinne von seit 10 Jahren nicht mehr).
Soweit ich sehe, benutzt Du $ auch nur für einen sehr trivialen Fall um auf dataset zuzugreifen.
Ungefähr genauso lange benutzt man XMLHTTPRequest nicht mehr, weil das durch fetch ersetzt worden ist.
Das setzen von on<xxx> wurde schon vor noch längerer Zeit durch addEventListener ersetzt.

Deine Slider hast Du einmal in der Variable `sliders` und einmal in `rangeslider`, eine davon kann weg.
Bei Deinen Paragraphen fehlt das </p>
Auch bei HTML sollte man nichtssagende Präfixe wie my oder Nummern an Namen wie canvas1 vermeiden und statt dessen aussagekäftige Namen verwenden.

Das ganze könnte daher ungefähr so aussehen:

Code: Alles auswählen

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    <p>
        <canvas id="tolle_grafik" width="200" height="200"></canvas>
    </p>

    {% for key, value in dict_default.items() %}
        <p>
            <label>{{ key }}: <span class="bold"> {{ value }} </span></label>
            <input type="range" min="0" max="1" value="{{ value }}" step="0.1" class="range_slider" data-key="{{key}}">
        </p>
    {% endfor %}

</div>

<script>
    function get_slider_values() {
        const data = {};
        for(const slider of rangesliders) {
            data[slider.dataset.key] = slider.value;
        }
        return data;
    }

    async function slider_changed(event) {
        const paragraph = this.closest('p')
        paragraph.querySelector('span.bold').innerHTML = this.value;

        const data = get_slider_values();
        const response = await fetch("/update", {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
            },
            body: JSON.stringify(data),
        });
        // TODO: update canvas
        // const result = response.json();
    }

    const rangesliders = document.getElementsByClassName('range_slider')
    for(const slider of rangeslider) {
        slider.addEventListener("input", slider_changed)
    }

    const json_default = get_slider_values();

    const canvas = document.getElementById("tolle_grafik");
    const ctx = canvas.getContext("2d");
    var boxwidth = canvas.width;
    var boxheight = canvas.height;

    ctx.clearRect(-canvas.width/2, -canvas.height/2, canvas.width, canvas.height);
    ctx.fillText('A: ' + json_default['A'], 100, 60)
    ctx.fillText('B: ' + json_default['B'], 100, 80)
    ctx.fillText('C: ' + json_default['C'], 100, 100)
</script>

</body>
</html>
Im Code fehlt noch der eigentliche Code, nämlich, Dein Canvas zu aktualisieren.
Die /update-Methode sollte dann auch kein komplettes HTML zurückliefern, sondern eine Beschreibung, wie das Canvas aktualisiert werden soll, idealerweise in Form von JSON-kodierten Daten.

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Montag 3. Juni 2024, 15:17
von Patrick1990
Vielen Dank für die nützlichen Tipps und Hinweise. Ich hatte mir das alles aus zahlreichen Foren zusammengebastelt.
Nun wäre noch die Frage wie man das mit dem "update canvas" angeht. Wie macht man das sinnvoll und zeitgemäß? Ich habe bisher eine Lösung, jedoch auch nur mit diesem $-Operator.

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Montag 3. Juni 2024, 20:42
von Sirius3
Den Context hast Du doch bereits als globale Variable. Und dann zeichnest Du ganz normal. Was auch immer Du darstellen möchtest.

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Montag 3. Juni 2024, 20:45
von Patrick1990
Ich habe ja folgendes vor:
- Sliderwerte zu Python senden (funktioniert)
- Mittels der Werte neue Koordinaten berechnen (funktioniert)
- Neue Koordinaten von Python zum Context senden & zeichnen (das müsste doch irgendwie mittels GET funktionieren, habe es bisher aber nicht so richtig geschafft)

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Montag 3. Juni 2024, 20:59
von Sirius3
Wie Zeichnest Du denn Deine Koordinaten auf das Canvas?
Die Information schickt Dein Post-Request JSON-Kodiert an den Browser, und dort hast Du dann den Code, der zeichnet.

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Montag 3. Juni 2024, 21:03
von Patrick1990
Ich zeichne mittels Javascript in dem Canvas.
Ich kann morgen mal ein Beispiel dazu senden.
Ich würde gern die Koordinaten von Python an Java senden und dort dann zeichnen. Vielleicht drücke ich mich aber auch falsch aus.
Beispiel folgt :)

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Dienstag 4. Juni 2024, 07:27
von Patrick1990
Beispielhaft sieht das so aus:

Code: Alles auswählen

const canvas = document.getElementById("canvas1");
const ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(100,100);
ctx.stroke();

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Dienstag 4. Juni 2024, 07:57
von Sirius3
Was ist Dein eigentliches Ziel? Was soll dargestellt werden? Warum ein Canvas? Warum nicht svg? Es gibt auch fertige Javascript-Bibliotheken, die komplexere Graphiken erzeugen können.

Wenn Du auf dem Level bleiben möchtest, dann bist Du schnell dabei, eine eigene Zeichnungssprache zu erfinden.

Code: Alles auswählen

[
    {"mode": "stroke", "points": [[0, 0], [100, 100]], "color": "red"},
]

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Dienstag 4. Juni 2024, 08:07
von Patrick1990
Ok ich versuche es mal zu beschreiben.
Ziel ist es eine Oberfläche zu erstellen, die Querschnitte eines Bauteils in Abhängigkeit von Parametern darstellt. Jeder Slider verstellt somit einen Parameter.
Ich habe in Python eine Klassse erstellt, welche die Koordinatenpunkte und die Art der Linie (Gerade, Kreisbogen) in Abhängigkeit der Parameter ausgibt.
Ich möchte also mit Hilfe der Sliderwerte eine Instanz der Klasse erstellen und die Koordinatenpunkte zurückgeben und entsprechend auf der Oberfläche die Punkte verbinden und darstellen.
Die Möglichkeit mit dem Canvas habe ich dabei öfter gesehen und fand sie nicht schlecht.
Später sollte jedoch auch eine Zoom-Funktion (evtl. auch Verschiebung) im Grafikfenster möglich sein, damit man Details gut erkennen kann.

Liege ich da komplett daneben oder ist die Idee mit dem Canvas geeignet dafür?
Ich freue mich auf jeden Fall sehr über deine Hilfe.

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Dienstag 4. Juni 2024, 10:13
von Sirius3
Wenn es nur um Linien geht, dass solltest Du Dir zu erst svg anschauen, ob das für Deine Zwecke geeignet ist. SVG ist ein Vektorformat, so dass Zoom, Verschieben, etc einfach über entsprechende Transformationen geht. Canvas sind Pixelgrafiken.

Bei svg würde dann der POST-Request einfach das komplette svg-Bild zurückliefern, dass man dann z.B. per innerHTML dem SVG-Container zuweisen kann.

https://itnext.io/javascript-zoom-like- ... c0df016d8d
https://jillix.github.io/svg.pan-zoom.js/

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Dienstag 4. Juni 2024, 10:19
von Patrick1990
Vielen Dank, dann mache ich das mal :)
Also müsste ich das svg-Bild in Python zeichnen oder benötigt man noch ein Javascript dazwischen?
Ich werde mal etwas recherchieren.

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Dienstag 4. Juni 2024, 15:41
von Patrick1990
Ok ich denke ich habs, danke!

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Dienstag 18. Juni 2024, 15:26
von Patrick1990
Hätte noch eine Frage zu HTML.
Ich habe die App jetzt auf einem Rechner laufen. Man kann von anderen Rechnern aus über die IP im Browser auf die App zugreifen. Ein Bestandteil dieser App ist das Öffnen eines bestimmten Ordners bei Klick auf einen Button.
Das habe ich so in Python implementiert, aber nicht daran gedacht, dass der Ordner immer auf dem Rechner geöffnet wird, der die App ausführt.
Nun wäre ja ein Workaround, den Ordner direkt per HTML aufzurufen, bspw. so:

Code: Alles auswählen

<a href="file:///G:/"><button>Ordner öffnen</button>Test</a>
Leider öffnet der Browser dann dennoch keinerlei Explorer. Wenn ich jedoch einen Rechtsklick auf die Schaltfläche tätige und dann "Link in einem neuen Tab öffnen" klicke, öffnet sich der File-Explorer.

Hat jemand eine Idee, woran es liegen könnte?

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Dienstag 18. Juni 2024, 16:06
von __blackjack__
@Patrick1990: Schau auf die Konsole vom Browser oder wo immer bei Deinem die Fehlermeldungen landen.

Webseiten können keine lokalen Dateien verlinken. Aus Sicherheitsgründen.

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Dienstag 18. Juni 2024, 17:51
von Sirius3
Das geht aus Sicherheitsgründen nicht. Warum soll ein Ordner geöffnet werden? Was ist der Zweck des Ganzen?

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Mittwoch 19. Juni 2024, 06:58
von Patrick1990
Die Console sagt folgendes: "Sicherheitsfehler: Inhalt auf http://127.0.0.1:8080/ darf file:///G:/ nicht laden oder verlinken."
Schade, das lässt sich sicher auch nicht beheben. Finde es nur seltsam, dass es geht, wenn ich die gewünschte Adresse in einem neuen Tab öffne.

Die Idee (der Zweck) ist folgende(r):
Einige Kollegen können über die Flask-Anwendung über Ihren Browser auf eine Datenbank zugreifen. In dieser Datenbank sind Protokolle hinterlegt und die zugehörigen Daten (oftmals mehrere GB pro Protokoll) sind in einem Ordner auf einem Netzwerklaufwerk abgelegt. Ich habe nun einen HTML-Button, der bei Betätigung diesen Ordner öffnen soll. Jedoch bei jedem der Kollegen auf Ihrem PC und nicht auf dem Host-PC.
Gibt es da evtl. noch eine andere Möglichkeit?

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Mittwoch 19. Juni 2024, 07:46
von Kebap
Ich glaube, Browser können einen "Datei öffnen"-Dialog anzeigen, zum Beispiel wenn man Fotos zu einem Sharehoster hochladen will.
Vielleicht hilft das schon in deinem Fall, wenn diese Popups direkt im Ordner mit den Protokollen starten, und die User das Protokoll anklicken können, je nachdem welches Format es ist, würde es im Browser geöffnet, oder in einer eigenen Anwendung.

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Mittwoch 19. Juni 2024, 08:51
von Sirius3
@Kebap: beim "Datei öffnen"-Dialog kann man aber nicht vorgeben, welches Verzeichnis da geöffnet werden soll.

@Patrick1990: Du kannst einen Copy-To-Clipboard-Button anbieten, so dass die Nutzerin nur im Explorer per Copy-Paste das Verzeichnis einfügen kann. Eventuell kannst Du auch auch alle Protokolle im Browser darstellen, so dass man gleich den Pfad zu einem bestimmten Protokoll kopieren kann.

Falls das Programm, das mit diesem Dateityp assoziiert ist, ein URL-Schema registriert hat, kann man damit auch direkt die Applikation öffnen, z.B. bei Excel: href="ms-excel:ofe|u|file://G:/Pfad/zur/Datei.xlsx"
Dann wird der Nutzer gefragt, ob er wirklich diese Datei öffnen will, aber mit Ok landet man direkt in Excel.

Und nun kommt der Trick. Es gibt ein Protokoll, das die Explorer-Suche öffnet: href="search-ms:displayname=Protokolle&amp;crumb=&amp;crumb=location:G:\pfad\zu\den\protokollen"

Re: Ändern und Aktualisieren von Werten mittels HTML Slider

Verfasst: Mittwoch 19. Juni 2024, 09:09
von Patrick1990
@Sirius3: Ja, die Protokolle werden direkt im Browser angezeigt. Die Anhänge dazu (Fotos, Messdaten, ..., jedoch unterschiedlichste Dateiformate) werden jedoch in einem Ordner auf einem Netzwerklaufwerk hinterlegt. Die Datenbank enthält einen Verweis auf den Pfad des Ordners.

Den Trick werde ich direkt mal testen :)