qgis / qgis-js Goto Github PK
View Code? Open in Web Editor NEWQGIS core ported to WebAssembly to run it on the web platform
Home Page: https://qgis.github.io/qgis-js
License: GNU General Public License v2.0
QGIS core ported to WebAssembly to run it on the web platform
Home Page: https://qgis.github.io/qgis-js
License: GNU General Public License v2.0
I have observed that labels get rendered in different sizes depending on the browser used (Chromium 118.0.5993.88 / Firefox 119.0b9) on my system (Ubuntu 22.04, Wayland, Scale 150%).
Also @andreasneumann reported that this test project is rendered with smaller labels than on QGIS Desktop.
Probably we have to set qtFontDpi depending on the devicePixelRatio property.
See also https://doc.qt.io/qt-6/highdpi.html
If the QGIS project uses a WMS / WMTS layer, the project loading will get stuck, with this warning being emitted all the time:
QEventLoop::WaitForMoreEvents is not supported on the main thread without asyncify
This is likely due to the fact that the WMS provider is doing a synchronous blocking GetCapabilities call in the constructor.
Many global variables are not supporte, such as:
etc.
Tested with writing out the variables with COALESCE in a label.
See also issue #26
Here's the test project: test_project.zip
Loading it will emit this error:
Uncaught (in promise) RuntimeError: index out of bounds
loadProject https://qgis-js.dev.schmuki.io/assets/wasm/qgis-js.js line 6867 > Function:8
<anonymous> https://qgis-js.dev.schmuki.io/assets/index-5d3bd54b.js:120
r https://qgis-js.dev.schmuki.io/assets/index-5d3bd54b.js:1
n https://qgis-js.dev.schmuki.io/assets/index-5d3bd54b.js:1
async* https://qgis-js.dev.schmuki.io/assets/index-5d3bd54b.js:120
[qgis-js.wasm:5700853:1](https://qgis-js.dev.schmuki.io/assets/wasm/qgis-js.wasm)
<anonymous> https://qgis-js.dev.schmuki.io/assets/index-5d3bd54b.js:120
AsyncFunctionThrow self-hosted:856
When using a QGIS project containing vector tiles layer with a couple of styling rules, it failed to load with this RuntimeError:
qgis-js.wasm:0x56fcf5 Uncaught (in promise) RuntimeError: memory access out of bounds
at QgsExpressionNodeFunction::QgsExpressionNodeFunction(int, QgsExpressionNode::NodeList*) (qgis-js.wasm:0x56fcf5)
at exp_parse(expression_parser_context*) (qgis-js.wasm:0x54bcd8)
at parseExpression(QString const&, QString&, QList<QgsExpression::ParserError>&) (qgis-js.wasm:0x54e28d)
at QgsExpression::QgsExpression(QString const&) (qgis-js.wasm:0x55145b)
at QgsProperty::loadVariant(QVariant const&) (qgis-js.wasm:0x9d9bd2)
at QgsPropertyCollection::loadVariant(QVariant const&, QMap<int, QgsPropertyDefinition> const&) (qgis-js.wasm:0x9dfd97)
at QgsAbstractPropertyCollection::readXml(QDomElement const&, QMap<int, QgsPropertyDefinition> const&) (qgis-js.wasm:0x9dce89)
at QgsSymbolLayerUtils::loadSymbolLayer(QDomElement&, QgsReadWriteContext const&) (qgis-js.wasm:0x447961)
at QgsSymbolLayerUtils::loadSymbol(QDomElement const&, QgsReadWriteContext const&) (qgis-js.wasm:0x4455a1)
at QgsSymbolLayerUtils::loadSymbols(QDomElement&, QgsReadWriteContext const&) (qgis-js.wasm:0x45d3f7)
QgsExpressionNodeFunction tries to lock a recursive mutex, maybe that's the reason (possibly related to #3 which also fails when locking mutex, but with a different error message)
When using a QGIS project that contains a cloud-optimized GeoTIFF (COG) on a remote server, it fails with a runtime error:
qgis-js.wasm:0x4792c6f Uncaught (in promise) RuntimeError: memory access out of bounds
at strlen (qgis-js.wasm:0x4792c6f)
at std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char>>::basic_string[abi:v15006]<std::nullptr_t>(char const*) (qgis-js.wasm:0x932371)
at CPLString::CPLString(char const*) (qgis-js.wasm:0x23aeac1)
at cpl::VSICurlHandle::GetFileSizeOrHeaders(bool, bool) (qgis-js.wasm:0x242d5d3)
at cpl::VSICurlHandle::GetFileSize(bool) (qgis-js.wasm:0x244222a)
at cpl::VSICurlHandle::Exists(bool) (qgis-js.wasm:0x242f73e)
at cpl::VSICurlFilesystemHandlerBase::Stat(char const*, stat*, int) (qgis-js.wasm:0x243cb26)
at VSIStatExL (qgis-js.wasm:0x23e16c8)
at GDALOpenInfo::GDALOpenInfo(char const*, int, char const* const*) (qgis-js.wasm:0x3d7e2c7)
at GDALOpenEx (qgis-js.wasm:0x3db2ab9)
We are using our custom implementation of /vsicurl
that uses emscripten's fetch API to do the requests.
It is strange that it crashes on some string construction. In the gdal sandbox this works fine (https://github.com/wonder-sk/wasm-gdal-sandbox), but the whole test case there runs in a worker thread because of the blocking networking calls.
It would be great to have either a "full-screen" mode or a more responsive map view.
On my relatively large screen I only get a small map view - see screenshot below
Alternatively (or in addition) it would be cool to have a "full-screen" button for the map.
Of course this is all "low priority" - but maybe not that hard to implement.
Rendering of vector tiles or raster tiles throws a RuntimeError "operation does not support unaligned accesses"
First there are a couple of suspicious warnings from QgsNetworkAccessManager code:
qgis-js.js:1631 qt.core.qobject.connect: QObject::connect(QgsNetworkAccessManager, Unknown): invalid nullptr parameter
qgis-js.js:1631 qt.core.qobject.connect: QObject::connect(QgsNetworkAccessManager, QgsNetworkAccessManager): invalid nullptr
qgis-js.js:1631 qt.core.qobject.connect: QObject::connect(QgsNetworkAccessManager, Unknown): invalid nullptr parameter
In case of raster tile layer: (wms provider with xyz service type)
qgis-js.worker.js:68 RuntimeError: operation does not support unaligned accesses
at QBasicMutex::lockInternal(int) (qgis-js.wasm:0x1b4a57)
at QRecursiveMutex::tryLock(int) (qgis-js.wasm:0x1b48f4)
at QgsNetworkAccessManager::setupDefaultProxyAndCache(Qt::ConnectionType) (qgis-js.wasm:0x581770)
at QgsNetworkAccessManager::instance(Qt::ConnectionType) (qgis-js.wasm:0x57f546)
at QgsTileCache::tile(QUrl const&, QImage&) (qgis-js.wasm:0x1884371)
at QgsWmsProvider::draw(QgsRectangle const&, int, int, QgsRectangle&, double&, QgsRasterBlockFeedback*) (qgis-js.wasm:0x194d54e)
at QgsWmsProvider::readBlock(int, QgsRectangle const&, int, int, void*, QgsRasterBlockFeedback*) (qgis-js.wasm:0x1953332)
at QgsRasterDataProvider::block(int, QgsRectangle const&, int, int, QgsRasterBlockFeedback*) (qgis-js.wasm:0xd2108a)
at non-virtual thunk to QgsRasterDataProvider::block(int, QgsRectangle const&, int, int, QgsRasterBlockFeedback*) (qgis-js.wasm:0xd22314)
at QgsSingleBandColorDataRenderer::block(int, QgsRectangle const&, int, int, QgsRasterBlockFeedback*) (qgis-js.wasm:0xd86462)
In case of vector tile layer:
qgis-js.worker.js:68 RuntimeError: operation does not support unaligned accesses
at QBasicMutex::lockInternal(int) (qgis-js.wasm:0x1b4a57)
at QRecursiveMutex::tryLock(int) (qgis-js.wasm:0x1b48f4)
at QgsNetworkAccessManager::setupDefaultProxyAndCache(Qt::ConnectionType) (qgis-js.wasm:0x581770)
at QgsNetworkAccessManager::instance(Qt::ConnectionType) (qgis-js.wasm:0x57f546)
at QgsTileDownloadManagerWorker::queueUpdated() (qgis-js.wasm:0xa2df28)
at QtPrivate::QSlotObject<void (QgsTileDownloadManagerWorker::*)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) (qgis-js.wasm:0xa2dbae)
at QMetaCallEvent::placeMetaCall(QObject*) (qgis-js.wasm:0xe9091)
at QObject::event(QEvent*) (qgis-js.wasm:0xebd08)
at QCoreApplicationPrivate::notify_helper(QObject*, QEvent*) (qgis-js.wasm:0xb65fe)
at QCoreApplication::notify(QObject*, QEvent*) (qgis-js.wasm:0xb66c5)
Importing import { useProjects } from "@qgis-js/utils"
only works when the internal Vite configuration is in place. Otherwise Vite will report:
Could not resolve "public/projects"
node_modules/@qgis-js/utils/dist/qgis-js-utils.js:340:8:
340 │ "public/projects"
╵ ~~~~~~~~~~~~~~~~~
You can mark the path "public/projects" as external to exclude it from the bundle, which will
remove this error. You can also add ".catch()" here to handle this failure at run-time instead of
bundle-time.
This doesn't make sense for external usage. Will have to find another solution or remove this feature from the @qgis-js/utils
package.
Reported by @amuedespacher, CC @andreasneumann
If a label or a map symbol (e.g. a point marker) ends up being near the edge of a tile, it may get cut off: it only shows in one tile, but not on the neighboring tile.
QGIS server users also have this problem, and they set non-zero tile buffer (e.g. 100 pixels) in project settings:
QGIS server code then takes care of expanding the extent to add the extra buffer, something like this:
int tileBufferPixels = QgsProject::instance()->readNumEntry( QStringLiteral( "WMSTileBuffer" ), QStringLiteral( "/" ), 0 );
double buffer = tileBufferPixels * tileExtentWidthMapUnits / tileWidthPixels;
mapSettings.setExtentBuffer( buffer );
It would be good if there could be feature info support (Identify tool) in the JS-QGIS API.
QGIS has different identify-tools modes:
For the web mapping context I think that the middle two versions (Top-Down, Stop at first; Top-down) would make most sense.
It would be great if this could support the QGIS expression engine and HTML for the display of feature info. See the "Display" section in the Layer properties:
That way we can be really flexible, with the mixture of HTML and QGIS expression support.
The current MapLayer
implementation cannot deal with hierarchical layers (e.g. layer groups).
Instead of doing our own abstraction, we should expose the QGIS internals: QgsLayerTree
, QgsLayerTreeModel
, QgsLayerTreeNode
, QgsLayerTreeGroup
, QgsLayerTreeLayer
.
Based on this API, one should be able to build a hierarchical layer tree widget.
This question came up by @andreasneumann while testing out some own projects. See the notes in the Qt6 WebAssembly reference for context.
A real cool solution would be the proposed Local Font Access API by Google. Qt did some integration, but the API is only available in Chromium based browsers and behind a flag for the time of writing. So probably not the solution for qgis-js.
What we could do is to scan the uploaded folder for any known/supported font file extensions and add those via addApplicationFontFromData to the runtime.
It would be useful to render larger tiles for high-dpi monitors.
One could have a switch depending on the screen size. E.g. when a browser window is larger than 2000 px on either width or height, then the tile size could switch from 256 px tiles to 512 px tiles.
of course, this is also low priority.
It seems like Chrome does some color management which results in slightly dumper (less vivid) colors - when compared to QGIS Desktop and Firefox wasm rendering. One can see at in the blue of the rivers or the orange tones of the polygons above the shaded relief.
This is more an observation and not so much a bug.
@boardend : how to you transfer the rendered images from QGIS wasm to OpenLayers? As a JPEG or PNG encoded file? Can we influence color management in chrome?
If a QGIS project has a layer group set to visible==false, setting the visibility of the individual layers to true in QGIS-js does not render the layers on the map.
Steps to reproduce:
Actual result:
Expected result:
The attached project uses SVG files for rendering points. The SVG files are in a subfolder and are attached as relatives paths. However, they don't render correctly, but the question mark replacement symbol is shown instead.
This is how they should render:
and this is how they render in qgis-wasm:
Is this an issue with the epxression engine or relativ paths treatment, or the wasm file system?
The JS interface should support the following functionality:
That way we can add predefined combinations of layer visibilities and/or style combinations without having the user to switch many layers one after the other.
See also QgsMapThemeCollection Class
I am working on an expressJS based web application which is primarily intended to object detection from tiff images. As of now, i am using openseadragon for loading the tiff images inside the application but it takes too much time. So i had a thought of using QGIS interface inside my application for loading the tiff images.
can anyone help with this?
Steps to reproduce:
Actual result:
Expected result:
Hints:
const loadLocalProject = async (): Promise<LocalProject> => {
try {
const entries: LocalEntries = await openLocalDirectory({
recursive: true,
mode: "read",
}) as LocalEntries;
const localProject = new LocalProject(fs, entries);
return localProject;
} catch (error) {
console.error(error);
throw error;
}
};
When setting the opacity of a map layer to some value below 1 (e.g. 0.5), the map layer is displayed in a gray-ish color.
Steps to reproduce:
Actual result:
Expected result:
Tested both with the sample project "village" and an own QGIS project.
When running a website on a different base path than root (e.g. "/qgis-demo"), loading remote projects does not work; it always expects files to be located at "/projects".
Steps to reproduce:
Actual result:
Expected result:
Steps to reproduce:
Actual result:
Expected result:
Current code: https://github.com/qgis/qgis-js/blob/main/packages/qgis-js-utils/src/fs/RemoteProject.ts
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.