6

问题

我正在为 emberjs 制作传单视图,但遇到了一些问题。Leaflet 是一个外部库,与问题有些无关,但只知道它是一个映射库。

考虑一个简单的属性,如缩放级别。传单地图实例具有map.getZoom()可通过 访问和分配的缩放级别map.setZoom(zoomLevel)。此外,用户可以与地图交互,并更改其缩放级别。Leaflet 允许我们在缩放更改时注册回调。

我希望我的“Ember-Leaflet”视图具有zoomLevelember 属性。通过这种方式,我可以从 ember 对象模型中受益(zoomLevel例如,绑定到模板或另一个值),并且我们正在“使用 ember 方式”进行操作。

基础溶液

我目前拥有的是 Ember.View 的子类,具有 zoomLevel 属性。在didInsertElement我创建传单地图实例。代码被注释并且应该是不言自明的。

App.Leaflet = Ember.View.extend({
    classNames : ['ember-leaflet'],

    //default zoom level
    zoomLevel : 13,
    didInsertElement : function() {
        var self = this;
        var zoomLevel = this.get('zoomLevel');

        // create map instance
        var map = L.map(this.$().get(0)).setView(center, zoomLevel);

        // configure map instance...

        // Event listeners
        map.on('zoomend', function(e) {
            self.set('zoomLevel', e.target.getZoom());
        });

        // save map instance
        this.set('map', map);
    }
});

清单

为了让这个问题更“可回答”,我认为这个问题的解决方案应该满足以下要求:

  1. 更改属性时zoomLevel,地图应相应更改其缩放级别(使用map.setZoom(zoomLevel)
  2. 当用户在地图上交互改变缩放时,zoomLevel属性应该改变(可能使用传单地图的zoomend事件回调)

请注意,我们这里有一种“循环依赖”,即“更改时做某事(在地图上设置缩放) zoomLevel“当某事发生时(用户更改缩放),更改zoomLevel。我想要一个可以避免这种循环观察者依赖的解决方案。Ember 的notifyPropertyChange可能是一个解决方案。

对于Ember 的计算属性来说,这似乎是一项理想的任务,但我不知道在依赖属性字符串中放入什么。zoomLevel基本上是一个属性,它依赖于不是 ember 属性的东西。


更新

我的第一次尝试是使用观察者来设置传单上的缩放并在传单上绑定一个事件zoomend来设置zoomLevel我的视图。

问题:当我在 zoomend 传单事件上设置 zoomLevel 时,我会自动再次触发我的观察者。我说清楚了吗?

所以,这一系列事件发生了:

  1. zoomLevel在交互式地图上更改
  2. 传单火灾zoomend事件
  3. zoomend事件回调设置 emberzoomLevel
  4. 观察者跑
  5. 不必要地调用setZoom传单

这效率不高,但我不介意它是否有效。问题在于,当用户非常快速地多次更改缩放(在地图上进行简单的长滚动)时,观察者会被多次调用,从而混淆小册子

4

3 回答 3

2

好吧,我想我做到了。

我使用了计算属性和辅助属性。

App.Leaflet = Ember.View.extend({
    classNames : ['ember-leaflet'],

    //default zoom level
    zoomLevelValue : 13,
    zoomLevel : function(key, value){
        // getter
        if (arguments.length === 1) {
            var zoomLevel = this.get('zoomLevelValue');
            return zoomLevel;
        // setter  
        } else{
            var map = this.get('map');

            this.set('zoomLevelValue', value);
            map.setZoom(value);

            return value;
        }
    }.property('zoomLevelValue'),

    didInsertElement : function() {
        var self = this;
        var zoomLevel = this.get('zoomLevel');

        var map = L.map(this.$().get(0)).setView(center, zoomLevel);

        // configure map instance...

        // Event listeners
        map.on('zoomend', function(e) {
            console.log('zoomend', 'Setting zoomLevel '+e.target.getZoom());
            self.set('zoomLevelValue', e.target.getZoom());
        });

        // save map instance
        this.set('map', map);

    }
});

基本上,有两种情况:

  1. zoomLevel 以编程方式更改 -> 我们更新地图上的缩放
  2. 地图上的缩放级别被更改了->我们在辅助属性上设置了,计算机属性观察者也会得到通知,我们没有再次在地图上设置缩放级别

但是我有一个新问题,但我认为它与传单有关。当我setZoom在课程中调用另一个缩放动画时,此 setZoom 将被忽略。例如,执行:

map.setZoom(1);
map.setZoom(12);

最终以1缩放级别结束。

也许与传单相关的 SO 问题会有所帮助。

于 2013-03-27T16:19:04.627 回答
1

要从 ember 中的 zoomLevel 到 setZoom,您可以使用观察者。

要采取另一种方式,您可能必须将事件绑定到传单上的 zoomChange

于 2013-03-27T14:29:19.127 回答
1

几乎没有什么不同的策略,我将 zoomLevel 设置为一个属性并从一个函数中观察它,并且仅当属性的实际值与实际缩放不同时才在地图上设置缩放。看到这个小提琴http://jsfiddle.net/5As2z/30/ 我将逻辑传递给控制器​​,视图在插入文档时设置地图

App.ApplicationController = Ember.Controller.extend({
//default zoom level
zoomLevel: 13,
map: null,
zoomLevelChanged: function () {
    var zoomLevel = this.get('zoomLevel');
    var map = this.get('map');
    //Control not changing the zoom of the map if it is yet at the value
    if (zoomLevel != map.getZoom()) {
        map.setZoom(zoomLevel);
    }
}.observes('zoomLevel')});

App.ApplicationView = Ember.View.extend({
templateName: 'application',
didInsertElement: function () {
    var center = [41.3823000, 2.1825000];
    var controller = this.get('controller');
    var zoomLevel = controller.get('zoomLevel');
    var map = L.map('map').setView(center, zoomLevel);
    L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
        attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(map);
    // configure map instance...

    // Event listeners
    map.on('zoomend', function (e) {
        console.log('zoomend', 'Setting zoomLevel ' + e.target.getZoom());
        controller.set('zoomLevel', e.target.getZoom());
    });

    // save map instance
    this.controller.set('map', map);
}});

html

<script type="text/x-handlebars" data-template-name="application">
    <h1> Leaflet map ember example </h1>
    {{view Ember.TextField valueBinding="zoomLevel"}}
    <div id="map"></div >
</script>
于 2013-06-21T17:23:46.630 回答