konvajs / konva

Konva.js is an HTML5 Canvas JavaScript framework that extends the 2d context by enabling canvas interactivity for desktop and mobile applications.
http://konvajs.org/
Other
11.72k stars 933 forks source link

Konva vs Fabric #637

Closed Nadoedalo closed 5 years ago

Nadoedalo commented 5 years ago

Hello! I'm researching a couple of canvas libraries(Paper, Fabric and Konva) and I've done a demo for each of them. Paper dropped down almost instantly - since its not a good fit for my project. Fabric done its job well and I didn't struggle, despite not-so-great documentation. I've looked at Konva because referenced design used that as well. Konva has awesome documentation - but not-so-great syntax from time to time(have you tried to implement support for base64 image?). I'm struggling to choose between Konva and Fabric and could use a little advice here. Both of them have required functions out-of-the-box and Konva seems to be more modern - but lack of popularity gives me doubts.

Have anyone used both? Why choose Konva instead of Fabric?

lavrton commented 5 years ago

Just curious what are your struggles with the Konva? What is base64 image? You can draw an image with base64 src as any other image. Also, you can convert any node into base64 url.

Nadoedalo commented 5 years ago

Current working demo, see FIXME: https://jsfiddle.net/sfkobgtu/ Expected interface: https://jsfiddle.net/91ot38ga/

How to add images from inputs directly? I mean the FileReader interface is basically the only one we have to read file inputs, right?

Fabric for example works directly with output of the FileReader.

lavrton commented 5 years ago

The first demo is totally correct. Just go with it.

Nadoedalo commented 5 years ago

Uhm... Okay it's probably hard to explain. Here is the demo that does more or less the same, but on FabricJS https://jsfiddle.net/eug6j2dp/

What I'm curious is - what is the reason behind using Konva instead of Fabric? What is the advantage? It seems like Fabric is a lot simpler because it just works out of the box and as natively expected. And it has more-or-less the same features.

lavrton commented 5 years ago

Your Fabric demo loads image too. You can use Konva.Image.fromURL as well:

Konva.Image.fromURL(imageURL, function(image){
   // image is Konva.Image instance
   layer.add(image);
   layer.draw();
 });

You can use FabricJS if you think it is better. Is it a very good library and I can recommend it even as I am the maintainer of Konva.

Hard to say what is the advantage. A long time ago I decided to use KineticJS (origin of Konva) on my projects because I liked API more compared to FabricJS. Later KineticJS was forked to Konva framework.

Nadoedalo commented 5 years ago

Sorry @lavrton for late reply - just yesterday I were going to write a report on this.

So we've stuck with the Konva - mainly because of documentation and because React community uses Konva(it were the final argument for Konva to win, btw). As the syntax and features go - I don't see a major difference between FabricJS and KonvaJS. Fabric seems a lot easier to get in - but you WILL need the documentation if you are new to Canvas and 2D graphics - just reading Konva documentation makes a lot of sense in future applications. Other up side - is that the almighty KonvaJS maintainer is actually paying attention to his issues, thank you for your time @lavrton .

As the development goes - I'm making a customization tool - something like "make your custom item with our constructor". It has different text / image change options as well as layers support - and I've just recently started to touch some of the stuff that Konva has to offer. So I've got some feedback, as well - and if you are interested I can keep updating this thread with my personal experience with your library. I can't share anything without permission - but after I roll this out I will be able to reference it.

1) I suggest having a page with crash course on Math that is going to be used like 100%. All of those vectors, point transformation, object rotation and other 2D stuff. Because usually front-enders come without proper background and have to get/refresh their middle school Math knowledge. A couple of examples and core formulas should be decent enough. I understand that this is basic Math and you can't do graphics without Math. Alongside with the math course one can reference Konva as a practical example and give a dive into how to understand what is happening when you do this or that...

2) I've just recently finished doing z-index stuff and had small wtf moment. There is a warning(big thanks for it) that z-index can't exceed the number of elements attached to the container - and that is HARD limitation - so I can't set z-index to the element BEFORE it is attached and drawn on the layer. Because of this I need to re-draw the second time just to set z-index right. It comes useful if you are trying to achieve "first in - first displayed" strategy. Since currently it is "last in - first displayed" - newly added images will get z-index higher than others

3) Scale, rotate and "center something relative to something". I had to scratch my head for a couple of days before I realized that I'm getting un-transformed data and I had to manually calculate offset, rotation and scale modifications. Maybe I'm just calling the wrong, "pure" method - but I couldn't find the "impure" ones. And there should be methods that takes care of any transformation there is.

4) Image sync. I synced two images to behave exactly the same - but they are located at different layers. I've done it so I could have low-opacity image off the painting body and clearly visible image inside of the different stage. So it would be nice to be able to create group of images that are attached to different parents and stages even. Maybe - I'm still thinking on a better way than to just listen to all actions and transfer it to synced image. Or maybe I'm just doing it wrong.

And here are the questions I'm currently working on: 1) How am I supposed to bind(listen?) what happens to image and what should happen in the UI? For example - if the image is rotated with the help of "transformer" - is there a way to know what changed? Have a callback at least? Currently my only solution is doing something like "DeepProxy" on attributes and directly attach to listen changes on "attrs" of the Image instance. 2) "Transformer" styling. It seems like I will need to write my own transformers in order to style them - for example set custom image for corners. Extending / morphing those I guess were out of the scope of the library. But they don't completely fit - and using it feels weird.

If you would like to - I can keep posting feedback in this thread. There are ways you can improve in your library to reduce learning curve difficulty - and there are stuff I can learn about KonvaJS.

lavrton commented 5 years ago

@Nadoedalo thanks a lot for good feedback. Feedback and your experience are very valuable to me.

1 It will be good if you can provide some ideas about math demos. Usually, math knowledge is required in large canvas apps. I am happy to make some math demos, but I need specific ideas about what exactly to demonstrate.

2 I did fully get your issues with zIndex. If you are making the app with React framework, you should not worry about zIndex a lot (because it is defined by render() function). If you are using Konva directly you just need to (1) add a node to the container and (2) set zIndex. That doesn't look hard to me. It will be good if you can provide more information here.

3 Just make a universal store (or state) where you save full information about your properties. Then just sync from that store.

1 For listening changes, you have transformend and dragmove events.

2 Yeah, we may need more API for Transformer styles. As workaround you can try to style it manually with direct access to anchors:

const anchors = transformer.find('_anchor');
anchors.forEach(node => {
   // do some styles
})

At the current moment Konva.Transformer is just a group with several shapes inside.