Ionic 4 D3 styling scss class

Hi,

I am in the process of porting my app from ionic 3 to ionic 4. I use D3 for the creation of a meter. None of the styling is working. The entire meter is black. I am assuming it has something to do with lazy loading / shadow DOM.

The html is as follows:

<ion-header>
  <ion-toolbar>
    <ion-title>meter</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>
  <div #battery></div>
</ion-content>

This part of the code is for adding two posts to the top of the meter and where I try to add a scss class ‘battery-post’ to it:

og.selectAll('rect')
  .data([0.20, 0.80])
  .enter().append('rect')
  .attr('class', 'battery-post')
  .attr('x', function (d) {
    return rect.x + rect.width * d - config.postWidth / 2;
  })
  .attr('y', rect.y - config.postHeight)
  .attr('width', config.postWidth)
  .attr('height', config.postHeight)
  .attr('rx', config.postRx);

This is one of the scss classes for the two posts part of the meter at the top:

  .battery-post {
      fill: 'var(--ion-color-success)';
  }

And here is the result - all black. I highlighted the html for the two posts at the top where the rect has the battery-post on it which should fill the posts with -ion-color-success but it stays black:

<rect class="battery-post" x="226.3" y="2" width="25" height="8" rx="4"></rect>

Any thoughts or help on how to get the styling working would be great.

Thanks,

Brent

I did notice that if I just create one of the meter posts with the following directly in the html:

  <svg width="400" height="110">
    <rect class="battery-post" x="226.3" y="2" width="25" height="8" rx="4"></rect>
  </svg>

The content of the scss battery-post class takes affect.

The issues seems to be adding the class with D3:

.attr('class', 'battery-post')

I tried to simplify things with just trying to style the color of a box with D3 along side creating creating a box directly in html with svg:

<ion-header>
  <ion-toolbar>
    <ion-title>meter</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>

  <svg width="100%" height="100%" viewBox="0 0 900 500">
    <rect class="battery-background" x="2" y="10" width="296" height="268" stroke-width="0"></rect>
  </svg>

  <div id="meter"></div>
</ion-content>

    const svg = d3.select('#meter')
      .append('svg')
      .attr('width', '100%')
      .attr('height', '100%')
      .attr('viewBox', '0 0 900 500');


    svg.append('rect')
    .attr('class', 'battery-background')
    .attr('x', rect.x)
    .attr('y', rect.y)
    .attr('width', rect.width)
    .attr('height', rect.height)
    .attr('stroke-width', 0);

  .battery-background {
    fill: red;
  }

The box created directly in html utilizes the battery-background .scss class. The one using D3 does not.

Any thoughts on why would be greatly appreciated.

Thanks,

Brent

A thing to try:
https://teropa.info/blog/2016/12/12/graphics-in-angular-2.html#namespacing-svg-elements

<svg:rect class="battery-background" x="2" y="10" width="296" height="268" stroke-width="0"></svg:rect>

There might be all sorts of issue with Angular and templates if you do not tell Angular that these are elements of svg namespace.

So since you are adding elements using D3 (basically adding to DOM with out Angular’s attention) I think this might be what is causing the issue.

Thank you very much for the article.

I have not been able to figure out how to add the svg namespace to each element with D3. I did try replacing:

<ion-content>
  <div #battery></div>
</ion-content>

with

<ion-content>

  <svg #battery></svg>

</ion-content>

What is frustrating is that this is working with the exact same version of D3 that I am using with the ionic 3 (angular 3) version of the app and comparing with the ionic 4 app - all of the elements and .scss classes in chrome inspector match what I have in the ionic 3 project. It is just that none of the .scss classes are taken affect in the ionic 4 (angular 7 project)

02%20AM

I might have to ditch D3 and use svg directly so I can try your suggestion. I was really hoping moving from ionic 3 to ionic 4 would be a little easier than it has been.

Thanks again,

Brent

Hey man, I hear you. I am also in the process of migration and indeed its not that easy. But I think the more I learn about differences the more I like it (4) and also the more i learn about Angular and Ionic.

I think the issue that you have most likely can be resolved in not so painful manner but this requires an expert help (which I am not;/). D3 is a popular library so I am sure a thing such as adding a class should be supported with no issues.

See this article please: https://medium.com/@jeanphilippelemieux/creating-a-responsive-graph-with-angular-and-d3-b45bb8065588

The author uses ViewEncapsulation.None as a mean to avoid similar issue that you have - please try?

In the component declaration, we changed the ViewEncapsulation, since the dynamic modifications to the DOM by D3 don’t play well with the default Angular styling. Without this modification, the styles aren’t applied.

1 Like

Thank you so much for finding this!! This was the issue!!