Passing Array to Openlayers 3 with geolocation and style - javascript

I am looking to create simple markers in Openlayers 3 based on a two dimensional array which I pass via PHP containing the Geolocation of the marker and an attribute. Currently the attribute is the colour that I would like the layer to be:
//run external php script to grab all entries from the database; make an array and add to source vector
var latlong_marker = <?php require 'db_multiple_gps.php'; echo $ol_latlong;?>;
var latlong_array_length = latlong_marker.length;
var vectorSource = new ol.source.Vector({
//create empty vector
});
// cycle through all entries in the array
for (var i = 0; i < latlong_array_length; i++){
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform(latlong_marker[i][0], 'EPSG:4326', 'EPSG:3857'))});
vectorSource.addFeature(iconFeature);
var iconStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({color: latlong_marker[i][2]})
})
});
//add the feature vector to the layer vector, and apply a style to whole layer
var vectorLayer = new ol.layer.Vector({
source: vectorSource,
style: iconStyle
});
}
The vector layers are presented on the map in the correct locations but the issue is that the colour is that of the last entry in the array latlong_marker[i][2].
From my research I think it may be due to closure of functions but I'm not exactly sure how or where the functions are in play here.
Debugging show the entire array being passed through the loop and vectorSource looking good; however iconStyle appears to have many null values.
Am I going about this in the right fashion? I could pass another parameter other than the actual colour required (such as a integer) to then be used to create the different style.
In addition to the code snippet above, I have played around with with closing the loop earlier; this works fro creation of vectorSource but I always fall down with trying to pass an array of iconStyle to the Vector Layer.

Try this
var latlong_marker = <?php require 'db_multiple_gps.php'; echo $ol_latlong;?>;
var latlong_array_length = latlong_marker.length;
var vectorSource = new ol.source.Vector({
//create empty vector
});
// cycle through all entries in the array
for (var i = 0; i < latlong_array_length; i++){
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform(latlong_marker[i][0],
'EPSG:4326','EPSG:3857'))});
var iconStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({color: latlong_marker[i][2]})
})
});
// THIS IS NEW - add each style individually to the feature
iconFeature.setStyle(iconStyle);
// First add the feature when it has got its style
vectorSource.addFeature(iconFeature);
}
//add the feature vector to the layer vector, and apply a style to whole layer
var vectorLayer = new ol.layer.Vector({
source: vectorSource,
// remove this - > style: iconStyle
});

Related

OpenLayers adding circle feature with same vectorSource increases opacity of all

Background
Specs
OpenLayers 4.4.1
OSM
I'm fairly new to OpenLayers and have never used vectors before (primarily because I found out that I was using OpenLayers version 1, and had to relearn everything).
My application adds circles to a map relating to a position with a specific radius indicating position accuracy.
In its operation, multiple circles are added to the map at different times.
This is my code for loading the map:
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
target: 'mapdiv',
controls: ol.control.defaults({
attributionOptions: /** #type {olx.control.AttributionOptions} */ ({
collapsible: false
})
}),
view: new ol.View({
//center: [0, 0],
zoom: 16
})
});
//this is where all map 'features' (circles) are stored
var vectorSource = new ol.source.Vector({
projection: 'EPSG:4326'
});
As you can see, I load the 'vector source' right after the map as I understood that it holds all 'vectors' which are displayed on the map so long as you specify it as the 'source'.
This is the code I use to generate the circle (source) (I tweaked it at getPointResolution because the OP made a mistake):
//code from https://stackoverflow.com/a/28299599
function addCircle(map, vectorSource, radius) {
var view = map.getView();
var projection = view.getProjection();
var resolutionAtEquator = view.getResolution();
var center = view.getCenter();
var pointResolution = ol.proj.getPointResolution(projection, resolutionAtEquator, center);
var resolutionFactor = resolutionAtEquator/pointResolution;
var radius = (radius / ol.proj.METERS_PER_UNIT.m) * resolutionFactor;
var circle = new ol.geom.Circle(center, radius);
var circleFeature = new ol.Feature(circle);
// vector layer
vectorSource.addFeature(circleFeature);
var vectorLayer = new ol.layer.Vector({
source: vectorSource
});
map.addLayer(vectorLayer);
}
Problem
Loading one circle goes normally, adds a blue stroked, opaque circle at the specified location with specified radius.
Loading a second circle appears more opaque than the last. Moving the map to the previous circle, it is also more opaque.
With each added circle, the apparent opacity increases for all displayed circles.
Running vectorLayer.getOpacity() in every circle generation results in 1, when clearly the circle is translucent, becoming increasingly opaque with every new circle.
Summary
Looking around, it appears that often it is the case that the developer is reloading the same circle over and over until many are stacked on top of one another. It almost seems like this is the case for me too, except I've triple-checked that I'm only running addCircle() once and the circle is in a different position than the last.
Is it possible that OpenLayers is redrawing all previous circles with every new circle?
Maybe this isn't related to getOpacity but has to do with the color as an rgba() combination...
Question
I want every circle to remain the same after drawing new circles. The default opacity and color is fine.
Am I doing something wrong?
Here's a fiddle as an example - https://jsfiddle.net/f5zrLt20/5/
Define the layer when defining the vectorSource:
var layer = null;
//this is where all map 'features' (circles) are stored
var vectorSource = new ol.source.Vector({
projection: 'EPSG:4326'
});
And check if it exists on creating a new circle:
// If layer is not yet set, create new layer and add it to map
if (!layer) {
vectorSource.addFeature(circleFeature);
layer = new ol.layer.Vector({
source: vectorSource
});
map.addLayer(layer);
}
//Otherwise, just add feature to the source
else {
layer.getSource().addFeature(circleFeature);
}

Openlayers 4: loading features from array

So, i'm pretty new to JS.
I'm creating features styled as markers in the center of my rgb layers and assign them to an array with this code:
for (var i = 0, len = Layers.length; i < len; i++) {
var mExtent = ol.proj.transformExtent(Layers[i].BoundingBox[0].extent, 'EPSG:4326', 'EPSG:3857');
var X = mExtent[0] + (mExtent[2]-mExtent[0])/2;
var Y = mExtent[1] + (mExtent[3]-mExtent[1])/2;
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point([X, Y]),
name: Layers[i].Title,
layername: Layers[i].Name,
description: Layers[i].Abstract
});
var iconStyle = new ol.style.Style({
image: new ol.style.Icon(/** #type {olx.style.IconOptions} */ ({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: ortho
}))
});
iconFeature.setStyle(iconStyle);
var vectorSource = new ol.source.Vector({
features: [iconFeature]
});
var vectorLayer = new ol.layer.Vector({source: vectorSource, zIndex: 100 });
layers2[i] = vectorLayer
}
when im trying then to call a map with:
var map = new ol.Map({
layers:[BaseLayers, POI, layers2],
target: document.getElementById('map')
});
My layers2 array of features does not show up on the map.
If then i try to add this array of features manually in the console:
map.addLayer(layers2)
I get following error:
TypeError: a.addEventListener is not a function
But if i try to manually call an element from array like such:
map.addLayer(layers2[0])
It works fine.
My array containing base layers(OSM+mapbox) works fine.
Im pretty sure there's something wrong with my type of array.
But don't know what.
Thanks for coming by.
Edit 1
Tried to put all my features, rgb layers and basemaps in a single array "layers".
So the code changed in a first loop from
layers2[i] = vectorLayer;
To:
layers.push(vectorLayer);
Where "layers" already contains all the rest layer objects.
When calling the map - no "vectorLayer" features are on it.
When calling "layers" manually in console with map.addLayer(layers) still get the same error.
When calling specific "vectorLayer" feature with map.addLayer(layers[2]), for example - it show's up.
By looking at the code layers2 is an array of layers. While creating ol.Map object layers attribute should be single dimension array but in your code its a 2 dimensional array like below. Thats the reason its giving error.
[ BaseLayer, POI, [layers[0],layers2[1],.....]]
Solution 1: Add array of layers after creating the map object using loop.
var map = new ol.Map({
layers:[BaseLayers, POI],
target: document.getElementById('map')
});
for ( var i=0; i<layers2.length; i++ ) {
map.addLayer(layers2[i]);
};
Solution 2 : Insert BaseLayers and POI to layers2 then configure ol.Map by declaring only layers2.

Openlayers-3 Raster Layer not Changing when Sources Changed

My server is statically serving several different PNG images of the same object, each taken with a different spectral filter (for example, just a red channel or just a blue channel). I'd like to show a slippy, false-colored map of that object. I do so by creating three separate images sources like so:
extent = [0, 0, ncols, nrows];
pixelProjection = new ol.proj.Projection({
code: 'some-image',
units: 'pixels',
extent: extent
});
rsource = new ol.source.ImageStatic({
url: "static/imgs/band_1.png",
projection: pixelProjection,
imageExtent: extent
});
gsource = new ol.source.ImageStatic({
url: "static/imgs/band_2.png",
projection: pixelProjection,
imageExtent: extent
});
bsource = new ol.source.ImageStatic({
url: "static/imgs/band_3.png",
projection: pixelProjection,
imageExtent: extent
});
Next, I use these sources as inputs to a raster source which can compose them:
rgbSources = [rsource, gsource, bsource];
raster = new ol.source.Raster({
sources: rgbSources,
operation: function(bands, data) {
var rband = bands[0];
var gband = bands[1];
var bband = bands[2];
var composed = [
rband[0],
gband[0],
bband[0],
255
];
return composed;
}
});
I then create a layer that uses this raster as its source:
colorLayer = new ol.layer.Image({
source: raster
});
Lastly, I can create a map and add my raster layer to the map:
var map = new ol.Map({
target: 'map',
view: new ol.View({
center:ol.extent.getCenter(extent),
projection: pixelProjection,
zoom: 1.5
})
});
map.addLayer(colorLayer);
So far so good! This displays a colorized version of the image as expected. The problem arises when the user triggers a change to a color channel by inputting a new channel index to pull from. I handle a blue channel change like this:
var index = 4; // actually gets passed in from user
bsource = new ol.source.ImageStatic({
url: "static/imgs/band_" + index + ".png",
projection: pixelProjection,
imageExtent: extent
});
rgbSources[2] = bsource; // this was in global scope from before
raster.sources = rgbSources; // as was this
Expected behavior is that the map would immediately change colors, or at least it would change when I zoom in or pan but neither of those things happens. I am unable to get the new colors to appear at all. Am I updating the wrong thing? Perhaps the raster.sources field has an associated setter function that I am unable to find?
Found a solution! It looks like setting a raster's source directly is not allowed, but setting a layer's source is. So unfortunately, I have to create a new raster object (new source entirely), but at least I don't need a new layer:
raster = new ol.source.Raster({
sources: rgbSources,
operation: composeBands
});
colorLayer.setSource(raster);
Accepting my own answer but willing to accept someone else's solution if it means I don't need to create a new source.

OpenLayers, nice marker clustering

Do you know how to have a nice clustering in OpenLayers such as this google example ?
You can add label to pointStyle in above example and explain context of this label.
Your code should be something like this:
var pointStyle = new OpenLayers.Style({
// ...
'label': "${label}",
// ...
}, {
context: {
// ...
label: function(feature) {
// clustered features count or blank if feature is not a cluster
return feature.cluster ? feature.cluster.length : "";
}
// ..
}
});
var styleMap = new OpenLayers.StyleMap({
'default': pointStyle,
});
var googleLikeLayer = new OpenLayers.Layer.Vector("GoogleLikeLayer", {
// ...
styleMap : styleMap,
// ...
});
Use OpenLayers.Strategy.Cluster for clustering.
Example Code
Working Example
Custom Styling
In-depth Explanation
I have just implemented a so called AnimatedCluster strategy for OpenLayers.
You can see a bit more about it at: http://www.acuriousanimal.com/2012/08/19/animated-marker-cluster-strategy-for-openlayers.html
It is only a firts version but adds a nice animation to the clusters. There are many things to improve but it is a starting point.
There's a great clustering example available in OpenLayers 3.
I created a jsFiddle from the code so you can play with it.
Basically you have to create an ol.source.Cluster with a grouping distance from an ol.source.Vector formed by an array of ol.Feature. Each ol.Feature created from your source coordinates in the form of ol.geom.Point.
var features = [
new ol.Feature(new ol.geom.Point([lon1, lat1])),
new ol.Feature(new ol.geom.Point([lon2, lat2])),
...
];
var cluster = new ol.source.Cluster({
distance: 50,
source: new ol.source.Vector({ features: features });
});
var map = new ol.Map({
layers: [
new ol.source.MapQuest({layer: 'sat'}), // Map
new ol.layer.Vector({ source: cluster }) // Clusters
],
renderer: 'canvas',
target: 'map'
});
you can do this with as igorti has said. the soltion is using OpenLayers.Strategy.Cluster class and styling your layer with OpenLayers.Style class...
for styling :
var pointStyle = new OpenLayers.Style({
'default': new OpenLayers.Style({
'pointRadius': '${radius}',
'externalGraphic': '${getgraph}'
....
},{
context:{
radius: function(feature){
return Math.min(feature.attributes.count,7)+3;
},{
getgraph : function(feature){
return 'ol/img/googlelike.png';
}}}};
it must helps you, more power to you!
Here is the JSfiddle for clustering based on custom attributes added to the layers. I struggled a bit with this so putting it here; Also shows creating a summary pie graph image when zoomed out with the clustered data http://jsfiddle.net/alexcpn/518p59k4/
Also created a small openlayer tutorial to explain this OpenLayers Advanced Clustering
var getClusterCount = function (feature) {
var clustercount = {};
var planningcount = 0;
var onaircount = 0;
var inerrorcount = 0;
for (var i = 0; i < feature.cluster.length; i++) {
if (feature.cluster[i].attributes.cluster) {
//THE MOST IMPORTANT LINE IS THE ONE BELOW, While clustering open layers removes the orginial feature layer with its own. So to get the attributes of the feature you have added add it to the openlayer created feature layer
feature.attributes.cluster = feature.cluster[i].attributes.cluster;
switch (feature.cluster[i].attributes.cluster) {
......
return clustercount;
};

open layers LineString not working

Sorry to bother you guys, but I'm stuck with his problem for half a day.
I want to draw poly line in OpenLayers using LineString object, so I've copied the example from documentation. It runs ok but i can't see the line on the screen
Code looks like this
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title></title>
<script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script>
<script src="http://www.openstreetmap.org/openlayers/OpenStreetMap.js"></script>
<script src='http://maps.google.com/maps?file=api&v=2&key=ABQIAAAAjpkAC9ePGem0lIq5XcMiuhR_wWLPFku8Ix9i2SXYRVK3e45q1BQUd_beF8dtzKET_EteAjPdGDwqpQ'></script>
<script type="text/javascript">
var map;
var lineLayer ;
var points;
var style;
var polygonFeature
function test()
{
lineLayer = new OpenLayers.Layer.Vector("Line Layer");
style = { strokeColor: '#0000ff',
strokeOpacity: 1,
strokeWidth: 10
};
map.addLayer(lineLayer);
points = new Array();
points[0] =new OpenLayers.LonLat(-2.460181,27.333984 ).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());;
points[1] = new OpenLayers.LonLat(-3.864255,-22.5 ).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());;
var linear_ring = new OpenLayers.Geometry.LinearRing(points);
polygonFeature = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Polygon([linear_ring]), null, style);
lineLayer.addFeatures([polygonFeature]);
alert("1");
}
function initialize()
{
map = new OpenLayers.Map ("map_canvas", {
controls:[
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.LayerSwitcher(),
new OpenLayers.Control.Attribution()],
maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),
maxResolution: 156543.0399,
numZoomLevels: 19,
units: 'm',
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326")
});
// Define the map layer
// Here we use a predefined layer that will be kept up to date with URL changes
layerMapnik = new OpenLayers.Layer.OSM.Mapnik("Mapnik");
map.addLayer(layerMapnik);
var lonLat = new OpenLayers.LonLat(0, 0).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
map.zoomTo(3);
map.setCenter(lonLat, 19);
test();
}
</script>
</head>
<body onload="initialize()" >
<div id="map_canvas" style="width: 828px; height: 698px"></div>
</body>
</html>
I'm sure I'm missing some parameter in creation of map or something but I really can't figure which one.
You forget 's' character in this line:
lineLayer.addFeatures([lineFeature]);
Function 'addFeature' doesn't exist: OpenLayers.Layer.Vector.addFeatures
To see the feature, hold Shift key on your keyboard and try to draw a box
EDIT: Ok, now I know how did you want.
You need to create one OpenLayers.Point object for each point you have in your DB. One solution is to use and Ajax call to your own PHP function to retrieve them. The PHP file includes code to get them. I recommend to return them in JSON format (pherhaps an string). Using JQuery framework:
$.ajax({
url: 'your_php_file.php',
dataType: JSON // for example, you can use 'string' type too
success: function(coordinates){
}
});
Now you have a lot of coordinates from your DB. It's time to draw your polygon. Following link can be useful
OpenLayers - how do I draw a Polygon from existing lonLat points?
I hope it helps you. Happy codding!
EDIT2:
linear_ring is an object belongs to OpenLayers.Geometry.LinearRing class. The constructor needs an array of OpenLayers.Geometry.Points and you was giving it OpenLayers.LonLat array.
You need to modify this adding this line after each point creation (modifying the index according to you own code):
points[0] = new OpenLayers.Geometry.Point(points[0].lon,points[0].lat);
So your test function looks like this:
function test(){
lineLayer = new OpenLayers.Layer.Vector("Line Layer");
style = { strokeColor: '#0000ff',
strokeOpacity: 1,
strokeWidth: 10
};
points = new Array();
points[0] =new OpenLayers.LonLat(-2.460181,27.333984 ).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());;
points[0] = new OpenLayers.Geometry.Point(points[0].lon,points[0].lat);
points[1] = new OpenLayers.LonLat(-3.864255,-22.5 ).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());;
points[1] = new OpenLayers.Geometry.Point(points[1].lon,points[1].lat);
var linear_ring = new OpenLayers.Geometry.LinearRing(points);
polygonFeature = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Polygon([linear_ring]), null, style);
lineLayer.addFeatures([polygonFeature]);
map.addLayer(lineLayer);
}
The result is this: Image result
Yes, OpenLayers can programatically draw lines. Its even fast enough to draw new lines multiple times a second so you can show live data or animations. Anyway, you have a lot of stuff going on in your code. Perhaps your style is messed up and drawing invisible lines, or your data points are getting transformed incorrectly and the line is off the map. Anyway, I suggest this simple test.
Create a map, and add a vector layer. hang on to the vector layer in a global var called layerVec. Then, run this code.
var CreateLine = function()
{
var pList = new Array();
for(var i=0; i<200; i++)
{
var p = new OpenLayers.Geometry.Point();
p.x = i;
p.y = i;
pList.push(p);
}
var g = new OpenLayers.Geometry.LineString(pList);
var f = new OpenLayers.Feature.Vector(g,null,null);
layerVec.addFeatures(f);
};
Dont worry about coordinates yet, this should be a line in the middle of the map. It may be tiny, or huge depending on your projection, so zoom in.

Categories