The closest post I could find to my question is Compound complex feature in OpenLayers. Alas, no one answered it. I am quite proficient in JavaScript but relatively new to OpenLayers and its complex API. I have created complex Controls prior to this. However, this time I am looking to create a complex Feature / Vector. The general idea of it is that the feature has a display icon (like a pin, for example) as the main component. The component is interactive and responds to user actions (select, drag, etc). Upon selection, I desire to render additional vectors that are logically associated with this component (circles, rectangles, etc). These Vectors listen to user interactions as well.
Previously, in case of Controller, I was able to use source of other controllers to make sense of development direction and successfully proceed. Its a little harder with Features / Vectors, imho.
I started by extending OpenLayers.Feature.Vector using OpenLayers.Feature.Vector.CustomClass = OpenLayers.Class( OpenLayers.Feature.Vector, {...}); code. Constructor takes specific parameters to my feature, creates several geometry objects (points, polygon, lines), adds them to the OpenLayers.Geometry.Collection, and invokes OpenLayers.Feature.Vector constructor with collection passed into it.
Unfortunately, I realized that in order to display an icon, I cannot just use a Geometry.Point but need to create a Vector for it. That kind of threw me off because I will create Vectors within my custom Vector object. It is nothing unusual in general but I wonder if this is the way things are done in OpenLayers. Like I have mentioned, I do not find API documentation very useful as it simply states general function headers / brief description.
I would greatly appreciate if someone could point me into the right direction (haven't found many tutorials online beyond the basic "create marker with custom image" types). If the description isn't clear, let me know and I'll try to provide additional information.
I've had to tackle similar problems in the past. The best approach with OpenLayers (or any mapping tool for that matter) is usually to separate your layers into feature classes, each of which represents a collection of points, lines, or polygons. Once you create all of your layers, you can create a select control that listens for events on each of these layers and responds appropriately.
If you need to logically associate subsets of these features together, you could store references to these features externally, or within the parent feature's attributes object.
My solution is to provide a FeatureCollection geojson as the complex/compound type data. In my case the FeatureCollection consists of many Point features, and one LineString feature. Openlayers can consume this geojson:
var features = (new ol.format.GeoJSON()).readFeatures(geojson)
... and provide the collection of features. You can then iterate over those features and provide some unifying attribute/object to each feature. Then, when you define event handlers (hover or select/click), access the unifying attribute to get hold of any other related feature.
Related
I want to search a layer for specific properties, so i want to get all features info of the layer for the whole map not for a specific coordinate. For a certain point i use getGetFeatureInfoUrl . Is there a function to get features for the whole layer?
You simply can't or not this way around at least.
You have two choices to maybe bypass the issue depending of your goal(s):
If it's just about rendering layer, you can use SLD to style WMS to render WMS only matching you criteria(s). Default WMS layer could be a river with a column river_width. You could only display the layer with river_width > 5m using SLD. However, you will not get the properties except some of them when clicking (like you already do with WMS GetFeatureInfo)
If you really want the properties, you may call the WFS endpoint if the WMS layer you use is also available through WFS.
In this case, you will use WFS with Filter Encoding or CQL/ECQL filter (only available in GeoServer). If there are too many results or the geometry are too big, it may overload the server or take it to long to return the result.
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.
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. ;-)
I'm somehow new in making web services using Openlayers and Javascript. I would like to create a clickable grid layer on top of a map (e.g. OSM) which first has a defined spatial resolution (e.g. 200 m) and of course when user zooms the grid size adapts to the new zoom level of the map. Also I want to show every cell of a grid with a specific colour, and when the user clicks on each cell some information can be shown. So, I guess each cell is like a feature in this layer (e.g. polygon). I was wondering if Openlayers has existing function to do such a thing that I can use, or do I have to code all of it? any help and suggestions on how I can manage to do this would be highly appreciated. Below is a link to a service that has created such a service, I would like to do the same... Thanx.
Link to sample:
http://koenigstuhl.geog.uni-heidelberg.de/osmatrix/#timestamp/allotments_area/8/12/-0.2142333984375/51.578776399817066
Having developed the application you mention in your example, I can give you some hints on your question. The solution is pretty straightforward.
The grid you see, i.e. the coloured hexagons, is simply map tiles, that are served by a custom back-end following the Tile Map Service schema (I used NodeJS) that, in turn, uses Mapnik (any other engine should work as well, e.g. GeoServer or MapServer) for rendering the images. The data is stored in a Postgres data base with PostGIS added on.
Use a client-side library to create the map and add the tiled layer. OpenLayers and Leaflet both do the job well. (Leaflet, though, is a bit easier to grasp if your new to the topic).
On client side you register a click-event handler on the Map, that you can use to get the coordinates of the mouse click. Use these coordinates, send them to your back-end and perform a spatial query on the data base to get the polygons adjacent to the coordinates. The server's response should then provide the geometries of the polygons (encoded in GeoJSON in this case, GML, KML should work fine as well) and whatever information you want to display.
Use these polygons and add them to a vector layer using whatever colour scheme you want.
Have a look at the code to see how it works. The important files are osmatrix.js (connects to the back-end), control.js (main module, keeps track of everything) and map.js (surprisingly enough, everything map-related).
Openlayers has facilities for creating an interactive vector later. In order to create something like in the example, you would have to 1) add a vector layer, 2) write a loop that adds vector features to the appropriate locations on the map, 3) style the features as hexagons, and 4) create a stylemap that dynamically sets the feature color based on the appropriate parameters. Each step is facilitated by Openlayers.
A good start is to use the leaflet library because it use the map projection and to read this tutorial: http://build-failed.blogspot.de/2013/07/dynamically-creating-hexagons-from-real.html?m=1.
I have a series of Leaflet FeatureGroups that are made up of a series of GeoJSON layers. The FeatureGroups are conceptually similar but I need them to be separate for certain control reasons. I also need to be able to turn them all on and off at once. Is there a way to do this?
I looked in the documentation and couldn't find an event that fires when the FeatureGroup is switched on and off. There is also no documented way of lumping the FeatureGroups into some kind of superGroup.
For those who want to picture it, here is the workflow:
GeoJSON gets data that is turned into layers in Leaflet. This is of different administration boundaries (e.g. States, Counties, etc...). Each of the layers goes into a different FeatureGroup based on its type (e.g. Arkansas and New York go into the State FeatureGroup, Ford and Lincoln counties go into the County FeatureGroup). This way I have control over opacity and styling for the different FeatureGroups (e.g. when I'm looking at the Counties of a state, I can lower the opacity of all the other states). I also need a way of turning all of this off and back on again. Leaflet provides the ability to do that on a FeatureGroup by FeatureGroup basis, but not a super set of that.
Any ideas on how to achieve this?
New version of question:
What is the event that fires when turning a LayerGroup On and Off? Is there anyway to hook into that?
I ended up having my usual LayerGroups or FeatureGroups, and then a FeatureGroup that contains all the layers on all the groups. So when you add a shape or layer to a FeatureGroup, also add it to the FeatureGroup that you are using to keep track of everything. And of course if you remove don't forget to remove it.
You can add this base FeatureGroup to the map along with the other groups and it should be fine.
I don't think Leaflet currently provides an event when a LayerGroup is turned on or off (you are talking about with the L.Control, right?). I agree that it would be useful. For now, you can just extend the code to do whatever you need to be done. For example:
var customLayerControl = L.Control.Layer.extend({
_onInputClick: function(Layer, name){
// This is just like calling super() if this confuses you!
L.Control.Layers.prototype._onInputClick.call(this,Layer,name);
// Do stuff
}
});
Then instead of using the L.Control.Layers, use your custom layer control:
map.addControl(new customLayerControl({}, {'Custom Layer':customLayer},{}));
I hope this helps.