kml style on draganddrop and ol.interactionSelect - javascript

With ol 4.4.2 kml style with drag and drop is very difficult and I can't set it by the layer style.
I can style it through the feature, but when I do, it's the style of the select interaction that does not work anymore.
The extractStyle: false does not work anymore.
Is there a bug ?
How can I do it ?
dragAndDropInteraction.on('addfeatures', function(e) {
var vectorSource = new ol.source.Vector({
opacity: 1,
features: new ol.Collection(),
format: new ol.format.KML({
extractStyles: false, defaultStyle: AnnotImportStyle
}),
visible: true
});
var features = e.features;
//features.forEach (function(s){s.setStyle(AnnotImportStyle)}); it works but put the style of select out
vectorSource.addFeatures(features);
var file_name = e.file.name;
var name = file_name.substr(0, file_name.lastIndexOf('.'));
var vector = new ol.layer.Vector({
title: name,
source: vectorSource,
style: AnnotImportStyle,
visible: true,
});
map.addLayer(vector);
map.getView().fit(vectorSource.getExtent());
});

Related

How to make a popup with GET/POST request ASP NET CORE

I have a map, with n numbers of markers with a unique ID. When I click on them a custom popup for that marker appears (using JS and CSS). Every time I click on one of the markers, I want it to send a POST request that will change the URL from ~/reports/index to ~report/index/custom_Id. I need it to be with a custom id in the URL because I need to load some popups from another page using GET request.
My code:
Load map:
<script type="text/javascript">
var layers = [new ol.layer.Tile({ source: new ol.source.OSM() })];
var map = new ol.Map({
target: 'map',
view: new ol.View({
zoom: 5,
center: [166326, 5992663]
}),
interactions: ol.interaction.defaults({ altShiftDragRotate: false, pinchRotate: false }),
layers: layers
});
const options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
};
function togglePopup(id) { //The function that revals the popup
document.getElementById("overlay-container-" + id).classList.toggle("active");
}
// Vector Feature Popup logic
map.on('click', function (e) { //The "sensor" that detects if a marker has been clicked.
map.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
togglePopup(feature.getId());
resetCurrent();
handleImages(feature.getId());
})
})
Add markers (this is inside a bigger for loop):
<script type="text/javascript">
markers = new ol.layer.Vector({
source: new ol.source.Vector(),
style: new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: 'https://ucarecdn.com/4b516de9-d43d-4b75-9f0f-ab0916bd85eb/marker.png' // => https://app.uploadcare.com/projects/c05bbeb5e1a61e862903/files/7110cd57-b0ee-4833-bcd1-ff0343dd01cc/?limit=100&ordering=-datetime_uploaded
})
})
});
map.addLayer(markers);
var marker = new ol.Feature(new ol.geom.Point([parseFloat(#_Data.coordLat), parseFloat(#_Data.coordLong)]));
marker.setId(#_Data.Id);
markers.getSource().addFeature(marker);
</script>
I know that if it was a HTML button for something like that I could have add asp-route-id=#_Data.Id or something but this is JS. How can I make it?

how to change the default marker OPENLAYERS 5

I am trying to display some markers on the OSM. This works so far, but i just wanted to change the default marker against another one from a local path, but i didnt know how to add this to my code, i have tried the setStyle but i didnt know how to apply it correctly. It would be also nice if am able to style the icon too.
I also want markers to be dynamically displayed, because i am doing this manually each time through
var layer = new ol.layer.Vector({source: new ol.source.Vector({
features: [
new ol.Feature({
geometry: new ol.geom.Point(ol.proj.fromLonLat([4.35247, 50.84673]))
}),
new ol.Feature({
geometry: new ol.geom.Point(ol.proj.fromLonLat([4.35247, 52.84673]))
}),
]
});
Here is a snippet of the full code that i use
/* open street map newest version */
var map = new ol.Map({
target: 'map', // the div id
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.fromLonLat([4.35247, 52.520008]),
zoom: 4
})
});
// add a marker to the map
var layer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [
new ol.Feature({
geometry: new ol.geom.Point(ol.proj.fromLonLat([4.35247, 50.84673]))
}),
new ol.Feature({
geometry: new ol.geom.Point(ol.proj.fromLonLat([4.35247, 52.84673]))
})
]
})
});
map.addLayer(layer);
//initialize the popup
var container = document.getElementById('popup');
var content = document.getElementById('popup-content');
var overlay = new ol.Overlay({
element: container,
autoPan: true,
autoPanAnimation: {
duration: 250
}
});
map.addOverlay(overlay);
//display the pop with on mouse over
map.on('pointermove', function (event) {
if (map.hasFeatureAtPixel(event.pixel) === true) {
var coordinate = event.coordinate;
content.innerHTML = '<b>Hello world!</b><br />I am a popup.';
overlay.setPosition(coordinate);
}
else {
overlay.setPosition(undefined);
closer.blur();
}
});
Fixed this, the issue was from the local path. If this may help anyone i added this to my code
layer.setStyle(new ol.style.Style({
image: new ol.style.Icon({
src: 'https://wiki.openstreetmap.org/w/images/0/0c/Hgv.png'
})
}));

How to style KML?

I have added drag and drop to my map, based on https://openlayers.org/en/latest/examples/drag-and-drop.html. Styling works for f.i. gpx but fails for kml.
Whatever I try, I can't get the kml features styled the way I want. Kml files with a style included are shown using that style but I cannot replace the style with my style. Kml with points but without a style are shown using a terrible old Google style push pin.
var styleFunction = function (feature, resolution) {
console.log("in styleFunction()");
var featureStyleFunction = feature.getStyleFunction();
if (featureStyleFunction) {
return featureStyleFunction.call(feature, resolution);
} else {
return defaultStyle[feature.getGeometry().getType()];
}
};
var dragAndDropInteraction = new ol.interaction.DragAndDrop({
formatConstructors: [
ol.format.GeoJSON,
ol.format.TopoJSON,
ol.format.EsriJSON,
ol.format.IGC,
ol.format.GPX,
ol.format.KML
]
});
map.addInteraction(dragAndDropInteraction);
dragAndDropInteraction.on('addfeatures', function (event) {
console.log("in dragAndDropInteraction");
const ext = event.file.name.split('.').pop().toLowerCase();
console.log(" ext: " + ext);
let vectorSource;
let layer;
switch (ext) {
case 'gpx':
vectorSource = new ol.source.Vector({
features: event.features,
format: new ol.format.GPX(),
// readExtensions:
});
break;
case 'kml':
vectorSource = new ol.source.Vector({
features: event.features,
format: new ol.format.KML({
extractStyles: false,
// showPointNames: false,
// extractAttributes: true,
// writeStyles: false
}),
});
break;
default:
break;
}
if (vectorSource) {
map.addLayer(new ol.layer.Vector({
source: vectorSource,
style: styleFunction
}));
map.getView().fit(vectorSource.getExtent());
}
An example at jsfiddle
Thanks.

Delete VectorLayer

I am trying to delete VectorSource Layer for redraw markers. The problem is that when I execute a setInterval function every 3 seconds, the new markers overlap to previous markers. The previous markers are not deleted.
I am trying with
map.getLayers().item(1).getSource().clear();
map.getLayers().item(1).getSource().getSource().clear();
But it not work.
So:
Mi code is:
var vectorSource = new ol.source.Vector({
features: iconFeatures //add an array of features
});
var clusterSource = new ol.source.Cluster({
source: vectorSource,
distance: 40
});
var vectorLayer = new ol.layer.Vector({
source: clusterSource,
style: clusterStyle
});
// Maps
var map = new ol.Map({
controls: ol.control.defaults({
attributionOptions: /** #type {olx.control.AttributionOptions} */ ({
collapsible: false
})
}),
target: 'map', // The DOM element that will contains the map
renderer: 'canvas', // Force the renderer to be used
layers: [
// Add a new Tile layer getting tiles from OpenStreetMap source
new ol.layer.Tile({
source: new ol.source.OSM()
//source: new ol.source.OSM({
//crossOrigin: null,
//url: 'http://34.240.39.198/osm_tiles/{z}/{x}/{y}.png',
//}),
}),
vectorLayer,
],
// Create a view centered on the specified location and zoom level
view: new ol.View({
center: ol.proj.transform([-3.7467975, 40.3705281], 'EPSG:4326', 'EPSG:3857'),
zoom: 3,
maxZoom: 15,
minZoom:2,
//extent: [226838, 5084100, 255700, 5055200],
}),
/*interactions: ol.interaction.defaults({
dragPan: false
}),*/
});
And function for Redraw is:
function get_traces(){
var token = $('meta[name="csrf-token"]').attr('content');
$.ajax({
type: "post",
url: "device_mapA",
typeData:'JSON',
data: {
'_method': 'POST',
'_token': token,
}, success: function (showdevice) {
removeAllMarkers();
iconFeatures = [];
showdevice[0].forEach(function(index) {
changeMarker(showdevice[0]); //this function redraw iconFeatures array correctly.
});
});
// console.log(iconFeatures);
var vectorSource = new ol.source.Vector({
features: iconFeatures //add an array of features
});
var clusterSource = new ol.source.Cluster({
source: vectorSource,
distance: 40
});
var vectorLayer = new ol.layer.Vector({
// source : vectorSource,
source: clusterSource,
style: clusterStyle
});
map.getLayers().item(1).getSource().clear();
map.getLayers().item(1).getSource().getSource().clear();
map.addLayer(vectorLayer);
map.getLayers().item(1).getSource().clear();
//console.log(map.getLayers().item(1).getSource()); It not working neither.
}
It does not actually abort those 7 iterations, it just skips those array items.
In your forEach cycle there is an array of references to map layers. If you take an element of that array (reference is "layer") and you remove it from map as it is, you remove the reference, so it is neither in the map nor in your array anymore and accidentally there is another reference on that index.
So if you have array:
0: layer0, name "layer0"
1: layer1, name "layer1"
2: layer2
after this forEach there will remain
0: layer1, name "layer1"
1: layer2
because after removal layer0, there is layer1 on the index 0 and AFTER that forEach moves along (to index 1), where it already finds layer without name.
To solve that, just use functions getArray() and slice() (to duplicate the reference array), something like that:

Layer switching in OpenLayers 3

I have an issue in where I need to change the map layer ( the displayed map tiles) in my web application.
I have this in my HTML
<div id="map"></div>
<select onchange="changeMap()">
<option value="BingSat">Bing Sat</option>
<option value="BingRoad">Bing Road</option>
<option value="OSM">OSM</option>
<option value="MapquestSat">Mapquest Sat</option>
<option value="MapQuestRoad">MapQuest Road</option>
</select>
and this is what I have in my JavaScript so far
$(document).ready(function() {
map = new ol.Map({
logo:'false',
target: 'map',
layers: [
new ol.layer.Group({
'title': 'Base maps',
layers: [
new ol.layer.Tile({
title: 'Water color',
type: 'base',
visible: false,
source: new ol.source.Stamen({
layer: 'watercolor'
})
}),
new ol.layer.Tile({
title: 'OSM',
type: 'base',
visible: true,
source: new ol.source.OSM()
}),
new ol.layer.Tile({
title: 'MapQuest Satellite',
type: 'base',
visible: false,
source: new ol.source.MapQuest({layer: 'sat'})
}),
new ol.layer.Tile({
title: 'MapQuest OSM',
type: 'base',
visible: false,
source: new ol.source.MapQuest({layer: 'osm'})
}),
new ol.layer.Tile({
title: 'Bing Maps aerial',
type: 'base',
visible: false,
source: new ol.source.BingMaps({
imagerySet: 'AerialWithLabels',
key: '123'
})
}),
new ol.layer.Tile({
title: 'Bing Maps road',
type: 'base',
visible: false,
source: new ol.source.BingMaps({
imagerySet: 'Road',
key: '123'
})
})
]
}),
],
view: new ol.View({
center: ol.proj.transform([17.813988, 43.342019], 'EPSG:4326', 'EPSG:3857'),
zoom: 3
})
});
}
function changeMap() {
//grab the selected ID
//change the map according to the selected ID
}
What would I need to do in order to change the displayed map? I have looked into https://github.com/walkermatt/ol3-layerswitcherdescription]1 but I cannot incorporate it entirely into my project because I need the dropdown list inside a toggable sidebar. I tried editing his code so it would add the generated HTML inside my sidebar but it did not work.
Is there a simpler way of changing the displayed map?
You need different layer groups. I do it this way:
var layersOSM = new ol.layer.Group({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
]
});
var layersMQ = new ol.layer.Group({
layers: [
new ol.layer.Tile({
source: new ol.source.MapQuest({layer: 'osm'})
})
]
});
function setMapType(newType) {
if(newType == 'OSM') {
map.setLayerGroup(layersOSM);
} else if (newType == 'MAPQUEST_OSM') {
map.setLayerGroup(layersMQ);
}
}
where setMapTypeis a function that I call with the necessary string attribute when I want to change the style. mapis my ol.Map variable.
You might arrange the layer groups in an array, and access them by name as you did already with the layers instead of the if/else construct I used. But I have only 2 different layer groups.
not directly an answer, but might be helpful for you or others:
to change the layer by using the name of the visible layer use:
var group = map.getLayerGroup();
var layers = group.getLayers();
var element = layers.item(0);
var name = element.get('name');
Here a JSfiddle to see what I mean.
I'm working on something similar using Bootstrap. This isn't "simpler", but it should be along the lines of what you're looking for.
So first in the HTML, I have this within my right sidebar for the basemaps:
...
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#basemap-choice">
<i class="fa fa-list-alt"></i>
Basemaps
</a>
</h4>
</div>
<div id="basemap-choice" class="panel-collapse collapse in">
<div class="panel-body" id="basemaps">
</div>
<div id="baseopacity">
<label>Opacity</label>
<input id="baseopslider" type="text" data-slider-min="0" data-slider-max="100" data-slider-step="1" data-slider-value="100"/>
</div>
</div>
</div>
Under the div where id=basemaps is where I dynamically add my basemap radio buttons.
I declared my basemaps in a similar fashion yours with type: 'base'. Once I've completed the initializing the map and layers, I call a javascript function to add the layers to the sidebar panel and also bind a radio button change event so the basemap changes to what's selected:
function initBaseLayersList() {
// get all the map layers
var layers = map.getLayers().getArray();
// array to hold the basemap layers
var baseLayers = new Array();
// loop through the layers and save
// the ones with type = 'base'
for (var i=0; i<layers.length; i++) {
var lyrprop = layers[i].getProperties();
if(lyrprop.type =='base') {
baseLayers.push(layers[i]);
}
}
/* now that the basemap layers are separated, create appropriate HTML
for each layer's radio button which will be appended to the sidebar panel
body div */
$.each(baseLayers, function(index) {
var basecontent = '';
var lyrprop = this.getProperties();
basecontent += '<div class="input-group" id="radio-basemap-'+index+'">';
// first basemap in the list is selected, others are not
if(index==0) {
basecontent += '<span class="input-group-addon"><input type="radio" name="radio-basemap" checked="checked">'+lyrprop.title+'</span>';
}
else {
basecontent += '<span class="input-group-addon"><input type="radio" name="radio-basemap">'+lyrprop.title+'</span>';
}
basecontent += '</div>';
$('#basemaps').append($(basecontent));
});
/* lastly, bind the radio button group to the change event making the
selected basemap visible and hiding the one deselected
*/
$('#basemaps').bind( "change", function(event) {
var newbase = $('input[name=radio-basemap]:checked');
var btntext = newbase[0].nextSibling.nodeValue;
for (var i=0; i<baseLayers.length;i++) {
var lyrprop = baseLayers[i].getProperties();
if (lyrprop.title == btntext) {
baseLayers[i].setVisible(true);
var baseslider = $('#baseopslider').slider();
var baseopacity = baseslider.slider('getValue')/100;
baseLayers[i].setOpacity(baseopacity);
}
else {
baseLayers[i].setVisible(false);
}
}
});
}
As my code indicates, I also have a Bootstrap compatible slider which can adjust the basemap opacity.
If you can use what I've written, you should be able to modify it for a dropdown list in the sidebar vs using radio buttons. As I had developed a page previously using jQuery mobile with radio buttons for basemap selection, I just adapted that code for Bootstrap and OpenLayers 3. Just for info, OL3 version is 3.14.1, Bootstrap is 3.3.6, jQuery is 1.11.3.

Categories

Resources