Використання D3.js з Angular 2


78

Я успішно інтегрував Angular 2 (Alpha 44) з D3.js:

<html>
<head>
<title>Angular 2 QuickStart</title>
<script src="../node_modules/systemjs/dist/system.src.js"></script>
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<script>
  System.config({packages: {'app': {defaultExtension: 'js'}}});
  System.import('app/app');
</script>
</head>
<body>
<my-app>Loading...</my-app>
</body>
</html>

app.js:

/// <reference path="./../../typings/tsd.d.ts" />

import {Component, bootstrap, ElementRef} from 'angular2/angular2';

@Component({
  selector: 'my-app',
  template: '<h1>D3.js Integrated if background is yellow</h1>',
  providers: [ElementRef]
})
class AppComponent { 
  elementRef: ElementRef;

  constructor(elementRef: ElementRef) {
   this.elementRef = elementRef;
  }

afterViewInit(){
    console.log("afterViewInit() called");
    d3.select(this.elementRef.nativeElement).select("h1").style("background-color", "yellow");
  }
}
bootstrap(AppComponent);

Все працює нормально. Але документація Angular 2 для ElementRef говорить наступне:

Використовуйте цей API як крайній засіб, коли потрібен прямий доступ до DOM. Замість цього використовуйте шаблони та прив’язку даних, надані Angular. Ви також можете поглянути на {@link Renderer}, який надає API, який можна безпечно використовувати, навіть якщо прямий доступ до власних елементів не підтримується. Спираючись на прямий доступ до DOM, ви створюєте тісне зв’язок між вашим додатком та рівнями візуалізації, що унеможливить розділення двох та розгортання вашого додатка у веб-службі.

Тепер виникає питання, як інтегрувати D3.js з API Renderer?


Це в якійсь допомозі? ng-newsletter.com/posts/d3-on-angular.html

Я також намагаюся змусити D3 працювати з angular 2. У наведеному вище прикладі я бачу, що ви посилаєтесь на скрипт d3 у своєму index.html, але я не бачу, як ви отримуєте затримку змінної d3 в app.js?
user2915962

8
@ user2915962 - npm встановіть d3, переконайтеся, що після встановлення запущено і d3.d.ts створено tsd, потімimport * as d3 from 'd3/d3';
намалював Мур

У одному з коментарів тут згадується відео: stackoverflow.com/q/34704148/2050479, яке є досить цікавим
Майкл

1
@urosjarc - Це Angular 1, який має зовсім інший спосіб робити подібні речі.
надсвітлий

Відповіді:


58

Щоб використовувати Renderer, вам потрібен вихідний елемент HTML (він же nativeElement). Отже, в основному ви повинні використовувати будь-яку вашу бібліотеку, отримати вихідний елемент і передати його в Renderer.

Наприклад

// h3[0][0] contains the raw element
var h3 = d3.select(this.el.nativeElement).select('h3');
this.renderer.setElementStyle(h3[0][0], 'background-color', 'blue');

Попередження про ElementRef стосується його безпосереднього використання. Це означає, що це не рекомендується

elementRef.nativeElement.style.backgroundColor = 'blue';

Але це нормально

renderer.setElementStyle(elementRef.nativeElement, 'background-color', 'blue');

Для показу цілей ви можете використовувати його також з jQuery

// h2[0] contains the raw element
var h2 = jQuery(this.el.nativeElement).find('h2');
this.renderer.setElementStyle(h2[0], 'background-color', 'blue');

Однак я рекомендую дотримуватися того, що надає angular2, щоб зробити це легко, не залежачи від інших бібліотек.

З чистою angular2 у вас є два простих способи

  • Використовуючи директиви
// This directive would style all the H3 elements inside MyComp
@Directive({
    selector : 'h3',
    host : {
        '[style.background-color]' : "'blue'"
    }
})
class H3 {}

@Component({
    selector : 'my-comp',
    template : '<h3>some text</h3>',
    directives : [H3]
})
class MyComp {}
  • Використання ViewChild з локальними змінними
@Component({
    selector : 'my-comp',
    template : '<h3 #myH3>some text</h3>',
})
class MyComp {
    @ViewChild('myH3') myH3;
    ngAfterViewInit() {
        this.renderer.setElementStyle(this.myH3.nativeElement, 'background-color', 'blue');
    }
}

Ось plnkr із усіма випадками, про які я згадав у цій відповіді. Звичайно, ваші вимоги можуть відрізнятися, але намагайтеся використовувати angular2, коли тільки можете.


2
Отже, на прикладі використання плагіна для згортання bootstrap, я мав би рацію, сказавши, що jQuery(this.el.nativeElement).collapse('show');це був би цілком прийнятний спосіб створення плагіна?
garethdn

Я думаю, що підхід директиви не буде працювати для динамічно доданих h3s, чи не так? Приклад: plnkr.co/edit/U2lvYqtGvdf7kWoRg10N?p=preview
еко

6

Спробуйте це:

npm install d3@3.5.36 --save щоб встановити потрібну версію

npm install @types/d3@3.5.36 --save або вищу версію, якщо ви хочете d3 4+

а потім у вашому tsdo

import * as d3 from 'd3';

Повинна працювати нормально


використовуючи останню версію d3 (v4) і на основі прикладу швидкого запуску angular 2 мені довелося також додати 'd3':'npm:d3'до map та 'd3': {main:'build/d3.js', defaultExtension:'js'}пакунки у systemjs.config.jsфайлі.
Нікос Цокос

Привіт @Entrodus, ти не заперечуєш дати точну послідовність встановлення на основі Quickstart? Я намагався слідувати цьому, включаючи мод системи, який ви запропонували, але я все ще застряг (ні ./build/d2.js, ні ./build також).
Стефан де Лука

@ StéphanedeLuca: 1. Налаштуйте кутовий швидкий запуск> 2. встановіть d3 та типізації для d3 версії 4.4.0> 3. додайте директиви карти та пакунки для d3 в system.config.js> 4. додайте імпорт d3 у компонент angular, який використовує d3> 5.Перемога.
Нікос Цокос

4
npm install --save d3

перевірити версію d3 в package.json і перевірити її також у node_modules.

потім у компонент.ts імпортуйте його, як показано нижче

import * as d3 from 'd3';

3

У мене були проблеми з використанням ElementRef, я не впевнений, що цей API змінився. Тож я в кінцевому підсумку скористався ViewContainRef, щоб отримати nativeElement.

import {Component, ViewContainerRef, OnInit} from '@angular/core';
declare var d3:any;
@Component({
    selector: 'line-chart',
    directives: [],
    template: `<div class="sh-chart">chart</div>`
})
export class LineChart implements OnInit{
    elem ;
    constructor(private viewContainerRef:ViewContainerRef) {}
    ngOnInit(){
        this.elem = this.viewContainerRef.element.nativeElement;

        d3.select(this.elem).select("div").style("background-color", "yellow");
    };
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.