0

Automatische Kilometerberechnung über Google

Für alle, die auf der Suche nach einer automatischen Berechnung der Kilometer sind, hier mein Lösungsansatz:

Start-Adresse (Text-Feld)
Ziel-Adresse (Text-Feld)
Google (Berechnungs-Feld)
Km (Berechnungs-Feld)

Code Google-Feld

text(http("GET", "https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + 'Start-Adresse' + "&destinations=" + 'Ziel-Adresse' + "&key=API_KEY"))

Den API-Key von Google kann man sich hier erstellen lassen und bei API_KEY einsetzen.

Code Km-Feld

let at := text(extractx(Google, "(text...)\d*.\d*"));
text(extractx(at, "\d+.\d+"))

Als Übergangslösung bis Ninox mit Arrays arbeiten kann, funktioniert es super.
Sobald man nun in das Start- und Zielfeld eine Adresse eingibt, berechnet er die Kilometer der schnellsten Route.

Man kann das ganze auch noch mit einem Button vervollständigen, der die Route in Google-Maps oder Apple-Maps öffnet.

Für Google: 

openURL("http://maps.google.com/maps?saddr=" + text('Start-Adresse') + "&daddr=" + text('Ziel-Adresse') + "&hl=de")

Für Apple-Karten:

openURL("http://maps.apple.com/maps?daddr=" + text('Straße' + " " + 'Hausnr.' + " " + PLZ + " " + Ort))

84 Antworten

null
    • Maurice
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Hallo,

    in der PDF-Ausgabe habeb ich ein Funktionsfeld mit folgendem Code

    let myGrund := 'Grund der Reise'.Grund;
    let myBeginn := Dienstreisen.'Beginn der Reise';
    let mykm := first((select Dienstreisen)['Grund der Reise'.Grund = myGrund and 'Beginn der Reise' = myBeginn].'km Fahrt');
    if mykm != null then mykm end

    Als Ausgabe erhalte ich "0 km", obwohl im Feld "km Fahrt" ein durch Google-Abfrage erhaltener Wert enthalten ist. Soll heißen: das Feld "km Fahrt" in der Tabelle "Dienstreise" ist ein Funktionsfeld, das den in diesem Thread kommunizierten Google-Abfrage-Code einschl. Key enthält. Obwohl dort z. B. 31 km ausgegeben wird, bekomme ich die 31 km nicht in die PDF-Ausgabe.

    Woran kann es liegen?

    Grüße

    Maurice

    • Leonid_Semik
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Hallo Maurice,

    wenn deine Formel mit let myBeginn... stimmt, dann ist die Tabelle Dienstreisen fest mit der Ausgabetabelle verknüpft. In diesem Fall brauchst du keine select Anweisung um Dienstreisen anzusprechen, also einfach

    —-

    Dienstreisen.'km Fahrt'

    —-

    eingeben

    Leo

    • Maurice
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Hallo Leo,

    da ist richtig. Ich habe mykm eingeführt, um die Bedingungen einzubringen. Aber das ginge ja dann auch mit einer if-Schleife. Problemweiterhin: Auch nur

    Dienstreisen.'km Fahrt'

    bringt die Ausgabe "0" (mit meinem obigen Code erhalte ich "0 km".

    Die Null ist das Problem. In der Formularansicht von Dienstreisen steht "91 km".

    Grüße

    Maurice

    • Leonid_Semik
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Dann brauche ich mehr Info. Datenmodell und Datenstruktur der Printausgabetabelle 

    • Leonid_Semik
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Versuch bitte das Berechnungsfeld mit der Formel (Dienstreisen.'km Fahrt') in der Tabelle Anträge zu erstellen und im Layout direkt ansprechen

    • Maurice
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Habe ich getan. Im (neuen) Berechnungsfeld der Tabelle Anträge wird die korrekte Kilometeranzahl angezeigt. Das Feld im PDF-Layout bringt wieder nur eine 0. Habe auch mal number(Dienstreisen.'km Fahrt') in das Berechnungsfeld gesetzt. Gleiches Ergebnis. Ist das ein Bug?

    • Leonid_Semik
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Ich glaube, dass die REST Abfrage einfach viel langsammer abläuft, als für layout-Berechnung notwendig ist. Ich würde die km Start-DG und km Ende-DG als ZahlenEinfügen und die Werte per skript fest rein schreiben (z.B. per Button). Dann sollte es klappen.

    Leo

    • Ninox Premiumpartner
    • Bastian_Vorholt
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Versuch mal das Feld in ein Textfeld oder Zahlenfeld zu schreiben. Am besten ein Button mit dem ganzen code von oben und dann nur bei der stelle round(number(km.value) / 1000, 0) machst du Textfeld := round(number(km.value) / 1000, 0)

    • Maurice
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Hallo Leo und Bastian,

    echt klasse, dass ihr mir helft. Das Forum hier ist spitze.

    Leos Vorschlag verstehe ich nicht ganz. Wo soll ich die km Angaben von Start-DG und Ende-DG als Zahlen einfügen? Und wo die Werte per Script reinschreiben?

    Das Merkwürdige ist ja, dass im Feld "km-Fahrt" mit den Ergebnissen aus Start-DG und Ende-DG richtig gerechnet wird.

    Bastain, deinen Vorschlag habe umgesetzt: einen Button mit dem Google-Code und am Ende Ergebnis := round ...; Ergebnis ist ein Textfeld, das ich neu angelegt habe. Das Feld bleibt leer, ebenso, wenn ich das Feld als Zahlfeld anlege.

    Grüße

    Maurice

    • Ninox Premiumpartner
    • Bastian_Vorholt
    • vor 5 Jahren
    • Gemeldet - anzeigen

    In dem Response gibt er ja auch km mit aus und ninox erkennt dies dann als text. Text kannst du aber nicht in ein Zahlenfeld wandeln darum musst du die km mit replace(text(km), "km", null) wegbekommen. Leider ist es damit noch nicht getan, du musst aus dem komma ein punkt machen also wenn bei dir 5,5 km entfernung kommen musst dieses komma wegbekommen und erst dann kann der wert als number gewandelt werden und auch erst dann in ein Zahlenfeld geschrieben werden. Vielleicht hat leo da eine einfache Lösung.

    • Maurice
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Aber warum addiert Ninox die beiden Response-Felder Start-DG und Ende-DG im Feld "km-Fahrt" korrekt? Wenn das nur als Text aufgefasst würde, ginge das doch nicht, oder? Aber dachte, wenn schon richtig addiert, sollte Ninox das auch leicht weiterverweten können (im PDF).

    • Maurice
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Noch eine Merkwürdigkeit: füge ich in mein PDF-Layout eine Tabelle ein, so wird die Spalte 'km Fahrt' korrekt ausgegeben.

    So werde ich das vielleicht lösen als workaround. Ich brauche aber nur einen Datensatz - mal schauen.

    • Leonid_Semik
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Hallo zusammen,

    nach den ganzen Diskussionen hier und auch auf Telegramm habe ich mir den Code nochmals angeschaut. Es werden immernoch die Texte vor Responce analysier obwohl Ninox schon lange in der Lage ist Json zu lesen. In der Cloud funktioniert die Google-Abfrage auch. man muss nur do as Server verwenden. Also Angenommen es gibt zwei Textfelder:

    'Start-Adresse'

    'Ziel-Adresse'

    Dann noch das Feld Zeitdauer (von Typ Zeitdauer)

    und ein Zahlenfeld Entfernung. 

    Dann wäre die Formel für einen Button:

    ---

     

    let gcode := do as server
    http("GET", "https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + 'Start-Adresse' + "&destinations=" + 'Ziel-Adresse' + "&key=*********************")
    end;
    Zeitdauer := number(last(first(gcode.result.rows).elements).duration.value) * 1000;
    Entfernung := number(first(first(gcode.result.rows).elements).distance.value) / 1000

    ---

    man sollte selbstverständlich den eigenen Key einsetzen. Ich habe hier auf Prüfungen, ob die Adressfelder nicht leer sind, verzichtet. Es geht mir erstmal um json-Auswertung.

    Die Zeitdauer kommt hier in Millisekunden und die Entfernung in km.

     

    Leo

    • Maurice
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Hallo Leo,

    vielen Dank. Das Feld Entfernung lässt sich im PDF-Formular ansprechen.

    Jetzt  habe ich noch ein Problem: der von dir gepostete Code funktioniert bei einem Button. In einem Berechnungsfeld erscheint die Meldung, dass diese Funktion keine Datenveränderungenn vornehmen kann. Über response ging das.

    Ich hätte (natürlich) gerne in meiner Tabelle, dass ich etwas in das Start und/oder Ziel Feld tippe und sofort die Abfrage erfolgt, ohne auf einen Button klicken zu müssen. Dazu muss ich den Button triggern über die Änderung der Felder Start bzw. Ziel (die bei mir selbst ein Funktionsfeld sind, da sie aus mehreren Feldinhalten zusammen gesetzt werden, aber das Triggern erfolgt dann über die ursprünglichen Felder).

    Ich finde den Namen der Befehlsschlatfläche (Button) aber nicht in der Übersicht der Feldnamen, so dass ich irgendwie als Trigger-Funktion "Button = true" eingeben könnte. Wie trigger ich den Button bei einer Änderung?

    Grüße

    Maurice

    • Leonid_Semik
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Hallo Maurice,

    Die Formel für ein Berechnngsfeld soll anders aussehen. Für Zeitdauer:

    ---

    let gcode := do as server
    http("GET", "https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + 'Start-Adresse' + "&destinations=" + 'Ziel-Adresse' + "&key=*********************")
    end;
    number(last(first(gcode.result.rows).elements).duration.value) * 1000

    ---

    Für Entfernung:

    ---

    let gcode := do as server
    http("GET", "https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + 'Start-Adresse' + "&destinations=" + 'Ziel-Adresse' + "&key=*********************")
    end;
    number(first(first(gcode.result.rows).elements).distance.value) / 1000

    ---

     

    Ich bin kein Freund von Berechnungsfelder mit REST-Abfragen. Stell dir for, du hast 1000 Datensätze und in einer Tabellenansicht die Spalten Entfernung und Zeitdauer. Auch wenn die Abfrage nur 1 Sekunde dauern würde, braucht Ninox zum Aufbauen der Tabellenansicht 1000 *1*2:=2000s=33 min. Viel besser wäre es, wenn die Felder eben als Zahl bzw. Zeitinterval angelegt sind und bei beiden Textfelder Start- und Ziel-Adresse einen Trigger nach Änderung angelegt ist:

    ---

    if 'Start-Adresse' and 'Ziel-Adresse' then

    let gcode := do as server
    http("GET", "https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + 'Start-Adresse' + "&destinations=" + 'Ziel-Adresse' + "&key=*********************")
    end;
    Zeitdauer := number(last(first(gcode.result.rows).elements).duration.value) * 1000;
    Entfernung := number(first(first(gcode.result.rows).elements).distance.value) / 1000

    end

    ---

    so prüft Ninox bei Änderung eines Adressfeldes ob beide Adressfelder gefüllt sind und falls JA fragt bei Google die Entfernung und die Zeit an. 

     

    Leo

    • Maurice
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Hallo Leo,

    deine Überlegungen zur Zurückhaltung bei der Google-Abfrage überzeugen, aber das klappt nicht bei mir.

    Bei mir werden die Start-Adresse und Ziel-Adresse, aus dem für Google Start und Ziel gelesen werden, wie folgt generiert:

    let myStart := Start;
    let Maurice := first(select 'Persönliche Daten' where Vorname = "Maurice");
    switch myStart do
    case 1:
    Maurice.'Straße' + ", " + Maurice.PLZ + " " + Maurice.Wohnort
    case 2:
    Maurice.'Straße Stammdienststelle' + ", " + Maurice.'PLZ Stammdienststelle' + " " + Maurice.'Ort Stammdienststelle'
    default:
    'Schlagwörter, Startadresse' + " " + 'PLZ, Start' + " " + 'Ort, Start'
    end

    sprich: ich habe ein Mehrfachauswahlfeld 'Start' mit 3 Optionen. Bei den ersten beiden Optionen wird das Feld 'Start-Adresse'  automatisch vorbelegt mit meiner Daten aus einer anderen Tabelle, bei der dritten Option (default) erscheinen drei Eingabefelder, die dann übernommen werden.

    Ein Funktionsfeld hat ja keine Option "Nach Änderung Skript ausführen", weshalb ich deinen Code in das Mehrfachauswahlfeld platziert habe. Wenn ich dort aber meine Auswahl ändere von z. B. case1 auf case2 ändert sich bei Zeitdauer und Entfernung nichts. Über einen Button, der den gleichen Code enthält, ändern sich die Einträge bei Zeitdauer und Entfernung.

    Grüße

    Maurice

    • Maurice
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Das Fatale ist: nur über ein Zahlfeld 'Entfernung' bzw. Zeitdauerfeld kann ich die Daten in das PDF-Layout übernehmen. Steht die Entfernung in einem Berechnungsfeld mit Google-API - das war ja mein Ausgangsproblem -, dann steht im PDF-Feld nur ein 0 km, obwohl in der Tabelle eine km-Berechnung ausgegeben wird.

    • Maurice
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Hallo,

    hier bin ich zwar fündig geworden, aber nicht weiter gekommen:

    https://ninoxdb.de/en/forum/technical-help-5ab8fe445fe2b42b7dd39ee7/call-a-button-from-a-trigger-5b8b1c5c510f420693fb13c1

    Dort lese ich, dass im Trigger-Feld keine Feldinhalte geändert werden können. Den dort vorgeschlagenen Workaround konnte ich nicht umsetzen (vielleicht, weil ich ihn nicht verstanden habe).

    Ich habe den Google-Code einschl. die Anweisung für die Felder Zeitdauer und Entfernung in eine Funktion ins TRigger-feld der Tabelle gepackt. Ein Ja/Nein Feld wird über meine Auswahlfelder für die Startadresse gesteuert. Leider kein Erfolg.

    Hat noch jemand eine Idee?

    Grüße

    Maurice

    • Maurice
    • vor 5 Jahren
    • Gemeldet - anzeigen

    Hallo, kennt jemand den Grund, warum:

    let gcode := do as server
    http("GET", "https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + 'Start-Adresse' + "&destinations=" + 'Dienstgeschäft-Adresse' + "&mode=bicycling" + "departureTime:" + 'Beginn der Reise' + "&key=*************************")
    end;

    'Dauer Hinfahrt' := number(last(first(gcode.result.rows).elements).duration.value) * 1000;

    mir als Reisezeit  (Dauer Hinfahrt) immer die Zeit mit dem Auto ausgibt. Egal, was ich bei mode einstelle, es erscheint die Autoreisezeit.

    Hat jemand einen Tipp?

    Grüße

    Maurice

    • domkai
    • vor 3 Jahren
    • Gemeldet - anzeigen

    Hallo

    seit ein paar Wochen funktioniert mein alter Code zum Berechnen der Entfernung nicht mehr. Ich habe nun diese hier probiert, gehen auch nicht. Alles angepasst, keine Chance. Gibts da irgendeine umstellung seitens ninox oder google die hier nicht berücksichtig wurde? Danke für eure Unterstützung.

    VG Dominik 

    • Dirk_Patzer
    • vor 3 Jahren
    • Gemeldet - anzeigen

    Stimmt, bei mir auch. Keine Zeit, keine Entfernung, nur leere Felder. 

    • Leonid_Semik
    • vor 3 Jahren
    • Gemeldet - anzeigen

    Diese Formel funktioniert bei mir:

    ---

    let gURL := url("https://maps.googleapis.com/maps/api/distancematrix/json", {
    origins: Startadresse,
    destinations: Zieladresse,
    mode: "car",
    key: "XXXXXXXXXXXXXXXXXXXXXXXXXXX"
    });
    let gcode := do as server
    http("GET", gURL)
    end;
    Zeitdauer := number(last(first(gcode.result.rows).elements).duration.value) * 1000;
    Entfernung := number(first(first(gcode.result.rows).elements).distance.value) / 1000

    ---

    Leo

    • Jens_Peters
    • vor 3 Jahren
    • Gemeldet - anzeigen

    Hallo.

    Ich hatte diesen Fehler schon am 18.01.21 dem Ninox-Support gemeldet. Auch folgte mit Sam ein sehr intensiver Austausch zu dieser Problematik.

    Weder die "do as Server", noch die "normale" Version funktionierte in der Mac-App / Web-Version und in der iPad-App. In der iPhone-App funktionierte die Google-Distanzabfrage bis zur Version 2.7.3. Ab der iPhone-Version 2.8.0 funktioniert es auch in der iPhone-App nicht mehr.

    Ich habe auf dem iPad noch die 2.7.3 iPhone-App installiert, da funktioniert es auch heute noch.

    Ninox weiß vom Fehler, ignoriert es aber hartnäckig.

    • Leonid_Semik
    • vor 3 Jahren
    • Gemeldet - anzeigen

    Hallo Jens, 

    die Formel, die ich gepostet habe funktioniert sowohl als Button als auch als Trigger bei Änderung in Web (Windows, Chrome),  in der Mac App (letzte Version), Mac Web Safari, iPhone App letzte Version. Ich habe leider kein iPad, daher keine Aussage diesbezüglich.

    Leo

    • Jens_Peters_icloud
    • vor 3 Jahren
    • Gemeldet - anzeigen

    Hallo Leo.

    Danke für die schnelle Hilfe. 

    Die Distanzabfrage verhält sich eigenartig. 

    Der Code mit "do as Server" funktionierte in der Vergangenheit in der Mac-App und iPhone-App über iCloud. Ab einem Update Anfang des Jahres ging nur noch die iphone APP.

    Dann hatte ich nach Rücksprache mit Sam den Code ohne "do as Server" geschrieben. Mac-App = 0 / iPhone App 2.7.3 = OK

     

    Aktueller Stand:

    Mac Safari Web Ninox Cloud: Meine beiden Codes (die bisher immer funktionierten) = 0  / Dein Code = OK

    Mac App Ninox-Cloud : Meine beiden Codes (die bisher immer funktionierten) = 0 / Dein Code = OK

    Mac App iCloud: Meine beiden Codes (die bisher immer funktionierten) = 0 / Dein Code = 0

     

    iPhone APP 2.8.1 Ninox-Cloud: Meine beiden Codes (die bisher immer funktionierten) = 0 / Dein Code = OK

    iPhone APP 2.8.1 iCloud: Meine beiden Codes (die bisher immer funktionierten) = 0 / Dein Code = 0

     

    iPhone APP 2.7.3 Ninox Cloud: mit "do as Server" = 0 / ohne "do as Server" = OK / Dein Code = OK

    iPhone APP 2.7.3 iCloud: Meine beiden Codes (die bisher immer funktionierten) = OK / Dein Code = OK

     

    Fazit:

    Dein Code funktioniert mit der iCloud-Version mit den neuesten Updates Mac & iPhone auch nicht, aber über die Ninox-Cloud.

    Alle drei Codes funktionieren mit der iCloud-Version auf dem iPhone mit der App 2.7.3

     

    Hier die Codes, die früher funktionierten.

    Mit do as server

    "
    //--- Google Maps km ohne und mit Autobahn abrufen und die optimalste Strecke (Entfernung mA) an 'einfache Strecke' übergeben.

    ";
    let API_Key := "'API-Key'";
    "

    //--- Abruf Autobahn vermeiden und Übergabe Daten";
    let gcode := do as server
    http("GET", "https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + Startadresse + "&destinations=" + Zieladresse + "&avoid=highways" + "&key=" + 'API-Key')
    end;
    'Zeit oA 1' := number(last(first(gcode.result.rows).elements).duration.value) * 1000;
    'Km oA 1' := number(first(first(gcode.result.rows).elements).distance.value) / 1000;
    "

    //--- Abruf optimale Strecke lt. Google - Autobahn erlaubt und Übergabe Daten";
    let gcode2 := do as server
    http("GET", "https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + Startadresse + "&destinations=" + Zieladresse + "&key=" + 'API-Key')
    end;
    'Zeit mA 1' := number(last(first(gcode2.result.rows).elements).duration.value) * 1000;
    'Km mA 1' := number(first(first(gcode2.result.rows).elements).distance.value) / 1000;
    "
    //--- Ergebinsfeld zur Kontrolle, ob Daten abgerufen";
    'Ergebnis Abfrage mit Server' := text(gcode2.result)

     

    ohne do as server

    "
    //--- Google Maps km ohne und mit Autobahn abrufen und die optimalste Strecke (Entfernung mA) an 'einfache Strecke' übergeben.

    ";
    let API_Key := 'API-Key';
    "

    //--- Abruf optimale Strecke lt. Google - Autobahn erlaubt und Übergabe Daten";
    let gcode_mA := text(http("GET", "https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + Startadresse + "&destinations=" + Zieladresse + "&key=" + API_Key));
    'Zeit mA 2' := number(extractx(extractx(gcode_mA, "Minuten...value..\d+"), "\d+")) * 1000;
    'Km mA 2' := number(extractx(extractx(gcode_mA, "\d+.\d+ km"), "\d+."));
    "

    //--- Abruf Autobahn vermeiden und Übergabe Daten";
    let gcode_oA := text(http("GET", "https://maps.googleapis.com/maps/api/distancematrix/json?origins=" + Startadresse + "&destinations=" + Zieladresse + "&avoid=highways" + "&key=" + API_Key));
    'Zeit oA 2' := number(extractx(extractx(gcode_oA, "Minuten...value..\d+"), "\d+")) * 1000;
    'km oA 2' := number(extractx(extractx(gcode_oA, "\d+.\d+ km"), "\d+."));
    "

    //--- Ergebinsfeld zur Kontrolle, ob Daten abgerufen
    ";
    'Ergebnis Abfrage ohne Server' := gcode_mA