Open mrjoshuak opened 9 years ago
:+1: it would be great to have this library working in QML
I am happy to look into this, but never worked with QML. So where do I start? How are libraries loaded in QML?
You can find more information here at the Qt project.
In the QML getting started doc listed above there is a section that specifically discusses the javascript environment and how it differers from others such as in browser or Node.js. Here are the most relevant links from that section.
One can specify that a javascript file is a library that is imported and shared amongst multiple QML components by setting .pragma library
at the beginning of the javascript file, but I doubt that is critical in this case. The main points are that Node.js require
is not available, and there is no DOM.
There is a Canvas type in QML, and one can get the context to start drawing in it easily. Here's a simple example, but if it's helpful I could assemble a simple project that opens a QML window containing a Canvas object and javascript import. Just let me know, and I'll set it up.
MyCanvas.qml
:
import QtQuick 2.4
import "paper.js" as Paper
Canvas { id: myCanvas
property var paperEngine: null
onPaint: if(!!paperEngine) paperEngine.QMLonPaint();
Component.onCompleted: paperEngine = Paper.createQMLengine({canvas:myCanvas})
}
paper.js
:
PaperQMLengine = (function() {
function PaperQMLengine(params) {
this.ctx = params.context
this.x = params.x
this.y = params.x
this.width = params.width
this.height = params.height
}
// canvas paint code:
PaperQMLengine.prototype.QMLonPaint = function() {
this.ctx.save();
this.ctx.clearRect(this.x,this.y,this.width, this.height);
// draw stuff
this.ctx.restore();
}
});
createQMLengine = function(params) {
return new PaperQMLengine({
context: params.canvas.getContext('2d'),
x: params.canvas.x,
y: params.canvas.y,
width: params.canvas.width,
height: params.canvas.height
});
};
I typically use coffeescript so this javascript is a paraphrasing of some of the javascript produced in my code, but you get the idea. One must get the context via canvas.getContext('2d')
, and one must provide a 'paint' function that draws everything when called. As long as there are no expectations of a DOM, and resources are included via .import "foo.js" as Foo
or Qt.include("bar.js")
(for inline include without namespacing) as apposed to require
(et al), then you should be able to do just about anything you'd normally do in a canvas element.
Are there any updates on this?
No updates, but we're happy to accept a PR. None of us uses QML, so it's very low priority at our end.
@JoshuaKolden could something like this project ease the progress: https://github.com/quickly/quickly ? (the QMLify tool from the project is used in various other projects that attempt to easen up the porting of other Node / Browser libs to QML)
Having a super strong QML canvas library like this would indeed be a very nice addition to QML (especially for drawing on screen beyond the primitive (Rectangle, Image) types in QML).
ok... its been 3 years since this idea popped up... has this been developed yet?
If there was work on such a feature, it would be visible here. This comment still applies though: https://github.com/paperjs/paper.js/issues/710#issuecomment-189021783
No updates, but we're happy to accept a PR. None of us uses QML, so it's very low priority at our end.
I'm happy to assist anybody who's willing to implement this. It doesn't sound all that complicated, but we'd have to also test it and make sure it actually works and keeps working with future changes, as otherwise we wouldn't want to include it in the library. And I don't have the time and resources to do so.
I've managed to get paper.js working in qml: (https://github.com/dinusv/paperqml).
I've added a sample showing the use of mouse interactions and animations via qml items.
I used the distributed paper-full.js
file, since qml does not support requiring all project files
separately
Since paper-jsdom
uses specific node modules that are not available in Qt, I had to rewrite a minimal DOM API. (see paperqml/js/paper-dom.js
)
onPaint
handler:Canvas{
onPaint: {
var ctx = getContext("2d");
// use ctx ...
}
}
This disables creation and working with multiple Canvases at the same time, as the
application needs to wait for each Canvas to trigger the onPaint
handler.
I noticed Paper.js uses this functionality in CanvasProvider
, where it creates and reuses canvases for
a number of reasons, including opacity and blending of items. Due to the qml Canvas restrictions,
I'm forcing CanvasProvider
to work with a single canvas, so features
like opacity and blend modes will not work.
Due to the limited DOM, support for importing and exporting svg files is not yet available.
Item Opacity and blend modes do not work due to limitations on qml Canvas.
The qml implementation runs slightly slower than as it would in a browser, partly cause of qml's Canvas implementation, and partly cause of Qml's javascript engine.
No updates, but we're happy to accept a PR. None of us uses QML, so it's very low priority at our end.
Qml uses a different build system (qmake
, c++
and qml
), so my take
would be to keep these 2 projects separate, and simply keep them in sync (have paper.js as a dependency of paperqml).
I'm open to suggestions though.
I'm happy to assist anybody who's willing to implement this. It doesn't sound all that complicated, but we'd have to also test it and make sure it actually works and keeps working with future changes, as otherwise we wouldn't want to include it in the library. And I don't have the time and resources to do so.
To make sure paperqml will keep working with future versions from paper.js, would it make sense to keep a consistent documentation (together with tests?) to the parts of the DOM API that are used by paper.js? To be more precise, the file I've added in paperqml/js/paper-dom.js
provides the minimal DOM API that's needed to run paper.js, would it make sense to have this file tested against with each new version from paper.js?
Monumental work @dinusv ! Wow 👀
Man I would love it if this worked in a QML canvas, and other than DOM dependency it should. I tried using the Node.js version and faking the 'requires' function out with my own classes, but I just can't easily unravel all the mixin logic implemented via Base inject.
If DOM dependency was more modular, or this was written in coffeescript I might be more able to pull this off myself, but as it is I must ask for help. Any suggestions other than just a "please support QML" feature request that might get me headed in the right direction?
Thanks, and great work.