I am trying to upgrade my system from Openlayers 2 to Openlayers 3 and I have having one particular issue that I cannot seem to figure out.
My application has a grid and a map and when a user clicks on the grid I want to select the relevant point on the map.
In Openlayers 2 I used the following:
self.selectControl.select(feature[0]);
I cannot find or understand how to do the same in Openlayers 3.
So to be clear, I have a feature which I have found programmatically and I want to select that feature on a map (programmatically)!
I cannot seem to find anything in the APIs but that might be due to my lack of understanding as I am new to Openlayers.
To do this you need to do the following:
mySelectControl.getFeatures().clear() -> removes the selected items
mySelectControl.getFeatures().push(featureToSelect) -> selects the applied feature
var selectInteraction = new ol.interaction.Select(});
map.addInteraction(selectInteraction);
function highlightFeature(feat){
selectInteraction.getFeatures().push(feat);
selectInteraction.dispatchEvent({
type: 'select',
selected: [feat],
deselected: []
});
}
works like a char on latest openlayers 4.5
Add a select interaction to your map.
var selectInteraction = new ol.interaction.Select();
map.addInteraction(selectInteraction);
Add any features you want to select to the select interaction's feature array.
selectInteractions.getFeatures().push(featureToSelect);
Related
I'm currently working on an application for making geologic maps. I'm using Ruby on Rails for my back end, React for my front end, and Postgres for the database. I am using React Leaflet to display the maps (abstracts Leaflet.js to React components). I am getting the maps from OpenTopoMap. This application is non-commercial and I have checked their terms of use to make sure I am not in violation.
I want users to be able to view a map and be able to add points and draw polygons on it (I already know how to do this part). Once they are done drawing on the map I want them to be able to save the map with whatever additions they have made. They should then be able to reopen it later and modify it.
The only way I have found to save the map is as a .png, which means it can't be edited when it is reopened.
Saving only the points/polygons and re-rendering them when a user reopens the map is an acceptable solution as long as the correct area of the map is shown when it is reopened, but I am not sure how I would go about storing this data. A user can have many maps, so solutions that only work for a single instance of map will not work in this case.
I am aware that what I have described here just duplicates the functionality of many other mapping applications. Once this part is figured out I plan to add extensive functionality that is specific to making geological maps. I have not described that functionality here because it is not relevant to my current question.
How can I save a map to PostgreSQL in a format that will allow it to be edited when reopened?
Instead of reinventing the wheel with some JSON column monstrosity look into PostGIS. Its an extension for Postgres that adds geospatial data types like points, lines and polygons. It also lets you write geospatial database queries like for example testing if a point is in a polygon or proximity searches.
For rails the the activerecord-postgis-adapter gem adds these database types:
:geometry -- Any geometric type
:st_point -- Point data
:line_string -- LineString data
:st_polygon -- Polygon data
:geometry_collection -- Any collection type
:multi_point -- A collection of Points
:multi_line_string -- A collection of LineStrings
:multi_polygon -- A collection of Polygons
This provides the building blocks to create models with geospatial attributes. Its not a magic wand that will let you stuff a map with doodles into Postgres and get something editable out and will require a significant effort in both research and implementation.
I use leaflet and leaflet.draw together to save the geoJSON from drawing polygons or dropping markers and save it to a field called coords in the database. There is a good example of it here: https://github.com/jeremygradisher/mapping-leaflet
It boils down to using leaflet.draw to draw the coordinates and then saving that data where you need it. Here is leaflet.draw: http://leaflet.github.io/Leaflet.draw/docs/leaflet-draw-latest.html
Here I am using leaflet.draw to draw on the map and then I stringify the data and add it to a field to be saved in the database.
<script>
// Initialize the FeatureGroup to store editable layers
var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
// Initialize and alter the draw control and pass it the FeatureGroup of editable layers
var drawControl = new L.Control.Draw({
draw: {
//These options make up the root object that is used when initializing the Leaflet.draw control.
position: 'topleft',
polygon: {
allowIntersection: false,
drawError: {color: '#00dd00', timeout: 1000
},
shapeOptions: {color: '#00dd00', weight: 1}, showArea: true},
polyline: false,
rectangle: {shapeOptions: {color: '#00dd00',weight: 1}},circle: false},
edit: {featureGroup: drawnItems}
});
map.addControl(drawControl);
//draw:created - Triggered when a new vector or marker has been created.
map.on('draw:created', function (e) {
var type = e.layerType,
layer = e.layer;
var shape = layer.toGeoJSON();
var shape_for_db = JSON.stringify(shape);
drawnItems.addLayer(layer);
//trying some things here
//enter in field to save to the database
document.getElementById('area_coords').value = shape_for_db;
});
As far as I understand you want to save complicated objects to the database. An user can draw lines on the map and can draw polygons and etc. Maybe using jsonb object for this problem can be your solution. Basically it's saving a JSON formatted field to database.
An example jsonb object can be like this.
{
"data": {
"type": "user_map",
"attributes": {
"user_id": "1",
"drawings": {
"points": [],
"lines": {},
"polygons": {}
}
}
}
}
You can both keep these information on user or on separate model with using has_many :maps on user model.
Links that can help you:
Example 1
Example 2
I would suggest not to think in terms of map (the rendering of spatial data) but in terms of data (a point/line/polygon with attributes). You would save each user data in tables, maybe have another map_config table that holds the map bounding box, name etc.
In you app, once you have authenticated the user, you give access to its map configurations (let him select the one to be shown) and associated data. You then display the map either using the raw vector data directly in Leaflet, Open Layers (or else), or you can pipe it through a geo server (Geoserver, Mapserver etc) for serving it as wms images, or wfs editable vector data. You zoom or restrict the displayed area to the one saved in the map configuration.
To be able to filter out items that should not be rendered with .Where("Visible") I need a property called umbracoNaviHide that returns true or false.
In earlier versions this was added to the Generic tab. However now you cant append to that tab anymore.
How would I accomplish hiding pages now?
Here's my foreach:
#foreach (var Area in Model.Content.Children.Where("Visible"))
{
Here's a statement about it. But I cant find any workaround.
Related Changes Summary - 7.4 beta - Option toCannot add properties to the "Generic properties" tab
Description - In the 7.4 beta it's not possible anymore to add
properties to the "Generic properties" tab. I know this has been done
because properties can be a bit hidden on that tab and usually are
better on a separate tab. But there are situations where the
properties are better on that tab.
You can add that property as a true/false datatype to any tab. However, it's important to note that umbracoNaviHide does not do anything special it is just a magic string, that, when implemented as a true/false datatype, it works with
.Where("Visible").
Personally I don't use it anymore. If I need to cause items to be visible or not then I would name the property more specifically. For example, it is often useful when implementing menus where you want some nodes to be visible but not others. I generally have a Menu tab where one of the properties is a true/false type called Show in menu with an alias of showInMenu.
In code it could be something like below (I have used TypedContentAtXPath to get the parent node of a specific doc type. Of course there are various ways of doing this)
var homeNode = Umbraco.TypedContentAtXPath("//MyHomePageDocType").First();
var menuItems = homeNode.Children.Where(item=>item.GetPropertyValue<bool>("showInMenu"));
foreach(var item in menuItems)
{
// Do your menu stuff here
}
Hope that helps
J
You can create a composition for node visibility with a checkbox to show or hide the menu item. And you can inherit this to the doc types that you do not want to show.
And then you can do
_homeNode.Children.Where(x => !x.GetPropertyValue<bool>("hideInNavigation"));
Hope this helps!
I'm using a split app layout for editing and creating new employees. Therefore I do have a button "Add employee". After submitChanges is done, I want to find this new employee in the master list and select it.
I am using an event-bus for the communication between detail-controller and master-controller.
fnAfterSubmitChangesSuccess: function(sChanel, sEvent, oData) {
var oResponseData = oData.__batchResponses[0].__changeResponses[0].data;
var sBindingPath = oModel.createKey("/EmployeeSet", {Begda: oData.Begda, Endda: oData.Endda, Pernr: oData.Pernr}).replace(/:\s*/g, "%3A");
},
Is there a way to find the index of a specific listitem by the using binding-path. Or is there another way to solve this problem, instead of looping over the whole list a do a comparison?
I'm afraid the only way to find the index of a specific listItems by binding-path is to walk through the collection of list items. So, I'm afraid that a very plain and short answer would be "No".
It's quite easy though, code is not that lengthy, and it also shouldn't cost to much performance if you're not talking about humongous lists. You will have to walk through the list of items though. Once you have found the item with a binding to the context path you're looking for, you can select it using setSelectedItem, like so:
var list = this.getView().byId("list");
jQuery.each(list.getList(), function(idx, item) {
if (items.getBindingContext().getPath = sBindingPath) {
list.setSelectedItem(item);
}
});
Note: Do keep in mind that if you're working with OData services and are working with a so-called 'growing list', the entry you're looking for may not necessarily be in the list.
Apologies, wish I could give you a more pleasant answer.
I am trying to localize selectOptions on the Visual Force page.
Here is the .class code snippet:
List<SelectOption> options = new List<SelectOption>();
List<MyOption__c> dropDownValues = [SELECT Id, Display_Label_Name__c FROM MyOption__c];
for (MyOption__c val : dropDownValues) {
// Display_Label_Name__c field is the label from *.labels that needs to be translated
options.add(new SelectOption(val.Id, val.Display_Label_Name__c));
}
Here is the .page code snippet:
<apex:selectList value="{!myVal}">
<apex:selectOptions value="{!options}"/>
</apex:selectList>
Right now the dropdown displays the Display_Label_Name__c verbose. I am trying to see how I can display the translated version from the .labels file. Is it possible? If not, what's the work around?
Thank you for your responses!
All localisation of page text can be done with Custom Labels.
Enable the translation workbench with the languages you require.
Create labels for all the localisible text on the page.
Replace the page text with the labels.
Add a translation for each label.
Change your profile langauge to test.
But for your case you pull the select option text from a custom object. If the values of the select list are not expected to change frequently, less than once a week or so, then I would change to using custom labels.
Otherwise, you lose the value of Salesforce automatic language selection and have to implement something yourself.
I would recommend extending the custom object MyOption__c to have columns for all the supported languages. You could use an if/else block or dynamic apex to select the select option text.
Sample using Dynamic Apex
string language = ParseForSupportedLangauges(UserInfo.getLanguage()); // includes __c
list<sobject> dropDownValues = Database.query('SELECT Id, '+language+' FROM MyOption__c');
for (sobject val : dropDownValues) {
options.add(new SelectOption(val.get('Id'), val.get(language)));
}
ParseForSupportedLangauges() would be a custom method that checks for supported languages and assigns the default when necessary.
EDIT
Turns out there is a solution: Don't look for something until you need it, right?
Introduced in Spring '12 is the ability dynamicaly select the label to display suing array syntax. Also, the ability to create visualforce components from the controller was added but using the array syntax would be sufficient for your problem. This method would allow you to select the labels you want by using the query results from MyOption__c.
Using a repeat in visualforce to loop over the query results
<apex:repeat value="{!displayResultsValues}" var="labelName">
<apex:outputText value="{!$Label[labelName]}"/>
</apex:repeat>
Here is a good article to show the usage and syntax.
http://zoofinder.us/map2.html
https://www.google.com/fusiontables/DataSource?docid=1EawtHPl3kbnsXqzPPxQWPZOJeHX3i0XUOffz884
Trying to create buttons to load certain categories.
Would eventually like it to load with all Categories and have the ability to turn them on and off via buttons on the left.
My queries do not seem to be working. For testing, I was trying to load all Farms and then toggle on the Zoos (and eventually toggle back off Zoos).
var layer = new google.maps.FusionTablesLayer({
query: {
select: 'Location',
from: '3092255',
where: 'Category contains Farm',
function updateMapZoosOn() {
layer.setOption("SELECT Location FROM 3092255 WHERE Category CONTAINS Zoo");
}
Any help please?
THANKS!
CONTAINS is a string operator and your search values must be quoted e.g.
where: "Category CONTAINS 'Farm'",
Plus your layer.setOptions() syntax is incorrect. You need the same type of {query: ....} options as you used when creating your layer
The GMap FT Query Reference explains this.