web-dev-qa-db-fra.com

Les styles dans le composant pour D3.js n'apparaissent pas dans angular 2

J'utilise Angular 2 et D3.js. Je veux montrer un rectangle rouge.

Cela ne fonctionne que si je mets des styles dans le fichier style.css . Vérifiez ce plunkr

Lorsque je mets mes styles dans le composantstyles: [], cela ne fonctionne pas. Vérifiez ce plunkr

Comment le laisser fonctionner lorsque j'utilise le composant styles: []? Merci

UPDATE: @micronyks fournit une solution, mais les styles du composant sont globaux. Il n'y a aucune différence avec l'écriture dans style.css fichier. Dans this plunkr , il indique que le style d'un composant remplace les styles d'un autre composant et ne peut donc pas afficher les rectangles verts et rouges.

UPDATE 2: @ La manière dont Günter a résolu parfaitement ce problème !! Un rappel, pour Günter: il a besoin d’au moins Angular beta 10. (Mes autres utilisateurs utilisent Angular beta 8) La démo de travail pour le rectangle vert et un rectangle rouge utilisant Angular beta 12 est ici .

import {Component} from 'angular2/core'
@Component({
  selector: 'my-app',
  providers: [],
   styles: [`
    /*this does not work*/
    .bar {
      fill: red;
    }
  `],
  template: `
    <div>
      <svg class="chart"></svg>
    </div>
  `,
  directives: []
})
export class App {
  constructor() {}

  ngOnInit() {
    this.draw();
  }

  draw() {
    let data = [{name: 'A', value: 1}];
    let width = 400, height = 200;

    let x = d3.scale.ordinal().rangeRoundBands([0, width]);
    let y = d3.scale.linear().range([height, 0]);

    let chart = d3.select(".chart")
      .attr("width", width)
      .attr("height", height)
      .append("g");

    x.domain(data.map(function(d) { return d.name; }));
    y.domain([0, d3.max(data, function(d) { return d.value; })]);

    chart.selectAll(".bar")
      .data(data)
      .enter().append("rect")
      .attr("class", "bar")
      .attr("x", function(d) { return x(d.name); })
      .attr("y", function(d) { return y(d.value); })
      .attr("height", function(d) { return height - y(d.value); })
      .attr("width", x.rangeBand());
  }
}
30
Hongbo Miao

ViewEncapsulation.Emulated (par défaut)

C'est par conception. Angular ajoute des noms de classe uniques aux composants et réécrit les styles ajoutés pour s’appliquer uniquement aux composants où ils ont été ajoutés. 

D3 génère du HTML de manière dynamique sans connaissance angulaire et Angular ne peut pas appliquer les classes pour que les styles s'appliquent sur le code HTML généré.

Si vous ajoutez les styles au fichier HTML du point d’entrée, Angular ne réécrit pas non plus les styles et les classes d’aide ajoutées ne prennent pas effet.

ViewEncapsulation.None

Avec encapsulation: ViewEncapsulation.None, Angular ne fait pas cette réécriture. Par conséquent, le résultat est similaire à l’ajout du code HTML au index.html.

"Perçage des ombres"

Vous pouvez également utiliser les combinateurs CSS de perforation des ombres récemment introduits >>>, /deep/ et ::shadow (::shadow est simplement remplacé par un et est donc très limité). Voir aussi https://stackoverflow.com/a/36225709/217408 et le Plunker

: Host/deep/div { La couleur rouge; }

SASS

/deep/ fonctionne bien avec SASS mais l'alias >>> ne fonctionne pas.

Les combinateurs CSS d’ombre sont réécrits par Angular et n’ont pas besoin d’être pris en charge par les navigateurs. Chrome les a prises en charge pendant un certain temps, mais elles sont déconseillées - mais comme cela a été dit, cela n'a pas d'importance, car Angular les réécrit pour utiliser son émulation d'encapsulation.

ViewEncapsulation.Native

Angular ne prend en charge aucun moyen de styler de tels composants de l'extérieur. Ce n'est que si le navigateur fournit un support similaire aux variables CSS que celles-ci peuvent être utilisées.

38
Günter Zöchbauer

ViewEncapsulation résoudra votre problème.

import {Component,ViewEncapsulation} from 'angular2/core'

@Component({
  selector: 'my-app',
  encapsulation: ViewEncapsulation.None,
  providers: [],
   styles: [`
     .bar {
       fill: red;
    }
  `],
  template: `
    <div>
      <svg class="chart"></svg>
    </div>
  `,
  directives: []
})
17
micronyks

Voir l'encapsulation

Cela est dû à l'encapsulation de la vue dans Angular 2. Par défaut, tout le code HTML et CSS est transformé de sorte qu'il ne s'applique que localement. En d'autres termes, si vous ajoutez ce style dans le CSS de votre composant:

h2 { color: red; }

Cela n'affectera que les éléments h2 du composant, et non tous les éléments h2 de l'ensemble de votre application. Vous pouvez en savoir plus sur ces mécanismes dans Documentation angulaire sur View Encapsulation .

Pourquoi cela vous concerne?

Angular transforme vos styles mais, le graphique C3 n'étant pas encore dessiné, il ne peut pas transformer HTML/SVG également. De ce fait, les styles de composant ne correspondent pas aux éléments du graphique C3.

Que devrais-je faire?

Feuille de style externe

Les mécanismes de visualisation des encapsulations ne transforment pas les feuilles de style externes, elles affecteront donc votre graphique C3 (et tout autre élément d'ailleurs).

Si vous utilisez l'interface de ligne de commande angulaire, l'ajout d'une feuille de style externe est très simple . Modifiez votre fichier angular-cli.json et à l'intérieur du apps propriété find styles tableau. Ajoutez une autre feuille de style ici:

{
    …
    "apps": [
        {
            …
            "styles": [
                "styles.scss",
                "c3.scss" // <---- add this or any other file
            ],
        }
    ],
    …
}

Si vous n'utilisez pas la CLI angulaire, il doit y avoir un moyen d'ajouter des feuilles de style externes. Le plus simple est probablement d'ajouter un autre <link …> à l'intérieur de <head> dans votre fichier index.html.

ViewEncapsulation.None

Votre première option est la suivante: Créez un composant avec le graphique (et uniquement un graphique) et désactivez Afficher l'encapsulation à l'intérieur de celui-ci. C’est une bonne idée de le faire également parce que nous respectons le principe de responsabilité unique. Votre graphique, par conception, doit être encapsulé dans un composant séparé. Activer View Encapsulation est aussi simple que d’ajouter une autre propriété à votre décorateur @Component:

@Component({
    …
    encapsulation: ViewEncapsulation.None
})

/deep/ sélecteur CSS

Si, pour une raison quelconque, vous ne voulez pas faire cela, il existe une autre possibilité. Vous pouvez essayer d'utiliser le sélecteur /deep/ à l'intérieur de votre CSS, ce qui force les styles dans toutes les vues de composants enfants. Effectivement, cela casse l'encapsulation et devrait affecter votre graphique C3. Ainsi, par exemple, vous pouvez le faire dans le fichier CSS de votre composant:

/deep/ .c3-chart-arc path {
    stroke: white;
}

Quoi qu'il en soit, je vous recommande de lire la documentation susmentionnée sur View Encapsulation in Angular 2 afin de comprendre pourquoi cela se produit et comment cela fonctionne. Cette fonctionnalité est supposée vous aider à écrire du code et non à causer des problèmes:) Cet article peut vous aider à comprendre comment cela fonctionne: Voir Encapsulation sur blog.blingtram.io

7
Michał Miszczyszyn
2
Mihail

... en savoir plus ... en savoir plus ... en anglais

Думаю, что это какое-то переопределение, ядана, насколь э.

добавьте child1-cmp, child1-cmp .bar например:

@Component({
  encapsulation: ViewEncapsulation.None,
  selector: 'child1-cmp',
   styles: [`
    child1-cmp .bar {
      fill: red;
    }
  `],
  template: `
    <div>
      <svg class="chart1"></svg>
    </div>
  `,
  directives: []
})

Remarque: il y a: encapsulation: ViewEncapsulation.None, как указано микроникс .

Тестовое задание

Plunker


или это:

@Component({
  selector: 'my-app',
  directives: [Child1Cmp, Child2Cmp],
   encapsulation: ViewEncapsulation.None,
   styles: [`
    child1-cmp .bar {
      fill: red;
    }

    child2-cmp .bar {
      fill: yellow;
    }
  `],
   ..//

@Component({
  //encapsulation: ViewEncapsulation.None,
  selector: 'child1-cmp',
  template: `
    <div>
      <svg class="chart1"></svg>
    </div>
  `,
  directives: []
})

@Component({
  //encapsulation: ViewEncapsulation.None,
  selector: 'child2-cmp',
  template: `
    <div>
      <svg class="chart2"></svg>
    </div>
  `,
  directives: []
})

Тестовое задание

Plunker


или это с использованием класса .chart1, .chart2, например, если вы хотите.

@Component({
  selector: 'my-app',
  directives: [Child1Cmp, Child2Cmp],
   encapsulation: ViewEncapsulation.None,
   styles: [`
    .chart1 .bar {
      fill: red;
    }

    .chart2 .bar {
      fill: yellow;
    }
  `],
   ..//

Тестовое задание

Plunker

1
Angel Angel

J'ai trouvé que * /deep/ .my-element-class fonctionne, mais pour une raison quelconque, UNIQUEMENT si l'élément parent svg est présent dans le modèle html (pas lorsque l'élément parent svg est créé à la volée par d3).

Par exemple, la situation suivante fonctionnerait:

mycomponent.component.html 

<svg id="mygraph"></svg> <!-- IMPORTANT!! -->

mycomponent.component.css

* /deep/ .my-element-class {
  /* ... desired styles */
}

mycomponent.component.ts

d3.select("svg#mygraph").append("circle").classed("my-element-class", true)
 ...
0
maia