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);
}
Related
I'm trying to set the pivot point of a group that contains a raster image to the center of the screen to no avail.
Please see my current code here: condesandbox example
Any help will be much appreciated
Based on your code example, I guess that you just have to set the position of your raster to be the view center and its pivot point will automatically be the same by default.
Here is a sketch demonstrating a possible solution.
// Create the raster.
const raster = new Raster({
source: 'http://assets.paperjs.org/images/marilyn.jpg',
// When image is loaded...
onLoad: () => {
// ...place it at center.
raster.position = view.center;
}
});
// Include raster in a group.
const group = new Group(raster);
// Mark center with a circle.
new Path.Circle({
center: view.center,
radius: 10,
fillColor: 'blue'
});
// Scale the group (the pivot point is bounds center by default).
group.scale(0.5);
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.
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
});
I want to create a hole in my Javascript Google API V3, so i follow Beginning Google Map API V3. But the code is rendering the whole area. Here is my Javascript code.
(function() {
window.onload = function() {
// Creating a map
var options = {
zoom: 6,
center: new google.maps.LatLng(36.5, -79.8),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map'), options);
// Creating an array with the points for the outer polygon
var polyOuter = [
new google.maps.LatLng(37.303, -81.256),
new google.maps.LatLng(37.303, -78.333),
new google.maps.LatLng(35.392, -78.333),
new google.maps.LatLng(35.392, -81.256)
];
// Creating an array with the points for the inner polygon
var polyInner = [
new google.maps.LatLng(36.705, -80.459),
new google.maps.LatLng(36.705, -79),
new google.maps.LatLng(35.9, -79),
new google.maps.LatLng(35.9, -80.459)
];
var points = [polyOuter, polyInner];
// Creating the polygon
var polygon = new google.maps.Polygon
({
paths: points,
map: map,
strokeColor: '#ff0000',
strokeOpacity: 0.6,
strokeWeight: 3,
fillColor: '#FF0000',
fillOpacity: 0.35
});
};
})();
One of the paths has to be reverted so polygons are drawn in different directions, for example:
var polyInner = [
new google.maps.LatLng(35.9, -80.459),
new google.maps.LatLng(35.9, -79),
new google.maps.LatLng(36.705, -79),
new google.maps.LatLng(36.705, -80.459)
];
My assumption is that the reason is how SVG or canvas render closed loops. If I am not wrong explanation lies in nonzero winding rule. See explanation at wikipedia.
Outer path is drawn clockwise, inner path is drawn counter-clockwise.
Set a counter to zero. Pick a point in object area and draw a line in direction out of object space. If the line cross clockwise path, add one. If the line cross counter-clockwise path segment, subtract one. If the final result for selected point is non-zero, the browser fills the area. If the final result is zero, the browser does not fill it.
So, if you pick up point in the 'hole', the result will be zero and area will not be filled.
I'm very new to OpenLayers and I'm trying to show a map on my home page, which shows only Australia, and then later add some points on the map. The important thing right now, is to just open the map to Australia.
I'm using the example found on OpenLayers home page, with:
var map = new OpenLayers.Map('map');
var wms = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://vmap0.tiles.osgeo.org/wms/vmap0", {layers: 'basic'} );
....
I'm guessing that I have to pass something to the constructor to have it display only a specific region?
Thanks,
Sam
Found this on another stackoverflow question:
var bounds = new OpenLayers.Bounds(-125, 25, -65, 50);
var map = new OpenLayers.Map('map', {restrictedExtent: bounds });
Open Layers uses projection to accommodate a 2D map of a 3D world. Projection is a mathematical way of saying that on a 3D sphere (the world) the coordinates x,y are actually x,y somewhere else on a 2D map. In openlayers this involves changing the view, you can use the fromLonLat() method. More information on projection here: https://openlayers.org/en/latest/doc/faq.html
mapOfAustralia = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
target: targetElement,
controls: ol.control.defaults({
attributionOptions: {
collapsible: false
}
}),
view: new ol.View({
center: ol.proj.fromLonLat([133.7751, -23.2744]),
zoom: 4
})
});