Ich erstelle eine MapboxGL-Karte, die viel Interaktivität über Tasten und Schieberegler unterstützt.Führen Sie eine Sequenz nach einer anderen Sequenz mit RxJS
MapboxGL Karte Instanzen sind Stateful und haben temperament Lifecycles wegen viel async Abrufen von Fliesen und Quellen. Dies bedeutet, dass die meiste Arbeit in Event-Handlern erledigt wird. Das lässt mich denken, dass RxJS ein solider Kandidat für die Verwaltung all dieser Interaktivität ist.
Wenn Sie zum Beispiel einen Feature-Layer zu einer Karte hinzufügen möchten, geben Sie the mapbox example an, alles in einem map.on('load', handler)
zu tun. Das ist gut für statische Karten, aber es ist mühsam, imperative Event-Handler für eine Karte zu koordinieren, die über 20 Umschalt-/Schieberegler/Steuerelemente verfügt.
Was ich tun möchte, ist Sequenzen für jede einzelne Operation zu erstellen. Die grundlegendste davon ist das Laden der Karte dann das Hinzufügen der Basis-Feature-Layer nach der Karte lädt.
Also hier ist, was ich habe, ich habe RxJS für ca. 5 Stunden insgesamt, also vielleicht gibt es etwas, ich weiß einfach nicht, dass ich nicht weiß.
Snippet:
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/dark-v9',
center: [-122.78, 38.43],
zoom: 10
});
// Check every 100ms if the map is loaded, if so emit
var loaded$ = Rx.Observable
.interval(100)
.map(() => map.loaded())
.filter(x => x)
.first();
// We must wait until the map is loaded before attaching the feature layer.
var addLayer = loaded$.subscribe(
baseMapLoaded, errorHandler, addFeatureLayerAndSource
);
// Attaching the feature layer sets the map.loaded() to false
// while it fetches the tiles.
//
// When the feature layer and source are loaded,
// log 'all tiles loaded' then 'completed' to the console
//
// Why can I declare `addLayer` and `completed` like this?
// Shouldn't these both fire after the loaded$ emits the first time,
// causing an error?
var completed = loaded$.subscribe(tilesLoaded, errorHandler, completeHandler);
/* Misc Handlers */
function addFeatureLayerAndSource() {
console.log(2, 'adding feature layer and source');
map.addSource('parcel_data', {
'type': 'vector',
'tiles': ['http://localhost:5000/api/v1/tiles/{z}/{x}/{y}']
});
map.addLayer({
"id": "parcel_data",
"type": "fill",
"source": "parcel_data",
"source-layer": "parcel_data",
});
}
function baseMapLoaded() { console.log(1, 'base map loaded'); }
function tilesLoaded() { console.log(3, 'all tiles loaded'); }
function errorHandler(err) { console.log('error handling', err); }
function completeHandler() { console.log('completed'); }
EDIT: Aktualisiert das Snippet @ CalvinBeldin Hilfe zu reflektieren. Derzeit versucht herauszufinden, warum das tatsächlich funktioniert. Die Reihenfolge meiner console.logs ist richtig:
1 "base map loaded"
2 "adding feature layer and source"
3 "all tiles loaded"
completed
Danke für die Hilfe! Gemäß dem MapboxGL-Issue-Tracker ist die einzige Möglichkeit, zu wissen, wann das letzte Render-Ereignis ausgelöst wurde, zu prüfen, ob 'map.loaded() === true' aus dem Ereignis-Handler 'render' stammt. Aus diesem Grund habe ich '.last()' mit der Prädikatfunktion verwendet. Wegen dieser Clogginess hoffe ich, einen einfachen Weg zu finden, das letzte der gefeuerten Render-Events zu abonnieren, damit ich es an mehreren Stellen wiederverwenden kann. –
Sie könnten ein Observable einrichten, das die Map nur gelegentlich abfragt, nach dem geladen wird, wenn es wahr ist, und dann emittieren. Wird die Antwort bald mit Code aktualisieren. –
Danke, das würde ich gerne sehen. –