D3 в приложении AngularJS
Я пытаюсь создать свое первое приложение с помощью AngularJS. Это выглядит аккуратно, но там много абстракции, и мне просто интересно, есть ли у кого-нибудь советы по самому идиоматическому способу использования методологии angular для обновления визуальных образов, созданных с помощью d3js.
Спасибо,
п.н.
Ответы
Ответ 1
Чтобы сделать angular и другие фреймворки хорошими, нужно обернуть "другие" фреймворки с помощью директив.
http://docs.angularjs.org/guide/directive
То, что вы хотите сделать, это сообщить angular, когда данные были обновлены "другими" фреймами. Если angular не нужно знать, тогда ваша задача будет проще.
Вот пример, который работает с SVG, его удивительным
http://sullerandras.github.com/SVG-Sequence-Diagram/
Вот пример, который включает TinyMCE
http://jsfiddle.net/programmieraffe/kjsEV/
Ответ 2
Пожалуйста, также просмотрите статью Брайана Форда (интернатура AngularJS), где он подробно описывает интеграцию AngluarJS с D3.
http://briantford.com/blog/angular-d3.html
Ответ 3
Существует также возможность вставить синтаксис дескриптора AngularJS непосредственно в создаваемые d3 элементы:
var containerDiv = d3.select(targetCSSSelectorForADiv);
var svgG = containerDiv
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
svgG.selectAll(".tempclass").data(scope.circles).enter()
.append("circle")
.attr("class", "tempclass")
.attr("cx", function (d, i) { return "{{circles[" + i + "].cx}}" })
.attr("cy", function (d, i) { return "{{circles[" + i + "].cy}}" })
.attr("r", function (d, i) { return "{{circles[" + i + "].radius}}" })
.attr("ng-style", function (d, i)
{
return "{fill: circles[" + i + "].circolor"
+ ", opacity: circles[" + i + "].opa"
+ ", 'stroke-width': 4*circles[" + i + "].opa"
+ ", stroke: 'red' }";
});
Обратите внимание на следующее: область действия - это объект объекта angular, переданный из директивы в функцию рендеринга. Установка стиля элемента в выражение "{...}} не будет работать, поэтому я использую здесь атрибут" ng-style ".
Однако есть еще один трюк: вам нужно сказать angular посмотреть на динамически сгенерированные элементы DOM и связать привязку данных, теперь я знаю два способа сделать это:
//the target div is the one with the angular ng-controller attribute
//this you can call at the end of the d3 rendering call from within the render function
angular.bootstrap(document.getElementById("d3ContainerDivID"), ['d3App']);
Другой способ:
//and this could be called from the directive that triggered the rendering or
//some other place that could have the angular $compile service injected
$compile(document.getElementById("d3ContainerDivID"))(scope);
Теперь вы можете изменить свои члены области действия, и они будут напрямую обновлены до ваших элементов d3, в этом случае круги svg. В контроллере angular (который получает экземпляр перед срабатыванием директивы, который рисует объекты d3).
$scope.circles = [];
for (var i = 0; i < 50; i++)
{
$scope.circles.push(new Circle());
}
setInterval(function ()
{
$scope.circles.forEach(function (d, i) { $scope.circles[i] = new Circle(); });
$scope.$digest();
}, 2000);
Обратите внимание на вызов $digest, который сообщает angular переварить измененную область; это изменит значения для элементов круга SVG. Для чего-то вроде анимации и т.д. Теперь d3 теперь не отвечает, и нужно будет вручную или использовать другой шаблон.
Ответ 4
Вы также можете следовать этому руководству /screencast, чтобы узнать, как использовать D3 с помощью angular.
Это немного отличается, потому что в нем используется библиотека-оболочка вокруг d3, называемая rickshaw, которая предоставляет некоторые графические данные, но подход точно такой же:
http://tagtree.tv/d3-with-rickshaw-and-angular
Ответ 5
Если мы используем d3 внутри директивы для генерации элементов с другими директивами Angular (как я думаю, вы найдете это довольно общее требование), вы можете вызвать $compile
в конце фазы UPDATE процесса рендеринга с помощью метод call()
. Подобно этому (если мы создаем кучу кругов):
mySvg.selectAll("circle")
.data(scope.nodes)
.enter()
.append("circle")
.attr("someDirective")
.call(function(){
$compile(this[0].parentNode)(scope);
});