Los estilos en el componente para D3.js no se muestran en angular 2

Estoy usando Angular 2 y D3.js. Quiero mostrar un rectángulo rojo.

Solo funciona si pongo estilos en el archivo style.css . Comprueba este plunkr

Cuando coloco mis estilos en los styles: [] componente styles: [] , no funciona. Comprueba este plunkr

Cómo dejarlo funcionar cuando uso los styles: [] componentes styles: [] ? Gracias

ACTUALIZACIÓN: @micronyks proporciona una solución, pero hace que los estilos del componente sean globales, básicamente no hay diferencia con la escritura en el archivo style.css . En este plunkr , muestra que el estilo en un componente anulará los estilos de otro componente, por lo que no puede mostrar los rectangularjs verde y rojo.

ACTUALIZACIÓN 2: ¡ La forma de @ Günter resuelve perfectamente este problema! Solo un recordatorio, a la manera de Günter: necesita al menos Angular beta 10. (Mis otros plunkrs usan Angular beta 8) La demo de trabajo para el rectángulo verde y uno rojo que usa Angular beta 12 está aquí .

 import {Component} from 'angular2/core' @Component({ selector: 'my-app', providers: [], styles: [` /*this does not work*/ .bar { fill: red; } `], template: ` 
`, 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()); } }

ViewEncapsulation.Emulated (predeterminado)

Eso es por diseño. Angular agrega nombres de clase únicos a los componentes y reescribe los estilos agregados para aplicarlos solo a los componentes donde fueron agregados.

D3 genera HTML dinámicamente sin conocimiento de Angulars y Angular no puede aplicar las clases para hacer que los estilos se apliquen en el HTML generado.

Si agrega los estilos en el archivo HTML de punto de entrada, Angular tampoco reescribe los estilos y las clases de ayuda agregadas no surten efecto.

ViewEncapsulation.None

Con encapsulation: ViewEncapsulation.None Angular no hace esta reescritura, por lo tanto, el resultado es similar a agregar el HTML al index.html .

“Perforación de las sombras”

Alternativamente, puede utilizar los combinadores de CSS de perforación de sombras recientemente introducidos >>> , /deep/ y ::shadow ( ::shadow es reemplazado por un y por lo tanto muy limitado). Ver también https://stackoverflow.com/a/36225709/217408 y Plunker

: host / deep / div {color: rojo; }

HABLAR CON DESCARO A

/deep/ funciona bien con SASS pero el alias >>> no.

Los combinadores de CSS shadow-piersing son reescritos por Angular y no necesitan ser compatibles con los navegadores. Chrome los apoyó por un tiempo, pero están en desuso, pero como se dijo, eso no importa, porque Angular los reescribe para usar su emulación de encapsulación.

ViewEncapsulation.Native

Angular no admite ninguna forma de diseñar dichos componentes desde el exterior. Solo si el navegador proporciona soporte, como las variables de CSS, pueden utilizarse.

ViewEncapsulation solucionará tu problema.

 import {Component,ViewEncapsulation} from 'angular2/core' @Component({ selector: 'my-app', encapsulation: ViewEncapsulation.None, providers: [], styles: [` .bar { fill: red; } `], template: ` 
`, directives: [] })

Ver encapsulación

Esto se debe a la encapsulación de la vista en Angular 2. De forma predeterminada, todo el HTML y CSS se transforman para que solo se aplique localmente. En otras palabras, si agrega este estilo en el CSS de su componente:

 h2 { color: red; } 

Solo afectará a los elementos h2 dentro del componente , no a todos los elementos h2 en toda su aplicación. Puede leer más acerca de estos mecanismos en la documentación angular en Ver encapsulación .

¿Por qué te afecta?

Angular transforma sus estilos, pero dado que el gráfico C3 aún no está dibujado, tampoco puede transformar HTML / SVG. Debido a eso, los estilos de los componentes no coincidirán con los elementos dentro del gráfico C3.

¿Que debería hacer?

Hoja de estilo externa

Las hojas de estilo externas no son transformadas por los mecanismos de Ver encapsulación, por lo que afectarán de manera efectiva su gráfico C3 (y cualquier otro elemento para el caso).

Si usa Angular CLI, agregar hojas de estilo externas es realmente simple. Edite su archivo angular-cli.json y dentro de la propiedad de las apps encuentre la matriz de styles . Agregue otra hoja de estilo aquí:

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

En caso de que no esté utilizando CLI angular, debe haber alguna manera de agregar hojas de estilo externas. Probablemente el más simple sea agregar otro dentro de en su archivo index.html .

ViewEncapsulation.None

Su primera opción es: crear un componente con el gráfico (y solo gráfico) y desactivar View Encapsulation dentro de él. Es una buena idea hacer eso también por obedecer el Principio de Responsabilidad Individual. Su gráfico, por diseño, debe estar encapsulado en un componente separado. El cambio de la encapsulación de la vista es tan simple como agregar otra propiedad a su decorador @Component :

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

/deep/ CSS selector

Si, por alguna razón, no quieres hacer eso, hay otra posibilidad. Puedes intentar usar /deep/ selector dentro de tu CSS, lo que fuerza a los estilos hacia abajo en todas las vistas de componentes secundarios. Efectivamente, esto rompe la encapsulación y debería afectar su carta C3. Entonces, por ejemplo, puedes hacer eso en el archivo CSS de tu componente:

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

De cualquier manera, recomiendo leer la documentación mencionada en Ver encapsulación en Angular 2 para comprender por qué sucede esto y cómo funciona. Se supone que esta característica te ayuda a escribir código, no a causar problemas 🙂 Este artículo puede ayudarte a entender cómo funciona: Ver la encapsulación en blog.thoughtram.io

… entonces no puedo mostrar un rectángulo rojo y otro verde … El problema vuelve

Creo que es una anulación, no sé cuánto de esto es cierto, pero creo que esto resuelve tu problema.

agregue en child1-cmp , child1-cmp .bar por ejemplo:

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

Nota: además de la encapsulation: ViewEncapsulation.None , como se menciona por micronyks .

Prueba

Plunker


o esto:

 @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: ` 
`, directives: [] })

 @Component({ //encapsulation: ViewEncapsulation.None, selector: 'child2-cmp', template: ` 
`, directives: [] })

Prueba

Plunker


o esto usando la clase .chart1 , .chart2 , por ejemplo si quieres.

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

Prueba

Plunker

puedes usar

 ::ng-deep .bar { fill: red; } 

Aquí puede leer el artículo perfecto explicando el enfoque.

Y … información de la documentación angular

Encontré que * /deep/ .my-element-class funciona, pero por alguna razón, SOLO si el elemento svg parent está presente en la plantilla html (no cuando el elemento padre svg es creado sobre la marcha por d3).

Por ejemplo, la siguiente situación funcionaría:

mycomponent.component.html

   

mycomponent.component.css

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

mycomponent.component.ts

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