Why there is no method draw() in KineticJS documentation? - javascript

I've spent hours googling about Kinetic.Layer.draw() method. All that I've found is use-cases - no documentation about how, when and why to use it. Maybe it's deprecated already?
These are primary links which I use while learning and playing with this wonderful framework:
http://kineticjs.com/docs/index.html
http://www.html5canvastutorials.com/kineticjs/html5-canvas-events-tutorials-introduction-with-kineticjs/
It will be really helpful if somebody explains to me such misunderstanding.

Actually draw() and drawHit() are in the docs, but they are poorly documented:
http://kineticjs.com/docs/Kinetic.Stage.html#draw
draw()
draw layer scene graphs
http://kineticjs.com/docs/Kinetic.Stage.html#drawHit
drawHit()
draw layer hit graphs
Surprisingly I was unable to find the 3rd and last draw method: drawScene() in the Kinetic Docs. Also to my surprise, these 3 functions were not found to be extended from the parent class of Kinetic.Stage: Kinetic.Container
Anyways, I think this SO question explains the differences of the methods perfectly: What is the difference between KineticJS draw methods?
And definitely, there's no avoiding using these functions, you'll need to use one of them eventually unless your canvas/stage is static during your entire application. (*There may be an exception, see below)
To answer your questions:
How:
Call .draw() on any Kinetic.Container which includes: stage layer and group, or any Kinetic.Node which includes all the Kinetic.Shape
Examples:
stage.draw(); //Updates the scene renderer and hit graph for the stage
layer.drawHit(); //Updates the hit graph for layer
rect.drawScene(); //Updates the scene renderer for this Kinetic.Rect
Why:
I would think it's a performance thing to not have everything redraw on the Kinetic.Stage every single time there is a change. The use of the draw methods this way we can control programatically when we want the stage to be updated and rendered. As you might imagine, it is quite expensive to have to draw the stage all the time if we have say 10000 nodes in the scene.
When:
drawScene()
Anytime you need to update either the scene renderer (for example using .setFill() to change the fill of a shape)
drawHit()
To update the hit graph if you're binding events to your shapes so that the hit area for any events will be updated to the node changes.
draw()
Whenever you need to do both of the above.
Finally, perhaps an example/lab will be the most beneficial learning tool here, so I've prepared a JSFIDDLE for you to test out the differences. Follow the instructions and read my comments inside to get a better understanding of what's going on.
*NOTE: I mentioned above there was an exception to having to use the draw methods. That is because whenever you add a layer to the stage, everything in the layer is automatically drawn. There is small example of this described at the bottom of the fiddle.

The draw() method is basically used for drawing all the (visible) elements associated with the container you call the method on.
It is therefore not just limited to Kinetic.Layer but can also be used on Kinetic.Group, Kinetic.Container and so on...
When & Why to use:
Whenever you make any change to the canvas, you call the appropriate container's Draw() method. KineticJS does not refresh the canvas unless you explicitly say it using Draw(). In general, try to call the smallest container affected by your changes to make use of the efficient caching and redrawing only a part of canvas that was affected.
Take for instance:
You have 2 layers in your application. Layer1 is used for a static background and some other static items that need not be redrawn everytime.
And Layer2 contains your moving elements, or active objects. Then you can simply make a call to Layer2.draw()
To add the complexity, you have a group of objects, lets say all menu items. When a user presses any menu btn, its better to call menuGroup.draw() rather than the draw function of the its parent layer.

Related

Change layer z-index in leaflet

I'm using leaflet to trace underground pipes which I create using the polyline methods.
Since the pipes/lines can sometimes overlap I need to be able to highlight the selected line which requires switching the z-index of the line.
Now it seems that leaflet does offer a setZIndex method, but it's not available for individual layers - so I can change it over an entire featureGroup, but that is less helfpul - and making every line into its own separate featureGroup feels like an overkill.
Any suggestions?
You could create another layer with a superior z-index that would be empty at start. When the mouse is going over a feature, copy the feature into that layer. When the mouse is going out, just remove it from the layer.
It might be a little bit cpu demanding, so I suggest you to debounce the mouseover function in order to make the mouse to wait 1-2 seconds over a feature before copying it into the top layer.
As IvanSanchez noted in a comment, the correct answer seems to be a method called bringToFront.

How to animate using requestAnimationFrame?

I am trying to use requestAnimationFrame to animate my canvas when I click on + and - buttons to zoom in and zoom out like the Google Maps does (When you click on the + button to zoom in, you see a slight transition or a delay). Unlike the traditional canvas implementations, I have a pretty complicated structure in the application.
When the button is clicked, zoomin() function inside a service is called where the values are calculated and then the resultant value is emitted which is captured by a different component A which in turn calls a different class method redraw() which redraws the canvas.
In every example I saw, the images are being animated by manipulating the pixel values with time and the draw() method is available right there. But could anyone tell me where I should handle this and is there any alternative? And also how could I animate like the google maps does in JavaScript?
Could anyone guide me?
Thank you.
The demos that you have seen are right. requestAnimationFrame is a means and not an end. You use it to make your application more smooth and performant by limiting how often a method can be called, not just for the sake of using it to draw because that will not help.
If you want to use requestAnimationFrame for throttling (ie doing a redraw update every 1/60 of a second instead of whenever zoomin is called), you will have to update your logic and indeed store and update the zoom values in the background in a data service somewhere. The requestAnimationFrame loop should indeed have access to and call redraw so it is called every 1/60 of a second instead of whenever something updates. Redraw should have access to all data needed to draw the map (like the current zoom level).
The only alternative is NOT using requestAnimationFrame and doing the debouncing yourself when receiving mousewheel events to prevent to much draws. It sounds like your application could benefit from a more simple structure that would allow the use of requestAnimationFrame.
For the animation part, I would ask a separate question as that is a whole other topic.

Kineticjs class hierarchy clarification

After reviewing the Kineticjs docs I have come up with the following
Kinetic.Node - Nodes are entities that can be transformed, layered, and have bound events.
Kinetic.Shape (Node) - Shapes are primitive objects such as rectangles, circles, text, lines, etc.
Kinetic.Container (Node) - Containers are used to contain nodes or other containers
Kinetic.Stage (Container(Node)) - A stage is used to contain multiple layers add(Layer)
Kinetic.Layer (Container(Node)) - Layers are tied to their own canvas element and are used to contain groups or shapes add(Node)
Kinetic.Group (Container(Node)) - Groups are used to contain shapes or other groups. add(Node)
Kinetic.BaseLayer (Container(Node)) - ???
Kinetic.FastLayer (Container(Node)) - is used for layers that don't need user interaction (update thanks markE)
Kinetic.Collection (Array) - This class is used in conjunction with Kinetic.Container#get
What are BaseLayer and 'FastLayer' used for exactly? In the documentation FastLayer has the exact same description as Layer and BaseLayer just says that it is a constructor.
in one of the commit comments it is inferred that FastLayer does not have to remove a hit canvas ... I am guessing this is because it does not have one thus making it faster?
Some clarification on what these two classes do, and how to effectively use them would be appreciated.
EDIT: Updated Question to reflect markE's input, anyone have insight on BaseLayer?
Note: as of this post the fast layer was introduced only several days ago. But as I understand...
The new fast layer is the old layer but with eventing turned off.
The KineticJS docs say:
If you don't need node nesting, mouse and touch interactions, or event
pub/sub, you should use FastLayer instead of Layer to create your
layers. It renders about 2x faster than normal layers.
The fast layer is used for layers that don't need user interaction:
a static background layer with no user interaction required.
a static layer that is manipulated and drawn entirely thru JS code with no user interaction required.
Drawing fast layers is faster because there is no overhead related to eventing.
Normal layers also have a supporting offscreen canvas which supports hit-testing and dragging.
I suspect the fast layer does not have this overhead either since hit-testing and dragging is related to eventing.
Having said this...I need to investigate this new tool more myself. ;-)

Storing shapes in JavaScript array to redraw after some operation

I am developing an editor in html5. I have buttons for creating shapes when clicked, including triangle, rectangle, hexa, penta, heptagons, lines, and so on. Now I also want to perform operations on these shapes such as rotate, flip, undo, redo, ...etc. I want to save these drawn objects in a JavaScript array or something so I can create them after performing operations on the canvas, since individual shapes cannot be rotated or flipped in canvas, we have to redraw it. How can I achieve this? Thanks in advance.
I have a project where if you click on an image of a rectangle you can then draw a rectangle, click on an ellipse then you can draw an ellipse. My shapes are stored as objects which are then drawn using Canvas and can be flipped, rotated etc I have not implemented undo redo.
My project is at http://canvimation.github.com/
The source code for my project is at https://github.com/canvimation/canvimation.github.com
The master branch is the current working code. You are welcome to use any of the code or fork the project.
as you said, you have to clear your context and redraw your shapes any time you change them.
It's not mandatory to clear and redraw all the context, you can just redraw the region in which a shape is modified.
So you have to think your shapes as objects (in a OOP way) with their own properties and render method.
What I'd do is to create another class to apply transformations to a shape (a flip is just a -1 scale).
If you go this way, it could become a huge work (the more features you add, the more complexe your code becomes and the first design of your application may be re-think during the work).
What I can suggest to you is to use a framework that already does the job.
For example, cgSceneGraph is designed to let developers add their own rendering method and provides a lot of methods to manipulate them. I'm the designer of the framework, feel free to ask more on about how to apply transformations or create your own nodes (tutorials and examples are already on the website, but I'll please to help you).

OpenLayers features redraw only after mouse moveend

In this case I use Map control from OpenLayers 2.10. On map I have base layer
which is OpenLayers.Layer.OSM and OpenLayers.Layer.Vector with custom features. Now when I move map using mouse the features that weren't previously visible won't redraw until release of mouse button. I have noticed the same issue in all OpenLayers examples. Can anyone provide some kind of work around to change this behaviour? What I want to achieve is to draw features immediately after feature becomes visible or always draw all features (I work with small number of features so performance of map control isn't critical).
My current idea is to handle some specific events on map (like mouse move with click) and force features redraw.
Update
The SVG2 renderer was introduced in v2.11, and then immediately deprecated in v2.12 for reliability reasons (See this pull request). For OL >= 2.12, set the layer's ratio property to have it render all features within a wider area as a ratio of the screen size. The trade-off is performance, and if your user "throws" their map in some direction, they will fly past the features, but at that point they probably expect to have some rendering delays.
new OpenLayers.Layer.Vector("My Layer", {
ratio: 2
});
Original Answer
From http://lists.osgeo.org/pipermail/openlayers-dev/2011-March/007345.html :
the new OpenLayers.Renderer.SVG2 renderer does what you are requesting. It is available on trunk (and will be in 2.11). To use it, configure the renderers array for your OpenLayers.Layer.Vector like this:
new OpenLayers.Layer.Vector("My Layer", {
renderers: ["SVG2", "VML", "Canvas"]
});
Or set it on the prototype:
OpenLayers.Layer.Vector.renderers = ["SVG2", "VML", "Canvas"];
Note that VML (used in IE6,7,8) and Canvas (used on Android devices) behave like Renderer.SVG and don't draw features while panning.
With OpenLayer v6.4.3 you can set the following property of VectorLayer:
updateWhileAnimating boolean (defaults to false) When set to true, feature batches will be recreated during animations. This means that no vectors will be shown clipped, but the setting will have a performance impact for large amounts of vector data. When set to false, batches will be recreated when no animation is active.
updateWhileInteracting boolean (defaults to false) When set to true, feature batches will be recreated during interactions. See also updateWhileAnimating.
I don't have a solution, but made an observation. Looking at this example on Vector Behavior on the OL Examples website, if features are partially visible (i.e. placed on the border of the viewport), they remain partially hidden when dragged into full view. Only fully visible upon release of the mouse button. My point being that it seems to be a display issue more than a load issue, if that wasn't apparent already...
Will keep an eye on the question, curious to the answer. :-)
Just in case anyone stumbles across this question (as I did) OpenLayers 2.11 resolves this issue. I tested it on my web application and it now redraws vector features instantly, whereas with an older version of OL installed it would do what was written above. Something I had never noticed before either so nice one for spotting it!
Here are the release notes.
http://trac.osgeo.org/openlayers/wiki/Release/2.11/Notes
This sort of shows it in action. Best example I could find I'm afraid :P
http://openlayers.org/dev/examples/rotate-features.html

Categories

Resources