paperjs / paper.js

The Swiss Army Knife of Vector Graphics Scripting – Scriptographer ported to JavaScript and the browser, using HTML5 Canvas. Created by @lehni & @puckey
http://paperjs.org
Other
14.5k stars 1.23k forks source link

QML Support #710

Open mrjoshuak opened 9 years ago

mrjoshuak commented 9 years ago

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.

ste93cry commented 9 years ago

:+1: it would be great to have this library working in QML

lehni commented 9 years ago

I am happy to look into this, but never worked with QML. So where do I start? How are libraries loaded in QML?

mrjoshuak commented 9 years ago

You can find more information here at the Qt project.

JavaScript Environment for QML Applications

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.

Example

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.

robhemsley commented 8 years ago

Are there any updates on this?

lehni commented 8 years ago

No updates, but we're happy to accept a PR. None of us uses QML, so it's very low priority at our end.

larpon commented 8 years ago

@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).

rubbieKelvin commented 5 years ago

ok... its been 3 years since this idea popped up... has this been developed yet?

lehni commented 5 years ago

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.

dinusv commented 3 years ago

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.

Some notes:

  1. I used the distributed paper-full.js file, since qml does not support requiring all project files separately

  2. 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)

  1. The qml Canvas is more restrictive than the html one. It allows access to its context only during the 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.

Limitations:

  1. Due to the limited DOM, support for importing and exporting svg files is not yet available.

  2. Item Opacity and blend modes do not work due to limitations on qml Canvas.

  3. 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.

PullRequest:

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?

larpon commented 3 years ago

Monumental work @dinusv ! Wow 👀