I have a component that is consuming fabricjs canvas content on the event "after:render", this works well with all the functions like adding objects, moving them etc.
However when it come to free drawing, the "after:render" event only fire once the drawing is completed, ie on mouse up event. I tried to read the canvas data while the mouse is drawing but with no luck, apparently the contents is not yet rendered onto the canvas during drawing.
I understand that from this PR https://github.com/fabricjs/fabric.js/pull/2895 that the free drawing draws on this contextTop element, my question is can I read the data from it? Or is there anyway to force fabric to render free drawing contents before mouse up? I have tried renderAll() with little luck.
Thanks!
I think you can do the following:
var points = canvas.freeDrawingBrush._points;
var pathData = canvas.freeDrawingBrush.prototype.convertPointsToSVGPath.call(canvas.freeDrawingBrush, points);
This should give you the actual path data string to create a path in the system you prefer.
Related
I am working on a little tool to measure architectural drawings from PDF files. The PDF is rendered by Mozilla pdf.js on to a canvas. Once rendered, I would like to get coordinates all the paths/lines/rects on the canvas. This is to make the tool snap to the endpoints of lines when the mouse cursor is nearby. There don't seem to be an API for retrieving that. As it is not my code that actually renders onto the canvas, I dont path information beforehand.
What I have so far tried is, modify the pdf.js to emit the endpoints' x,y based on moveTo and lineTo, save them in an array. Using this array I can snap correctly in simple drawings. For complex drawings, there seems to be lot of transformations applied and this simple procedure doesnt work.
Any ideas on how to go about it?
If you take a look at what I've done so far it'll help explain what I'm after, as I'm terrible at explaining normally haha. http://logomakr.bugs3.com/
On my drawing app I've implemented the ability to add text to the canvas, however, it's not recording/saving onto the canvas like the shapes are. When I've tried looking into it, it seems like HTML Canvas text tends to place over the canvas not on it.
I even copied a simple:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.font="30px Arial";
ctx.fillText("Hello World",10,50);
to test it out, that displays on the canvas all fine and dandy but soon as you draw a shape it vanishes and even just pressing the save button the text isn't on the png?
Is there like an alternative or a way round it?
(Let me know if you need to see the code although I'm sure you's will be able to view source on website)
Thank you in advance!
For drawn shapes (rects, circles, lines) you're using the mouseup event to trigger saving the "tempCanvas" to the "realCanvas".
But for text, you're not saving the tempCanvas to the realCanvas at all. Then when you clear the tempCanvas for additional drawings, the text is blown away. Maybe you could add a [save text] button so the user can trigger saving text's tempCanvas to realCanvas.
Take a look at this example:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
// First rectangle created
ctx.fillRect(20,20,150,100);
// Second rectangle created
ctx.fillRect(20,150,150,100);
// Third rectangle created
ctx.fillRect(20,300,150,100);
I created three rectangles here. After creating third rectangle I want to rotate first rectangle. How do i get reference of first rectangle now?
A canvas is just a dumb grid of pixels. It doesn't understand what shapes have been drawn on it. Your code (or a library that your code uses) must keep track of the shapes that you've drawn.
Instead, it sounds like you want a library to create a scene graph, like EaselJS, Paper.js, or KineticJS. These libraries will maintain a data structure that tracks what shapes have been drawn on the canvas, and they will then redraw them when you want to manipulate those shapes.
You don't "get the reference" of a rectangle or something with canvas. All you have is a canvas with a context. On which you can draw. Period.
If you want to move the first rectangle, then clear it (using clearRect) and redraw the new one.
Canvas itself is just pixels. It knows how to draw rectangles, but doesn't keep them layered.
To quote Simon Sarris:
HTML5 Canvas is simply a drawing surface for a bit map. You set up a
draw (Say with a color and line thickness) , draw that thing, and then
the Canvas has no knowledge of that thing: It doesn't know where it is
or what it is, it's just pixels. If you want to draw rectangles and
have them move around or be selectable then you have to code all of
that from scratch, including the code to remember that you drew them.
The only exception is the isPointInPath method, but it has limitations.
However, there are some libraries that provide object-oriented interface for Canvas. Like Fabric.js or KineticJS. They remember what you draw as objects (rectangles, circles and so on) and can layer them one over another, move around and add mouse/touch events. Much like DOM.
Drawing functions like fillRect() does not return anything (returns void).
Meaning it simply renders the pixels, it does not create a rectangle object and return it. You'll need to store the rectangle coordinates yourself.
Question:
Is canvas more suitable than svg in the following case?
Case:
I'm drawing a chart (using d3js library) similar to this one (but with much more data):
http://mbostock.github.com/d3/talk/20111116/iris-parallel.html
It's based on an svg and it works fine for several thousands of lines (up to 5000), adding more lines (svg path) decreases the performance dramatically (scrolling in the page becomes slow)
Keep in mind: That I need to add mouse events (which is handy in svg)
Generally svg is better suited for vector images, like in your example. However canvas has a lot of benefits in modern browsers such as hardware acceleration, so for drawing the lines, as long as zooming, panning ect. isn't required performance will be using canvas.
Mouse events can be a pain using canvas, since you have to manually keep track of everything, so with 5000+ points using canvas it wont be fun. The trade off however will be once the points are drawn, assuming you only draw them once the page will behave fine regardless of the number of lines, since they are all drawn to a raster image and aren't part of the DOM.
Honestly though the best way to find it is to test what you currently have using canvas.
When performance becomes a problem, switching to canvas might be an option. In this case you can draw the canvas once. Afterwards it's pretty much treated like an image. Drawing might take some time, but afterwards it can be scaled pretty quickly. Note that it is possible to draw a rendered SVG to a canvas using the context.drawImage method (example). So you could keep your SVG generation code to create an SVG in the background, and then draw it to the canvas.
But keep in mind that it won't scale as beautiful as an SVG as soon as it is on the canvas. When the user zooms in, it will get blurry or pixely, depending on how the browser scales graphics.
Click events on canvas can be handled in two ways. Either keep an array of click targets, and add an onclick event handler to the canvas. When a click occurs, iterate the array and check which one is closest to the click coordinates.
The other option is to use hit regions. These have to be defined as polygonal paths.
+1 to everything said above. I've seen some amazing performance increases when using canvas over SVG and over compositing images using the DOM.
About manipulating the canvas image with mouse events, I imagine the best approach for an image such as you are describing is to abstract it away using a library like the following:
http://paperjs.org
http://kineticjs.com
http://www.createjs.com/#!/EaselJS
Keep your code away from the canvas itself and let a library do the thinking for you.
I have been trying to find a good resource to point me in the correct direction and I'd really like someone to help me in this regard.
I'm developing an app that uses phonegap, js and html5. One component of this app is to have an image that can be overlayed with freeform scribbles.
I'm not sure if its the canvas object I should be using and if so how do I go about implementing a drawing solution.
You create a and position it absolute over image.
can have transparent pixels (alpha=1.0) and those pixels will display the underlying image.
Then you flip pixels accordingly your scribbling to black etc. You need to listen to touch events, transform their coordinates to coordinates and then use canvas.getContext() draw operation to manipulate pixels hitting in those coordinates.
If you need further assistance please ask individual questions for each part as a complete solution would be longish source code and outside the scope of simply answering the questions.