TileVector - Possibility of an loadend event - openlayers-3

I try to figure out how to implement a load/error/start/end event for the requesting vector tiles to know if the layer is still requesting tiles or not (similiar to [tile events example][1]http://openlayers.org/en/v3.5.0/examples/tile-load-events.html?q=tile+events) . Right now, the only possibility to get layerstate information on a TileVector is to catch the change event, which i think respond to the render event. Please let me know if you think its possible and i can implement some kind of custom event with not too much efforts or if its nearly impossible.

Related

Prevent redundant operations in RxSwift

I'm starting my adventure with RxSwift, having small experience with React in js already. I think that my problem is common, but I'm not sure how to describe it in concise abstract way, so instead I will describe it on the example.
I'm building iOS app showing some charts. The part of interest consist of ChartAreaController, ChartInfoController, both embedded in ChartController. First controller is the area showing some graph(based on rx chartData property), and the second one among others will have a slider for user to restrict show x-value (rx selectedXRange property) which is restricted to be between some min and max. The min/max value is defined by the current chart data.
Behavior when slider change updates chart is defined in ChartController:
override func viewDidLoad() {
super.viewDidLoad()
(...)
chartInfoController.selectedXRange.asObservable()
.subscribe(onNext: { [unowned self] selectedXRange in
(...)
let chartData = self.filterChartData(from: self.rawChartData, in: selectedXRange)
self.chartAreaController.chartData.accept(chartData)
}).disposed(by: disposeBag)
The filterChartData() method just filters out data that is not in the range, but for the sake of the argument we can assume it is very costly and I don't want it to run twice when it is not necessary.
When user changes the chart he or she wants to show, the new data arrives from server (again ChartController):
private func handleNewData(_ rawChartData: ChartData) {
self.rawChartData = rawChartData
guard let allowedXRange = rawChartData.xRange() else { return }
let selectedXRange = chartInfoController.selectedXRange.value
let newSelectedXRange = calculateSelectedXRange(currentSelectedDays: selectedDaysRange, availableDaysRange: daysRange)
let chartData = filterChartData(from: rawChartData, in: selectedXRange)
self.chartInfoController.allowedXRange = allowedXRange //this line is not crucial
self.chartInfoController.selectedXRange.accept(newSelectedXRange)
self.chartAreaController.chartData.accept(rawChartData)
}
So upon new chart data arrival it may be the case that the currently selected xRange must be trimmed because of the new min/max values of the data. So the side effect of the method will be changing the selectedXRange and in turn running the subscription I pasted earlier. So when new data arrives the chartData is updated twice and I don't want it to happen.
Of course I can comment out last line of the handleNewData() method, but I don't like it very much, since main reason for existence of the handleNewData() is to set chartData, and with the line commented out it's goal would be achieved because of the side effect of the method (which is updating the slider). Not acceptable.
To chartData I added throttle anyways, because fast moving slider will result in many updates and this solves my problem partially(chartData updated only once). But as you may remember the filterChartData() method is costly, and this part will still be running twice.
So the one question is, if my general layout of tackling the problem is OK, or should it be handled way different? At this point I came to conclusion that I'm looking for some way of temporary disabling particular subscription on selectedXRange (without damaging other subscriptions to that variable). Temporary meaning:
(...)
//disable subscription
self.chartInfoController.selectedXRange.accept(newSelectedXRange)
self.chartAreaController.chartData.accept(rawChartData)
//enable subscription
(...)
This seem legit to me, since ChartController as an owner of the subscription and changer of the values may want to disable the subscription whenever it suits him(it?).
Does RxSwift support something like this? If not, then I think I can achieve it myself e.g. via bool property in ChartController, or via adding the subscription to separate disposeBag, which I would dispose and then recreate the subscription. But if it's good thing to do? For example bool solution may be prone to be ill handled when there is some error, and dispose/recreate may be somehow costly, and it may be the case that disposal was not intended to be used like that.
Is there a better practice to handle such situations? As I said I think the problem is common so I hope there is a canonical solution to it :) Thanks for any answer, sorry for the lengthy post.
So the one question is, if my general layout of tackling the problem is OK, or should it be handled way different?
A properly written UI input element observable will only fire when the user makes a change to the UI, not when the program makes a change. For example:
textField.rx.text.orEmpty.subscribe(onNext: { print($0) }) will only print a value when the user types in the textField, not when you call textField.text = "foo" or from a binding .bind(to: textfield.rx.text).
If you wrote the ChartInfoController, I suggest you modify it to work the way the other UI elements do. If you didn't write it, submit an issue to the developer/maintainer.
Does RxSwift support something like [temporarily disabling particular subscription]?
It depends on what you mean by "temporarily disabling". It doesn't support silently unsubscribing and resubscribing but there are plenty of operators that will filter out some events they receive while passing others along. For example filter, throttle, debounce, ignoreElements... There's a lot of them that do that.
Is there a better practice to handle such situations?
Then best solution is mentioned above.
When We have multiple subscriptions to the same Observable, it will re-execute for each subscription.
To stop re-execute for each subscription. RxSwift has several operators for this: share(), replay(), replayAll(), shareReplay(), publish(), and even shareReplayLatestWhileConnected().
read more at (RxSwift: share vs replay vs shareReplay)

How to handle tile request errors from ol.source.WMTS - Openlayers 3

By using the obvious event handler::
layer.getSource().on('tileloaderror', function (ev) {
console.log(ev);
});
I get an output rather useless, since it doesn't seem to contain any information regarding HTTP Response body/headers etc.
Is there a way to access those kind of information after a failed tile request?
In my implementation, access token must be updated, thus response code is necessary.
If not possible after all, maybe there is a way to create a custom tile load request (maybe implement my own "tileloadfunction" or something).

Is there an event to watch for on pushObject?

I'm programmatically pushing an object (using pushObject) into a list that is sortable. My problem becomes that if I try $(selector).sortable('refresh') or $(selector).sortable('serialize') the serialize doesn't contain the recently added dom item. I can console.log($(selector)) and it seems to know that the dom item has been added though.
My original thought is there an event to watch for once pushObject has finished? Or a callback?
Is there an event to watch for on pushObject?
Easiest way to do this is add an observer that fires when the list length has changed. But probably that's not gonna be enough in this case.
It sounds like this is a timing issue. If you try to call refresh right after pushObject (or even in an observer) the refresh code is going to run before the dom has been updated.
The trick is to make sure you are calling $(selector).sortable('refresh') after the new elements have been written to the dom. That could be from a didInsertElement hook on the dom item's view or from an observer, but as #Luke reminded me in comments best way to do it is by scheduling refresh to run after render has completed. Something like:
Em.run.schedule('afterRender', this, this.refreshSortable)

Display the attribute as a table of x3dom object

I am starting with X3DOM and trying to find a way to display the attribute data of X3DOM object stored in the database in the client side. Querying the data and getting the 3D object was not that difficult but am stuck at the moment with getting its attribute data in popup when clicking on that object. I would be really grateful if anyone could help me on this. I have tried looking for tutorial for this but could not find any. If anyone has such links that they think would be helpful, please provide the link as well. I am also searching for the relevant materials myself as well. Thanking you in advance.
One way to attach listeners to X3D objects is to set its event attribute such as the onclick attribute (or onmouseover, onmouseout ...).
You may do it in the served page from the server, or dynamically.
Let's say you have a shape:
<shape onclick=​"return window.MyComponent && typeof window.MyComponent.showData === 'function' ? MyComponent.showData(this) : true​;​​">​…​</shape>​
and a JS component:
;(function(root) {
"use strict";
root.MyComponent = {
showData: function(shape) {
/* - do your data retrieval here
- in case you have jQuery: $(shape).data()
- there you also decide what your click handler returns
to keep event propagation or not */
}
}
})(this);
A click on the shape will trigger MyComponent.showData(this) where this is the shape, and you will be able to work with this element and its attributes in your component.
X3DOM developers might have added event listener addition without having to directly deal with the attributes.

Knockout js registerEvent handler

I'm having a great time playing around with knockout js and have just started to get to grips with adding custom bindingHandlers.
I'm struggling a bit with the update function of a 3rd party jqWidget gauge - I can only get it to animate the first time I update the variable. On each update after that it just sets the value directly.
I don't fully understand ko.utils.registerEventHandler() and what it does although I've seen it in a bunch of other examples. Is this what is causing the animation to break? How do I know which events to register from the 3rd party widget?
For some reason this works fine if I add a jquery ui slider that is also bound to the observable.
You can test this here: set the value a few times to see that it animates the first time and not after that.
http://jsfiddle.net/LkqTU/4531/
When you update the input field, your observable will end up being a string. It looks like the gauge does not like to be updated with a string value, at least after the first time.
So, if you ensure that you are updating it with a number (parseInt, parseFloat, or just + depending on the situation), then it appears to update fine.
Something like:
update: function(element, valueAccessor) {
var gaugeval = parseInt(ko.utils.unwrapObservable(valueAccessor()), 10);
$(element).jqxGauge('value', gaugeval || 0);
}
http://jsfiddle.net/rniemeyer/LkqTU/4532/
You would generally only register event handlers in a scenario like this to react to changes made by a user where you would want to update your view model data. For example, if there was a way for a user to click on the gauge to change the value, then you would want to handle that event and update your view model value accordingly.
I'm answering the
I don't fully understand ko.utils.registerEventHandler() and what it does
part of your question.
registerEventHandler will register your event handler function in a cross-browser compatible way. If you are using jQuery, Knockout will use jQuery's bind function to register the event handler. Otherwise, will use the browser Web API with a consistent behavior across browsers.
You can check it out on the source code.

Resources