openlayers get layer from feature - vector

I have a select interaction - to select features associated with a vector layer. My goal is to edit the feature attributes and save back to a database.
import Map from 'ol/Map';
import View from 'ol/View';
import Select from 'ol/interaction/Select.js';
...
this.map = new Map({
target: 'map',
view: new View({
center: this.$root.mapState.center,
zoom: this.$root.mapState.zoom
})
});
AddLayers(this.map, this.$root.map.layers, this.$root.register);
this.select = new Select();
this.map.addInteraction(this.select);
this.select.on('select', function(e) {
e.target.getFeatures().forEach(function(feature) {
alert('Selected ' + feature.getId());
});
});
How do I get the layer from the feature?
The answer to this question from 2015 would appear to work.
Do I really have to go through all this? In OpenLayers 2, I would refer to feature.layer - this functionality appears to have gone.

Thanks to #Mike, I added me.select.getLayer(feature) in the loop over the features.
Full solution is:
import Map from 'ol/Map';
import View from 'ol/View';
import Select from 'ol/interaction/Select.js';
...
this.map = new Map({
target: 'map',
view: new View({
center: this.$root.mapState.center,
zoom: this.$root.mapState.zoom
})
});
AddLayers(this.map, this.$root.map.layers, this.$root.register);
this.select = new Select();
this.map.addInteraction(this.select);
var me = this;
this.select.on('select', function(e) {
e.target.getFeatures().forEach(function(feature) {
var layer = me.select.getLayer(feature);
alert('Selected ' + feature.getId());
});
});

Related

dagre-d3 svg labels not rendering in Meteor

I'm somehow unable to apply the SVG label example here: http://cpettitt.github.io/project/dagre-d3/latest/demo/svg-labels.html into Meteor.
The svg_edge_label gets created, but somehow won't appear on the edge! Any idea what's unique about Meteor that doesn't allow this to render? (My Meteor app is using the perak:dagre-d3 package)
main.html:
<head></head>
<body></body>
main.js:
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import './main.html';
var g = new dagreD3.graphlib.Graph()
.setGraph({})
.setDefaultEdgeLabel(function () { return {}; });
svg_edge_label = document.createElementNS('http://www.w3.org/2000/svg', 'text');
edge_tspan = document.createElementNS('http://www.w3.org/2000/svg','tspan');
edge_tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
edge_tspan.setAttribute('dy', '1em');
edge_tspan.setAttribute('x', '1');
edge_link = document.createElementNS('http://www.w3.org/2000/svg', 'a');
edge_link.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'http://google.com/');
edge_link.setAttribute('target', '_blank');
edge_link.textContent = 'IE Capable Edge link';
edge_tspan.appendChild(edge_link);
svg_edge_label.appendChild(edge_tspan);
g.setNode(0, {label: "A"});
g.setNode(1, {label: "B"});
g.setNode(2, {label: "C"});
g.setEdge(0, 1, { labelType: "svg", label: svg_edge_label});
var render = new dagreD3.render();
var svg = d3.select("body").append("svg"),
svgGroup = svg.append("g");
render(d3.select("svg g"), g);

Reactive cursor without updating UI for added record

I am trying to make a newsfeed similar to twitter, where new records are not added to the UI (a button appears with new records count), but updates, change reactively the UI.
I have a collection called NewsItems and I a use a basic reactive cursor (NewsItems.find({})) for my feed. UI is a Blaze template with a each loop.
Subscription is done on a route level (iron router).
Any idea how to implement this kind of behavior using meteor reactivity ?
Thanks,
The trick is to have one more attribute on the NewsItem Collection Say show which is a boolean. NewsItem should have default value of show as false
The Each Loop Should display only Feeds with show == true and button should show the count of all the items with show == false
On Button click update all the elements in the Collection with show == false to show = true
this will make sure that all your feeds are shown .
As and when a new feed comes the Button count will also increase reactively .
Hope this Helps
The idea is to update the local collection (yourCollectionArticles._collection): all articles are {show: false} by default except the first data list (in order not to have a white page).
You detect first collection load using :
Meteor.subscribe("articles", {
onReady: function () {
articlesReady = true;
}
});
Then you observe new added data using
newsItems = NewsItems.find({})
newsItems.observeChanges({
addedBefore: (id, article, before)=> {
if (articlesReady) {
article.show = false;
NewsItems._collection.update({_id: id}, article);
}
else {
article.show = true;
NewsItems._collection.update({_id: id}, article);
}
}
});
Here is a working example: https://gist.github.com/mounibec/9bc90953eb9f3e04a2b3.
Finally I managed it using a session variable for the current date /time:
Template.newsFeed.onCreated(function () {
var tpl = this;
tpl.loaded = new ReactiveVar(0);
tpl.limit = new ReactiveVar(30);
Session.set('newsfeedTime', new Date());
tpl.autorun(function () {
var limit = tpl.limit.get();
var time = Session.get('newsfeedTime');
var subscription = tpl.subscribe('lazyload-newsfeed', time, limit);
var subscriptionCount = tpl.subscribe('news-count', time);
if (subscription.ready()) {
tpl.loaded.set(limit);
}
});
tpl.news = function() {
return NewsItems.find({creationTime: {$lt: Session.get('newsfeedTime')}},
{sort: {relevancy: -1 }},
{limit: tpl.loaded.get()});
},
tpl.countRecent = function() {
return Counts.get('recentCount');
},
tpl.displayCount = function() {
return Counts.get('displayCount');
}
});
Template.newsFeed.events({
'click .load-new': function (evt, tpl) {
evt.preventDefault();
var time = new Date();
var limit = tpl.limit.get();
var countNewsToAdd = tpl.countRecent();
limit += countNewsToAdd;
tpl.limit.set(limit);
Session.set('newsfeedTime', new Date());
}
});

Dragging Markers in Leaflet in Meteors realtime-environment

I want draggable markers on a Leaflet map and distribute their new locations in realtime to the clients. I use meteor. To achieve this I observe the marker-collection.
This is what I've tried so far but it crashes when I drag one marker. The selected marker disappears as it should but it won't rerender the markersGroup on the map.
var newMarker;
var markers = [];
Happening.find({}).observe({
added: function(marker) {
var myIcon;
myIcon = L.icon({
iconUrl: "icon_33997.svg"
});
newMarker = L.marker([marker.location.coordinates[1],marker.location.coordinates[0]], {
icon: myIcon,
_id: marker._id,
draggable: true
});
newMarker.on('dragend', function (e){
var newCoords = this.getLatLng();
var happeningOld = Happening.find({_id: e.target.options._id}).fetch();
return Happening.update({_id: e.target.options._id}, {
item: happeningOld[0].item,
location: {
type: 'Point',
coordinates: [newCoords.lng, newCoords.lat]
},
time: Date.now(),
owner: happeningOld[0].owner
});
});
markers[newMarker.options._id] = newMarker;
markersGroup.addLayer(newMarker);
return map.addLayer(markersGroup);
},
changed: function(marker){
map.removeLayer(markersGroup);
markersGroup.removeLayer(markers[marker._id]);
markersGroup.addLayer(markers[marker._id]);
return map.addLayer(markersGroup);
}
});
This is the crash-report:
Exception in queued task: L.DistanceGrid.prototype._sqDist#http://localhost:3000/packages/leaflet-markercluster.js?d3d9bebcb9f8a1b1711174aea16a51003ba02d10:36
L.DistanceGrid.prototype.getNearObject#http://localhost:3000/packages/leaflet-markercluster.js?d3d9bebcb9f8a1b1711174aea16a51003ba02d10:36
L.MarkerClusterGroup<._addLayer#http://localhost:3000/packages/leaflet-markercluster.js?d3d9bebcb9f8a1b1711174aea16a51003ba02d10:36
L.MarkerClusterGroup<.addLayers/l<#http://localhost:3000/packages/leaflet-markercluster.js?d3d9bebcb9f8a1b1711174aea16a51003ba02d10:36
o.Util.bind/<#http://localhost:3000/packages/leaflet.js?ad7b569067d1f68c7403ea1c89a172b4cfd68d85:37
L.MarkerClusterGroup<.addLayers#http://localhost:3000/packages/leaflet-markercluster.js?d3d9bebcb9f8a1b1711174aea16a51003ba02d10:36
L.MarkerClusterGroup<.onAdd#http://localhost:3000/packages/leaflet-markercluster.js?d3d9bebcb9f8a1b1711174aea16a51003ba02d10:36
o.Map<._layerAdd#http://localhost:3000/packages/leaflet.js?ad7b569067d1f68c7403ea1c89a172b4cfd68d85:37
o.Map<.addLayer#http://localhost:3000/packages/leaflet.js?ad7b569067d1f68c7403ea1c89a172b4cfd68d85:37
Template.map.rendered/<.changed#http://localhost:3000/where-to-go.js?1b666a1c77f7d81e0212a2c65aa72a9d570b4dac:287
LocalCollection._observeFromObserveChanges/observeChangesCallbacks.changed#http://localhost:3000/packages/minimongo.js?4ee0ab879b747ffce53b84d2eb80d456d2dcca6d:3845
LocalCollection._CachingChangeObserver/self.applyChange.changed#http://localhost:3000/packages/minimongo.js?4ee0ab879b747ffce53b84d2eb80d456d2dcca6d:3750
.observeChanges/wrapCallback/</<#http://localhost:3000/packages/minimongo.js?4ee0ab879b747ffce53b84d2eb80d456d2dcca6d:374
.runTask#http://localhost:3000/packages/meteor.js?148e9381d225ecad703f4b858769b636ff7a2537:576
.flush#http://localhost:3000/packages/meteor.js?148e9381d225ecad703f4b858769b636ff7a2537:604
.drain#http://localhost:3000/packages/meteor.js?148e9381d225ecad703f4b858769b636ff7a2537:612
LocalCollection.prototype.update#http://localhost:3000/packages/minimongo.js?4ee0ab879b747ffce53b84d2eb80d456d2dcca6d:732
#http://localhost:3000/packages/mongo-livedata.js?cf17a2975aa7445f0db2377c2af07e5efc240958:730
.apply/ret<#http://localhost:3000/packages/livedata.js?7f11e3eaafcbe13d80ab0fb510d25d9595e78de2:3818
.withValue#http://localhost:3000/packages/meteor.js?148e9381d225ecad703f4b858769b636ff7a2537:794
.apply#http://localhost:3000/packages/livedata.js?7f11e3eaafcbe13d80ab0fb510d25d9595e78de2:3810
Meteor.Collection.prototype[name]#http://localhost:3000/packages/mongo-livedata.js?cf17a2975aa7445f0db2377c2af07e5efc240958:531
Template.map.rendered/<.added/<#http://localhost:3000/where-to-go.js?1b666a1c77f7d81e0212a2c65aa72a9d570b4dac:272
o.Mixin.Events.fireEvent#http://localhost:3000/packages/leaflet.js?ad7b569067d1f68c7403ea1c89a172b4cfd68d85:37
o.Handler.MarkerDrag<._onDragEnd#http://localhost:3000/packages/leaflet.js?ad7b569067d1f68c7403ea1c89a172b4cfd68d85:40
o.Mixin.Events.fireEvent#http://localhost:3000/packages/leaflet.js?ad7b569067d1f68c7403ea1c89a172b4cfd68d85:37
o.Draggable<._onUp#http://localhost:3000/packages/leaflet.js?ad7b569067d1f68c7403ea1c89a172b4cfd68d85:39
o.DomEvent.addListener/s#http://localhost:3000/packages/leaflet.js?ad7b569067d1f68c7403ea1c89a172b4cfd68d85:39
Ok, nearly got it. The thing is that the error is created by the MarkerCluster plugin. When I exclude it, it works with the following approach:
var newMarker;
Happening.find({}).observe({
added: function(marker) {
markerInit(marker);
markers[newMarker.options._id] = newMarker;
return map.addLayer(newMarker)
},
changed: function(marker){
map.removeLayer(markers[marker._id]);
markerInit(marker);
markers[newMarker.options._id] = newMarker;
map.addLayer(markers[marker._id]);
}
});
markerInit() sets up the markers like my code before does. I'm still not sure how to get it with MarkerCluster working.

I'm doing model binding using backbone.stickit. How can I bind a prepopulated select with a model?

I have a form with a select populated with options. I want to bind it to a model using backbone.stickit but the documentation show how to populate the select on the binding configuration. I can't found an easy way to bind the model with my prepopulated select.
This is my html
<div id="main">
<form id="formulario">
<input id="test1" type="text" />
<select id="test2">
<option value="0">a</option>
<option value="1">b</option>
</select>
</form>
<div id="value-test1"></div>
<div id="value-test2"></div>
</div>
This is a working example based on the documentation, but not what I need
var Model = Backbone.Model.extend({});
var View = Backbone.View.extend({
el: $('#main'),
bindings: {
'#test1': 'test1',
'#value-test1': 'test1',
'#test2': {
observe:'test2',
selectOptions: {
collection: function() {
return [
{value: 0, label:'a'},
{value: 1, label:'b'}
];
}
}
},
'#value-test2': 'test2'
},
render: function() {
this.stickit();
}
});
var model = new Model({test1: 'test', test2: 0});
var view = new View({model: model}).render();
http://jsfiddle.net/camilosw/nDjHh/
I tried to obtain the option values from the select on the binding configuration using jquery but doesn't work
var Model = Backbone.Model.extend({});
var View = Backbone.View.extend({
el: $('#main'),
bindings: {
'#test1': 'test1',
'#value-test1': 'test1',
'#test2': {
observe:'test2',
selectOptions: {
collection: function() {
options = $("#test2 option").map(function(){
return {value: this.value, label: this.text};
}).get();
return options;
}
}
},
'#value-test2': 'test2'
},
render: function() {
this.stickit();
}
});
var model = new Model({test1: 'test', test2: 0});
var view = new View({model: model}).render();
http://jsfiddle.net/camilosw/2EYV7/2
It worked, but I think it will be a mess on forms with many selects
window.options = $("#test2 option").map(function(){
return {value: this.value, label: this.text};
}).get();
var Model = Backbone.Model.extend({});
var View = Backbone.View.extend({
el: $('#main'),
bindings: {
'#test1': 'test1',
'#value-test1': 'test1',
'#test2': {
observe:'test2',
selectOptions: {
collection: function() {
return window.options;
}
}
},
'#value-test2': 'test2'
},
render: function() {
this.stickit();
}
});
var model = new Model({test1: 'test', test2: 0});
var view = new View({model: model}).render();
http://jsfiddle.net/camilosw/Y3aEF/1
What is the best way to bind a prepopulated select to a model?
I tried only with backbone.stickit, it's easier with another library?
Stickit actually binds values as data to select-options instead of using the value html attribute. The reasoning behind this is that in rich apps, you often want to use different types of data for option values. For example, you may want an option to represent a JavaScript Object or Array which is not an easy value to serialize to an html attribute; or you may want to assign the attribute value to the Number 2, but because of type coercion when it is saved as an attribue it will be converted to the String "2". Also, since Stickit is going to parse/own the select-options, it makes sense to let Stickit render the options instead of rendering/processing it in two places (not to mention iterating in a template is ugly).
That said, this request is common enough that I'm convinced to support pre-rendered select-options. Can you open a new issue, and I'll get something out on master within the next couple of days?
EDIT: This is being actively worked on, now.

How can I navigate into tab from normal window?

I build a simple application by using Titanium Studio.
From normal window, when I click a button it must go back to the tab view and activate the third tab but now it show the full screen window of that third tab instead. What should I do ?
This is my ApplicationTabGroup.js
function ApplicationTabGroup(Window) {
//create module instance
var self = Ti.UI.createTabGroup(),
MapWindow = require('ui/common/MapTab'),
ListWindow = require('ui/common/ListTab'),
ContactWindow = require('/ui/common/ContactTab');
//create app tabs
var win1 = new MapWindow('MapTab'),
win2 = new ListWindow('ListTab')
win3 = new ContactWindow('Contact')
//Tab1
var tab1 = Ti.UI.createTab({
//title: 'MapTab',
icon: '/images/icmapactive.png',
window: win1
});
win1.containingTab = tab1;
//Tab2
var tab2 = Ti.UI.createTab({
//title: 'ListTab',
icon: '/images/iclistactive.png',
window: win2
});
win2.containingTab = tab2;
//Tab3
var tab3 = Ti.UI.createTab({
//title: 'Contact',
icon: '/images/icmailactive.png',
window: win3
});
win3.containingTab = tab3;
self.addTab(tab1);
self.addTab(tab2);
self.addTab(tab3);
return self;
};
module.exports = ApplicationTabGroup;
And this is my button's eventListener. It is in normal window.
btInfo.addEventListener('click', function(e) {
var ContactTab = require('/ui/common/ContactTab');
new ContactTab(Window).open();
});
Many thanks !!!
Use setActiveTab function. In your eventlistener, create ApplicationTabGroup and set the contact tab to be active. You can use object or tab index as parameter.

Resources