d3.js заставляет пространство имен макета в представлении магистрали

Я работаю над приложением средней сложности, используя backbone.js для обработки данных WordPress, и я не могу понять, как заставить работать силу в макете магистрали.

в основном, я пытаюсь создать экземпляр силового макета в шаблонном макете магистрали, например:

myLayout = Backbone.Layout.extend({
    initialize: function() {
        var f = this; // i.e. the layout instance
        f.force = d3.layout.force()
            .nodes(myModels)
            .on("tick", f.tick)
            .gravity(0)
            .friction(0.9)
            .start();

        console.log(f.force);
    },
    tick: function() {
        // stuff to do when the force ticks
    }
});

Проблема в том, что сила определяется со всеми пустыми функциями, такими как gravity: function(x) { //lots of null things here }. я почти уверен, что это проблема с пространством имен, но ничего из того, что я пытаюсь сделать, не работает - я пробовал делать $(window).force, var force, $this.force...

в моем примере tick - единственная функция пространства имен, но я пытался сделать это и со всеми остальными (гравитация, трение и т. д.) безрезультатно (хотя они должны просто привязываться к силовому объекту).

у кого-нибудь есть идеи? я не могу опубликовать .jsfiddle, потому что приложение слишком сложное, поэтому заранее извините за это. Текущая версия находится здесь

изменить: вот как d3 может успешно получить доступ к моделям:

это работает:

myLayout.nodes = myLayout.d3_wrapper.selectAll(".node")
    .data(myModels)
    .enter().append("g").attr("class", "node")
    .attr("x",10)
    .attr("y",10);

    myLayout.nodes.append("clipPath")
        .attr("id", function(d) { return d.get("slug"); })

как и это: myLayout.nodes.append("clipPath") .attr("id", function(d) { return d.attributes.slug });

изменить: для ясности вот код без псевдонима:

setforce: function() { // this gets called from the layout's initialize fn
    console.log("setting force");
    var f = this; // the layout
    f.force = d3.layout.force()
        .nodes(Cartofolio.elders.models) // Cartofolio is the module, elders is a Backbone Collection
        .gravity(0)
        .friction(0.9)
        .start();

    console.log(f.force);
}

person defenestrated    schedule 16.02.2013    source источник
comment
Что содержит переменная myModels?   -  person Ben    schedule 17.02.2013
comment
это набор Backbone.Models из Backbone.Collection, в каждом из которых есть куча .attributes - они отлично вытягиваются другими методами d3, вот только .force.layout кажется финским   -  person defenestrated    schedule 17.02.2013
comment
Не могли бы вы опубликовать пример того, как другой метод d3 получает доступ к атрибутам моделей?   -  person Ben    schedule 17.02.2013
comment
сделано - отредактировал вопрос с этим внизу   -  person defenestrated    schedule 17.02.2013
comment
пс. d3_wrapper — это просто ‹svg› для хранения всего этого   -  person defenestrated    schedule 17.02.2013
comment
Спасибо. Итак, опубликованные вами примеры используют либо model.get(), либо model.attributes для доступа к атрибутам. В случае принудительного макета вы просто передаете всю коллекцию в d3. d3 не узнает, что ему нужно использовать model.get() или model.attributes для получения атрибутов ваших моделей. Простым решением может быть передача myModels.toJSON() силовому макету, но тогда вы не получите никаких событий change на своих моделях...   -  person Ben    schedule 17.02.2013
comment
ох... хм. Действительно ли силовые функции, такие как гравитация, трение и тик, зависят от доступа к атрибутам модели?   -  person defenestrated    schedule 17.02.2013
comment
Так звучит API.   -  person Ben    schedule 17.02.2013


Ответы (1)


Я бы попробовал использовать toJSON() в вашей коллекции, прежде чем передавать ее d3:

myLayout = Backbone.Layout.extend({
    initialize: function() {
        var f = this; // i.e. the layout instance
        f.force = d3.layout.force()
            .nodes(myModels.toJSON())
            .on("tick", f.tick)
            .gravity(0)
            .friction(0.9)
            .start();

        console.log(f.force);
    },
    tick: function() {
        // stuff to do when the force ticks
    }
});
person Ben    schedule 16.02.2013
comment
нет кости. Я также, возможно, был неясен - myModels был псевдонимом для прямого массива моделей внутри коллекции, поэтому я даю d3 этот массив, а не коллекцию. Итак, моя коллекция Module.thecollection, а ее модели Module.thecollection.models, что я и передаю в силу. это не позволит мне вызвать Module.thecollection.models.toJSON(), только Module.thecollection.toJSON, что на самом деле не помогает, потому что это все еще слишком много абстрагированных шагов... - person defenestrated; 17.02.2013
comment
я добавил реальный код, так что, надеюсь, это менее запутанно. Мне действительно нужно иметь возможность прослушивать изменения, поэтому вызов .toJSON не идеален (хотя я полагаю, что мог бы просто каждый раз повторно использовать JSON) - person defenestrated; 17.02.2013
comment
Хм. Использование функций get и set — это лучший из известных мне способов запуска событий change. Возможно, стоит изучить исходный код для силового макета и добавьте вызовы get и set в соответствующих местах. - person Ben; 17.02.2013
comment
может быть правдой. это будет болезненно... что заставляет меня думать, что это проблема пространства имен, так это то, что даже если я сделаю это супербуквальным, например, projects: [{//json literal list of projects}], setforce: fn() {//force setup function}, это ни черта не изменит. ›.‹ - person defenestrated; 17.02.2013