OpenLayers features redraw only after mouse moveend - javascript

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

Related

Triggering responsive behavior when dynamically resizing amCharts 4 chart

The most recent version of amCharts (I'm using v4.7.8) includes a couple of mechanisms to allow for responsive chart designs. I'm trying to take advantage of the chart.responsive.rules feature, which allows for different chart property values based on the size of the chart (and/or inner chart elements).
At the same time, we've implemented a "zoom" feature on all of our charts. Each chart is wrapped in a "zoomable" container element, and the charts are styled to be 95% of the container width. When the "zoom" icon-button is clicked, the container is set to position: fixed; top: 3rem; right: 3rem; bottom: 3rem; left: 3rem;, mostly filling the screen.
The problem is that the chart just... doesn't seem to notice this. If I create the chart at the zoomed size, it uses the correct ruleset, but if I create the chart at a smaller size, then resize it to be large, it continues to use the "small" ruleset. I've tried calling chart.appear, chart.invalidate, and chart.deepInvalidate after resizing, but the result is always the same: the chart renders with whatever ruleset it was originally initialized with.
The one thing that makes me think that at least SOMETHING is happening (though mis-timed) is the fact that when I zoom in (so the chart is fullscreen) and then use the horizontal scrollbar, the scrollbar moves faster than my mouse cursor - almost as if it thinks it's smaller than it is. That holds up with my initial impressions. However, once I resize the chart BACK to being small, the scrollbar moves slower than my mouse cursor, as if it thinks the chart is BIGGER than it is.
This whole thing is all done with multiple LitElement web components, so it's difficult to provide a fiddle/codepen example, but if necessary I can mock up an example that should at least demonstrate the problem. I'm not sure if that would be necessary, as I suspect someone who knows what they're talking about would know the answer to this offhand, but if you think it'll help, let me know and I'll see what I can do.
Edit: I've found a workaround, but it's hardly ideal. I found that if I completely dispose of the existing chart on zoom in/out and completely recreate it at the new size, then it behaves the way I want, but it is SERIOUSLY processor intensive to recreate some of these charts. I'd still very much prefer to find a solution that can take advantage of the current chart and just recalculate its layout.
try using setTimeout(()=>{chart.responsive.enabled = false;chart.responsive.enabled = true; }) after resize
Turns out, the answer is that amCharts 4 does not support the actual properties I'm trying to change via the responsive rules. The properties in question are groupData and groupCount. Support tells me that the logic surrounding those features was considered too complex to support dynamic updates. I asked them to please reconsider that decision. We shall see if they do.
What I've done in the meantime to solve my problem is to create two charts, one configured for the larger size and one for the smaller size, and I just swap out which one is displayed when zooming in/out.

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.

Creating own dynamic layer type in OL3

I am currently migrating a special dynamic layer type I created for OpenLayers from OL2 to OL3. The layer displays markers (a lot of them, usually around 1000) that are moving on predefined trajectories. Trajectories are loaded in a special JSON format from a server.
My current approach for OL2 is very performant, heavily optimized and uses the Raphael library (http://raphaeljs.com/). The general application layout looks like this:
OpenLayers2 is loaded, the map is created
A special layer "DynLayer" is created which is modelled after OL2's own VectorLayer. This layer handles communication with OL2 (zooming, panning, dragging etc) and provides a very sophisticated asynchronous mechanism to redraw to map (that is, move the markers) based on the current interaction (for example, the refresh rate goes down if the user is currently panning to map to prevent a stuttering effect). During construction, the DynLayer creates a Raphael SVG-layer and attaches it into the DOM. If the map is panned or zoomed, the Raphael layer is synchronized by the DynLayer.
Markers are then created on the SVG-layer and their position is periodically updated
This approach works extremely well and because Raphael supports older IE versions, it also runs in IE8 and IE7. It also enables me to provide animations based on Raphaels built-in animate method.
I am now trying to migrate this application to OL3 and I am not 100% sure what the best approach would be. Is it possible in OL3 to add custom-built layers after OL3 is loaded? If so, is there any documentation? I tried implementing my own version of a VectorLayer, but OL3 threw a ton of errors related to the goog object provided by the Closure API.
More generally speaking: would it be better to recreate my old approach and draw a Raphael layer on top of OL3? This method would allow me to reuse most of my previous code. Or should I use methods provided by OL3 to draw directly on a HTML5 canvas? If so, how can I obtain control of the refresh rate of the canvas?
I had I a look at the example at http://ol3js.org/en/vector-api/examples/dynamic-data.html?q=dynamic but it does not really fullfil my needs. The markers are animated in an endless loop, and I need specific control over the refresh rate. More generally, how do I prevent my markers from being deleted on one of OL3's own canvas refreshes (for example, if new tiles are loaded).
My general impression of OL3 is that it is more difficult to add own extensions than with OL2, which appeared more 'open' to me than OL3.
Thanks for any help!
Note that OL3 is not meant to work well with IE7 or other 'old' browsers.
As far as I understand OL3 was build for performance and has fast vector rendering.
It also integrates with d3, so it can probably integrate with other technologies.

Canvas or SVG (or a blend) for large Org Chart

The main question is pretty simple... I'm making a rather large Organization Chart (or genealogy) and I'm wondering whether I should be using SVG or Canvas.
Some of the requirements might sway the choice:
Must be able to display between 1 to 50,000 nodes/people
Needs to pan and zoom much like a Google/Bing map.
Need to be able to click on a node and pop open a dialog with extra details on the person.
I was initially leaning towards SVG, but I heard somewhere that it would have performance problems when drawing a large number of items. Also, it seems Canvas has better support in older browsers.
Thanks everyone for your input. The following is what I have come up with after exploring some of the advice given.
SVG: This route was very tempting due to its vectorized nature and its integration into the DOM. Sadly the performance of rendering +100k nodes killed this route.
Canvas: Performance wise this seemed to be a winner. However, at this point I will need to explore how to add onClick/onHover functionality to each of the rendered nodes.
Leaflet: This too is a winner. It takes care of a lot of concerns like the map-like navigation, performance and mobile ready. Though it isn't a solution as to 'how' to draw the org chart. However, what is nice about it is that you can feed it image tiles or canvas. Which gives us some choice.
So in the end it is likely that I'll be using image titles to begin with and then migrating to canvas... while keeping my eye on performance advancements in SVG.

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

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.

Categories

Resources