i am currently working on a project where a user should be able to edit zones (= polygons). I have created a class Zone which extends L.Polygon so I can create zones and add them to the map. The editing of a specific instance of Zone is triggered by a button, which rund the following code: specificZone.editable.enable()
This works so far and looks like this:
The problem I have, is that when dragging the edit points around, one corner point always behaves like an edge point: So it splits the corner like this:
The other points behave as intended. I hope this was somewhat understandable outlined.
I am thankful for any kind of help. Have a nice day :)
Kind regards
Luca
Edit:
My map gets created as follows:
A Vue Component Map.vue creates an instance of CustomMap.ts:
const customMap = new CustomMap(
document.getElementById("mapcontainer") as HTMLElement,
mapUrl,
mapParams.getData()
);
the mapUrl is the place where the map is stored and the mapParams are previously loaded from a server
In the constructor of CustomMap.ts a L.DrawMap gets created, then the map gets added to the map as an instance of CustomImageOverlay which creates a L.imageOverlay. After that the L.FeatureGroup for the CustomZone(s) gets created.
this.map = L.map(el, {
crs: L.CRS.Simple,
center: [0, 0],
zoom: 4,
minZoom: 2,
maxZoom: 7,
dragging: true,
maxBoundsViscosity: 0.5,
maxBounds: mapBounds,
zoomSnap: 0.25,
zoomDelta: 0.25,
attributionControl: false
});
this.imageOverlay = new CustomImageOverlay(
mapUrl,
mapBounds.getNorthEast(),
mapBounds.getSouthWest(),
{
opacity: 0.5,
interactive: true,
zIndex: -1
},
this.map
);
this.map.addLayer(this.imageOverlay.getLayer());
// Create a group for zones and add it to map
const zoneGroup = new L.FeatureGroup();
zoneGroup.addTo(this.map);
// init drawers
this.polygonDrawer = new L.Draw.Polygon(this.map);
// Layers to show/hide
const overlayLayers: L.Control.LayersObject = {
Zones: zoneGroup,
};
// Create Layer Control with the previous options
const layerControl = new L.Control.Layers(base, overlayLayers);
// Add to map
layerControl.addTo(this.map);
The CustomZone is created and added to the feature group and map.
In the constructor of the customZone the actual polygon gets created by super(latlng, options)
I hope this code gives you better insight :)
Related
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);
}
i would appreciate some help in understanding why there are two different panoId patterns on Google StreetView.
I'm initializing photospheres with the following JavaScript code:
function initialize() {
var pocetneKoordinate = new google.maps.LatLng(44.81856295912351, 20.455767810344696);
var pocetniPanoID = 'F:-By57yDKJr5M/WWfMHHWwYjI/AAAAAAAACXU/v1tk1TK02yEmBWGt2U4sMK1d_Uf3qdKmwCLIBGAYYCw';
var mapOptions = {
center: pocetneKoordinate,
zoom: 0
};
var map = new google.maps.Map(document.getElementById('panorama'),
mapOptions);
panorama = map.getStreetView();
var panoOptions = {
position: pocetneKoordinate,
pano: pocetniPanoID,
visible: true,
pov: {
heading: 41,
pitch: 0,
zoom:1,
},
clickToGo: false
};
panorama.setOptions(panoOptions);
// Create a StreetViewService object.
var streetviewService = new google.maps.StreetViewService();
}
Just in case I pasted something wrong, working JSFiddle https://jsfiddle.net/markovica/pcLjbmwk/
It all works great, but what confuses me is that I open the same panorama with two different PanoID strings, ex:
CAoSLEFGMVFpcE1EZGhWWFJzVzBTd0I4amlQOWtjdEJ3Z3MwVnYtNTZBbEJNRHBI
F:-By57yDKJr5M/WWfMHHWwYjI/AAAAAAAACXU/v1tk1TK02yEmBWGt2U4sMK1d_Uf3qdKmwCLIBGAYYCw
Besides that, on other linked photospheres, panorama.getPano() will return the pattern of the initial pano, and links are not exactly the same (Screenshot showing differences in links) - there are some slight differences which I suppose are due to my recent edits.
But why are there two panoIDs for the same panorama and why are they behaving slightly different?
The correct way of retrieving PanoID is by querying StreetView Publish API. It will give the first pattern.
I used the API explorer:
https://developers.google.com/apis-explorer/#p/streetviewpublish/v1/
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'm using OpenLayers3 with OSM as a background map. I'm retrieving coordinates when clicking on the map. However, for some reason I do not understand, the coordinates returned differ from what they should be.
The crs is EPSG:3857 and the coordinates returned are for example:
[149320862354.13303, 7149613.877682245]
But they rather should look like this:
[1347655.049747, 7147342.608955]
I do not know why they are returned like this. I did not change anything in my code or configuration.
map.on('singleclick', function (e) {
var coordinates = map.getEventCoordinate(e.originalEvent);
console.log(coordinates);
}
Any ideas what is causing this?
Edit:
I've logged the map object to console:
projection_: ol.proj.EPSG3857_
revision_: 0
values_: Object
center: Array[2]
0: 149320863424.25146
1: 7177589.830034621
length: 2
__proto__: Array[0]
resolution: 152.8740565703525
rotation: 0
As you can see the coordinates of the center (especially center[0]) are wrong. I guess this issue may be caused by creating the map.
var map = new ol.Map({
layers: [
gnMap.getLayersFromConfig() //MapQuest, OSM, Bing
],
renderer: 'canvas',
view: new ol.View({
center: [0, 0],
projection: 'EPSG:3857',
zoom: 2
})
});
But I can't figure out why those are either created or returned wrong.
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.