Openlayers 3: interactions on loaded vector features - javascript

When I use map Interactions as from this example, creating features collection from scratch everithing goes well:
var features = new ol.Collection();
but when I try to define map interaction on imported features:
var geojsonObject = { ...a well defined (visible) GeoJSON object ...};
var features = new ol.format.GeoJSON().readFeatures(geojsonObject)
I get the following exception:
Error: addEventListener and attachEvent are unavailable. (ol.js:34:302)
when I use features collection in modify interaction definition:
modifyInteraction = new ol.interaction.Modify({
features: features,
deleteCondition: function(event) {
return ol.events.condition.shiftKeyOnly(event) &&
ol.events.condition.singleClick(event);
}
});

Are you attaching the features to a Vector source and to a f.ex ol.layer.Vector?

this line of code
var features = new ol.format.GeoJSON().readFeatures(geojsonObject)
returns an array of features and not an ol.Collection of features.
On the other hand ol.interaction.Modify expects to get features parameter as an ol.Collection of features. I suspect this is where your error comes from.
Try to chcnge the above line of code to this
var features = new ol.Collection(new ol.format.GeoJSON().readFeatures(geojsonObject));
Note that all the above have impact to the latest version of ol3.

Related

OpenLayers I am not able to drag the custom features

Following the query here:
Openlayers can't modify drawn features
I have built some code, which allowes me to edit nodes of my drawn features:
var modifyInteraction = new ol.interaction.Modify({
features: selectInteraction.getFeatures(),
deleteCondition: function(event) {
return ol.events.condition.shiftKeyOnly(event) &&
ol.events.condition.singleClick(event);
}
});
map.addInteraction(modifyInteraction);
However I have lost the option for dragging my features, which is defined by this code:
var translateInteraction = new ol.interaction.Translate({
features: selectInteraction.getFeatures(),
});
map.addInteraction(translateInteraction);
The new ol.interaction.Translate({ has been switched off, otherwise I am not able to edit my features, but I can only drag them.
Is there any chance to make my features draggable when I can edit them like defined in the code new ol.interaction.Modify({ above?
My full JSfiddle is here:
https://jsfiddle.net/g196cqoa/
You can add a condition option to the translate interaction to only interact when ctrl key is pressed.
var modifyInteraction = new ol.interaction.Modify({
features: selectInteraction.getFeatures(),
deleteCondition: function(event) {
return ol.events.condition.shiftKeyOnly(event) &&
ol.events.condition.singleClick(event);
},
});
map.addInteraction(modifyInteraction);
const translate = new ol.interaction.Translate({
features: selectInteraction.getFeatures(),
condition: function (event) {
return ol.events.condition.platformModifierKeyOnly(event) &&
ol.events.condition.primaryAction(event);
},
});
map.addInteraction(translate);
Alternatively, if you add the translate interaction before the modify interaction it should allow you to drag polygons as long as you stay away from the edges. This won't work with lines and points. as there is no area where the geometry cannot be modified.
The order in which the interactions are added to the maps interaction collection determines whether the modify interaction is allowed see and handle the events before the translate interaction handles them

Leaflet control Joomla issue

I've created a Joomla Component and i have a Leaflet map in the component window.
I've used Leaflet with Omnivore plugin to add GPX and KML to my map and I used the Leaflet controls to allow to add and remove the layers.
I've tested the controls in a clean joomla development installation and the controls are OK, as seen in the first image
enter image description here
When I use the component in my Joomla site che controls are not OK, there are some dirty entry as seen in the second figures
enter image description here
I think this is because of the templates and some script that interfere with Leaflet but I can't fix it.
The joomla versions are the same, the template no, the joomla site use gantry.
This is the function I used to populate the map:
function showRouteTracks(tracce, baseURI, popup=false, enableLayers=true, enableElevation=false){
var layerControl = new Array();
for (var i = 0; i < tracce.length; i++) {
var customLayer = L.geoJson(null, {
style: getStyle(i)
});
if(tracce[i][3]=='GPX'){
var layer = omnivore.gpx(baseURI+tracce[i][2], null, customLayer).on('ready', function() {
elevation(enableElevation,layer);
});
if(popup){
link=''+tracce[i][5]+''
layer.bindPopup(tracce[i][0]+"➝"+tracce[i][1]+"<br/>"+link);
}
lvrtMap.addLayer(layer);
layerControl[tracce[i][0]+"➝"+tracce[i][1]]=layer;
}
if(tracce[i][3]=='KML'){
var layer = omnivore.kml(baseURI+tracce[i][2], null, customLayer).on('ready', function() {
elevation(enableElevation,layer);
});
if(popup){
link=''+tracce[i][5]+''
layer.bindPopup(tracce[i][0]+"➝"+tracce[i][1]+"<br/>"+link);
}
lvrtMap.addLayer(layer);
layerControl[tracce[i][0]+"➝"+tracce[i][1]]=layer;
}
}
if(!enableLayers)
layerControl=null;
if(enableElevation)
L.control.layers(lvrtMapLayers,layerControl,{'position':'bottomright'}).addTo(lvrtMap);
else
L.control.layers(lvrtMapLayers,layerControl).addTo(lvrtMap);
}
Currently you're creating an array to store the title/layer items:
var layerControl = new Array();
But L.Control.Layers takes object literals as baselayer/overlay parameters:
var baseLayers = {
"Mapbox": mapbox,
"OpenStreetMap": osm
};
var overlays = {
"Marker": marker,
"Roads": roadsLayer
};
L.control.layers(baseLayers, overlays).addTo(map);
So you should use an object literal:
var layerControl = {};
You can add items the same way as you did before:
layerControl['MyTitle'] = myLayerInstance;
I'll bet you'll have no problem then. What happening now is that your trying to assign string keys to items in an array, which isn't supported (even supposed to work but that aside). A javascript array can only have numeric keys and nothing else.
That it works for you with a clean install and not in your production setup is that probably in production you have a javascript library/framework loaded which adds methods/properties to javascript's native array prototype and they are enumerable. Thus when the layercontrol instance iterates the array it also finds these extra methods/properties and tries to add them to the layercontrol.
Just use a object literal: {} not an Array, you'll be fine, good luck.
EDIT: Got curious and did some digging. As it turns out this is caused by Mootools and then i ran into this question: Looping through empty javascript array returns array object functions which gives some explanation and some other solutions but it's best if you just use a object literal because at the moment you're kind of abusing Array.

Get JSON WebMap from ArcGIS JavaScript API Map object

I'm trying to get a WebMap object (as JSON) from a JavaScript Map object in the ArcGIS JavaScript API. Is there any way to do this within the API, without using ArcGIS.com? Ideally something like:
webMapAsJSON = map.toWebMap();
From the "Export Web Map Task" documentation in the REST API, there's this line that suggests it should exist:
"The ArcGIS web APIs (for JavaScript, Flex, Silverlight, etc.) allow developers to easily get this JSON string from the map."
However, I don't see anything in the Map object or elsewhere in the API that would do this.
You can't. At least not officially. The steps outlined below are not recommended. They use part of the ArcGIS JS library that is not part of the public API and therefore this behavior may not work in the next version of the API or they may back-patch a previous version of the API and this could stop working even on something that previously did work.
That said, sometimes you need some "future" functionality right now and this is actually a pretty straightforward way of getting what you want using the common proxy pattern
Use the undocumented "private" function _getPrintDefinition
var proxy_getPrintDefinition = printTask._getPrintDefinition;
printTask._getPrintDefinition = function() {
var getPrintDefResult = proxy_getPrintDefinition.apply(this, arguments);
//Now you can do what you want with getPrintDefResults
//which should contain the Web_Map_as_JSON
console.log(Json.stringify(getPrintDefResult));
//make sure you return the result or you'll break this print task.
return getPrintDefResult;
}
_getPrintDefinition takes the map as the first argument and a PrintParameters object as the second.
so you'll have to create a PrintTask, redefine the _getPrintDefinition function on the newly created print task as outlined above, create a PrintParameters and then run:
myPrintTask._getPrintDefinition(myMap,myPrintParameters);
The results of this on my little test are:
{"mapOptions":{"showAttribution":false,"extent":{"xmin":-7967955.990468411,"ymin":5162705.099750506,"xmax":-7931266.216891576,"ymax":5184470.54355468,
"spatialReference":{"wkid":102100,"latestWkid":3857}},"spatialReference":{"wkid":102100,"latestWkid":3857}},
"operationalLayers":[
{"id":"layer0","title":"layer0","opacity":1,"minScale":591657527.591555,"maxScale":70.5310735,"url":"http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"},
{"id":"XXX-Redacted-XXX","title":"serviceTitle","opacity":1,"minScale":0,"maxScale":0,"token":"XXX-Redacted-XXX","url":"http://XXX-Redacted-XXX/arcgis/rest/services/TestService/MapServer"},
{"id":"XXX-Redacted-XXX","opacity":1,"minScale":0,"maxScale":0,"featureCollection":{"layers":[]}},
{"id":"featureGraphics","opacity":1,"minScale":0,"maxScale":0,"featureCollection":{"layers":[]}},
{"id":"map_graphics","opacity":1,"minScale":0,"maxScale":0,"featureCollection":{"layers":[]}}
]}
if you don't need to do any operations on the web map json and just need the output then you don't even need to use the proxy pattern.
#Suttikeat Witchayakul's answer above should work if your goal is to print the map using a print service.
However, if you are trying to export the map to the web map JSON spec so that you can save it to ArcGIS Online/Portal, or re-instantiate a map object from it later, you may have some problems. This is because the web map specification is not the same as the export web map specification, which what the print task generates and sends to printing services.
Unfortunately, the ArcGIS API for JavaScript does not provide any methods to export a map object to web map JSON. This is supposed to be coming in version 4... at some point. Until then, you can use the all but abandoned cereal library. However, if your map uses layer types that are not fully supported by cereal, it may not work for you as is and you would have to extend it.
If you want to use "esri/tasks/PrintTask" to export your map, you must use "esri/tasks/PrintParameters" for execute the printTask. Just set your map object directly to printParameter.
require([
"esri/map", "esri/tasks/PrintTemplate", "esri/tasks/PrintParameters", ...
], function(Map, PrintTemplate, PrintParameters, ... ) {
var map = new Map( ... );
var template = new PrintTemplate();
template.exportOptions = {
width: 500,
height: 400,
dpi: 96
};
template.format = "PDF";
template.layout = "MAP_ONLY";
template.preserveScale = false;
var params = new PrintParameters();
params.map = map;
params.template = template;
printTask.execute(params, printResult);
});

Restricting pointermove interactions to two layers in openlayers 3

In openlayers version v3.6 running in Chrome on Ubuntu
I have create a map with several layers (foo, bar, beltch) in it using the syntax:
layers:[foo,bar,beltch],
I would like to limit interactions to the layers foo and bar
The api documents at http://openlayers.org/en/master/apidoc/ol.interaction.Select.html
suggest using the following syntax
var selectPointerMove = new ol.interaction.Select({
condition: ol.events.condition.pointerMove,
layers:[foo,bar]
});
But I seem to get events for all layers, I have checked the examples and nothing seem to cover this area unless I have overlooked something.
Does anybody have any suggestions
Use filter instead of layers. And make sure you set a layer property to compare later.
var layerFeatures = new ol.layer.Vector({
name: 'selectable',
source: sourceFeatures
});
var hoverInteraction = new ol.interaction.Select({
condition: ol.events.condition.pointerMove,
filter: function(feature, layer){
if(layer.get('name') === 'selectable')
return true;
}
});

add namespace to your javascript

I have worked on google map api few years ago and wrote a little reusable utility. At that time adding google map api reference does add all the api classses in your page's global namespace. As this is working sample
<script src="http://maps.google.com/maps?SOMEPARAMETERS">
<script>
var map= new GMap2(document.getElementById("map_canvas"));
var point= new LatLng(31,75);
var line= new Polyline(OPTIONS);
</script>
In v3, all Google Maps JavaScript API code is stored in the google.maps.* namespace instead of the global namespace. Most objects have also been renamed as part of this process and some more changes are done.
Now you have to write the above code as follows
<script src="APIURL">
<script>
var map= new google.map.Map(document.getElementById("map_canvas"));
var point= new google.mapLatLng(31,75);
var line= new google.map.Polyline(OPTIONS);
</script>
ISSUE
I wrote a library back in Google v2 API time and used in number of projects and was working great. But now I am working on a new project and using Google V3 API and want to reuse that old v2 library. But adding v3 library doesn't add the API classes in global namespace and my library doesn't work. Is there any way we can add namespace to our JavaScript file like we did in C# on top and it allows us to write the classes without appending the namespace
You might be able to just use references:
(function() { // A scoping function to avoid creating glboals
var GMap2 = google.map.Map;
var LatLng = google.map.LatLng;
var Polyline = googlemap.Polyline;
// ...your code using the above here...
})();
This assumes, though, that the arguments haven't changed.
Alternately, you could use the Facade pattern:
function GMap2(/*...relevant args...*/)
return new google.map.Map(/*...relevant args here, possibly modified...*/);
}
(And similar for others.)
(That works even if you use new with GMap2 because the result of the new expression will be the object you return from the constructor function if you return an object.)

Categories

Resources