Edip Ahmet
Edip Ahmet

Reputation: 525

How to use JavaScript libraries on QML

I use some javascript libraries with QML on 5.12.2. Some of them works like Proj4JS. But I get errors when using geographiclib.js library with QML. How can the JavaScript library be imported into QML?

main.qml:

import QtQuick 2.12
import QtQuick.Window 2.12
import "geographiclib.js" as MyGeo
Window {
    visible: true
    width: 640
    height: 480
    Component.onCompleted: {
        var Geodesic = MyGeo.GeographicLib.Geodesic,
            DMS = MyGeo.GeographicLib.DMS,
            geod = Geodesic.WGS84;
        var r = geod.Inverse(23, 22, 44, 29);
        console.log("distance is: ", r.s12.toFixed(3) + " m")
    }
}

Error:

qrc:/geographiclib.js:3081: ReferenceError: window is not defined
qrc:/main.qml:9: TypeError: Cannot read property 'Geodesic' of undefined

Upvotes: 4

Views: 4026

Answers (2)

talamaki
talamaki

Reputation: 5472

You are importing the javascript file correctly.

From the doc:

QML provides a JavaScript host environment tailored to writing QML applications. This environment is different from the host environment provided by a browser or a server-side JavaScript environment such as Node.js. For example, QML does not provide a window object or DOM API as commonly found in a browser environment.

Upvotes: 1

MikeM
MikeM

Reputation: 13631

The easiest way to do this, is to make GeographicLib available globally:

At the end of the geographiclib.js file, change

window.GeographicLib = geo;

to

this.GeographicLib = geo;

and then you can just use:

main.qml:

import QtQuick 2.12
import QtQuick.Window 2.12
import "geographiclib.js" as ThenItWillBeAvailableGlobally
Window {
    visible: true
    width: 640
    height: 480
    Component.onCompleted: {
        var Geodesic = GeographicLib.Geodesic,
            DMS = GeographicLib.DMS,
            geod = Geodesic.WGS84;
        var r = geod.Inverse(23, 22, 44, 29);
        console.log("distance is: ", JSON.stringify(r))
    }
}

Resulting in:

qml: distance is:  {"lat1":23,"lat2":44,"lon1":22,"lon2":29,"a12":21.754466225665134,"s12":2416081.7576307985,"azi1":13.736139413215236,"azi2":17.669059640534535}

It you don't want to change the geographiclib.js file at all, you could add a global window object using, for example:

window.js:

this.window = this;

and then use:

import QtQuick 2.12
import QtQuick.Window 2.12
import "window.js" as ThenWindowWillBeAvailableGlobally
import "geographiclib.js" as ThenGeographicLibWillBeAvailableGlobally
Window {
    visible: true
    width: 640
    height: 480
    Component.onCompleted: {
        var Geodesic = GeographicLib.Geodesic,
            DMS = GeographicLib.DMS,
            geod = Geodesic.WGS84;
        var r = geod.Inverse(23, 22, 44, 29);
        console.log("distance is: ", JSON.stringify(r))
    }
}

If you don't want to add any global variables but you are happy to edit the geographiclib.js file, then you could just move line 68 to the top of the file:

var GeographicLib = {};
/*
 * Geodesic routines from GeographicLib translated to JavaScript.  See
 * https://geographiclib.sourceforge.io/html/js/

and at the end of the file change

  } else {
    /******** otherwise just pollute our global namespace ********/
    window.GeographicLib = geo;
  }
});

to

  } else if (typeof window === 'object') {
    /******** otherwise just pollute our global namespace ********/
    window.GeographicLib = geo;
  }
});

and then your main.qml will work just fine.

Upvotes: 3

Related Questions