简体   繁体   中英

How can I set up Openlayers to use backbone.js?

I am trying to build an app based on Openlayers and backbone.js. Should i make each layer a view? So far i have a Map View, marker view and was thinking about making each layer a view as well. I have a markers model and map model. Can anyone help me out with setting this up?

After doing it similarly to @Gagan's answer in the past, here's how I would do it next time:

Treat the OpenLayers Map as a special rendering surface - different from the DOM, similar to how you would treat a <canvas> . Recognize that Backbone makes some (light) assumptions around the idea that your views are rendered in the DOM:

  1. There is a special relationship between Views and their corresponding DOM node ( view.el and view.$el magic).

  2. The events hash is automatically translated into handlers for events triggered on the DOM node.

We will want to recreate these concepts for our OpenLayers views. Some ideas:

  1. In Backbone, the View is the mediator between a model and a piece of the DOM. In OpenLayers, instead of a piece of the DOM, we have an OpenLayers Feature, Vector, Marker, Popup, whatever. We could recreate this special relationship between the View and its OpenLayers object. The view listening to model changes and updating the OpenLayers object comes naturally. What about listening and responding to events on the OpenLayers object?

This is one of the sticky parts of OpenLayers. Let's say you have a SelectControl . You can listen to events at the layer level, which will give you a reference to event.feature . But how do you map that feature back to your view to keep good separation of responsibilities? Pick your poison. In my examples below, I will (re)trigger the event directly on the feature, which the view already has a handle to. Then the view will have to listen to those events on the feature. Note that OL features don't have events built into them. We will mix Backbone events into them using _.extend(object, Backbone.Events); .

  1. You could create a featureEvents hash, but that might be over-engineering. Views already receive a model object and explicitly bind to its events. In my examples below, I'll do the same thing for the OL Feature that my view creates.

Now for structuring your Views. I tend to think of an OpenLayers Layer as a collection of items . Let's say you want to render a collection of features. You might create a FeatureCollectionView class that is initialized with a Map object. It would then create a Layer for its collection.

FeatureCollectionView = Backbone.View.extend({
    initialize: function(options) {
        // requires options.map, an OpenLayers Map object.
        // requires options.collection, a FeatureCollection object.
        options = options || {};

        this.map = options.map;

        this.initLayer();
        this.initSelectControl();

        this.collection.on('add', this.addFeatureModel, this);
        this.collection.on('remove', this.removeFeatureModel, this);
        this.collection.each(this.addFeatureModel, this);

        // ...
    },

    initLayer: function() {
        this.layer = new OpenLayers.Layer.Vector('a collection of features', {/* options */});
        this.map.addLayers([this.layer]);
    },

    initSelectControl: function() {
        this.selectControl = new OpenLayers.Control.SelectFeature(this.layer, {
            hover: true,
            multiple: false,
            highlightOnly: true
        });

        this.map.addControl(this.selectControl);
        this.selectControl.activate();
        this.layer.events.on({
            featurehighlighted: function(event) {
                // requires that you've extended your view features with Backbone.Events
                if (event.feature.trigger) {
                    event.feature.trigger('featurehighlighted', event);
                }
            },
            featureunhighlighted: function(event) {
                // requires that you've extended your view features with Backbone.Events
                if (event.feature.trigger) {
                    event.feature.trigger('featureunhighlighted', event);
                }
            },
            scope: this
        });
    },

    addFeatureModel: function(model) {
        if (!this.views) this.views = {};

        this.views[model.cid] = new FeatureItemView({
            layer: this.layer,
            model: model
        });
    },

    removeFeatureModel: function(model) {
        this.views && this.views[model.cid] && this.views[model.cid].remove();
    },

    // ...

});

Then we need a FeatureItemView that is initialized with an OL Layer to render itself on.

MyFeatureView = Backbone.View.extend({
    initialize: function(options) {
        // requires options.layer, an OpenLayers Layer that is already added to your map.
        options = options || {};

        this.layer = options.layer;
        this.initSelectControl();

        // ...

        this.render();

        _(this.feature).extend(Backbone.Events);
        this.feature.on('featurehighlighted', this.showPopup, this);
        this.feature.on('featureunhighlighted', this.hidePopup, this);
    },

    render: function() {
        this.feature = // ...

        this.layer.addFeatures([this.feature]);

        // ...
    },

    remove: function() {
        this.layer.removeFeatures([this.feature]);
    },

    // ...

});

I found some other interesting solutions by searching for discussions related to "backbone and canvas" since it has some similar aspects.

This gist may help you. For understanding Backbone with OpenLayers its quite useful. https://gist.github.com/bwreilly/2052314

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM