8

After going through the below link

Using D3.js with Angular 2

I understood that we should not be manipulating DOM directly. So I started exploring to use Renderer2 of angular 4.

So I started to write some code to add svg to DOM. Below are the snippets of my code.

HTML code

<div class="row">
 <div class="col-12">
   <div #myBarGraph id="host"></div>
 </div>
</div>

Component.ts

export class BarGraphComponent implements OnInit {
 host:any;
 svg:any;
 @ViewChild('myBarGraph') myBarGraph:ElementRef;

 constructor(private renderer:Renderer2) { }

 ngOnInit() {
  //some logic
 }

 // called on some drop down selection
 teamSelection(){
  //some logic
   this.host = this.mybarGraph.nativeElement;
   buildSVG();
 }

 buildSVG():void {
   this.svg = this.renderer.createElement('svg');
   this.renderer.setAttribute(this.svg,'width','600');
   this.renderer.setAttribute(this.svg,'height','400');
   this.renderer.setAttribute(this.svg,'background-color','blue');
   this.renderer.appendChild(this.host,this.svg); 
 }
}

The above code is able to add the svg element to the DOM. But to my surprise, it actually not displaying the svg element!.

I did refer to the following questions

  1. Angular2 Renderer: Svg rect is rendered but not showing in page
  2. Angular2 does not render SVG in runtime

But I couldn't find the proper answer so far.

Below is a screenshot of the problem problem

As you can see above, svg is present in DOM, but it is not displayed in web page. Any help would be much appreciated.

3TW3
  • 337
  • 1
  • 3
  • 14
Srinivas Valekar
  • 1,083
  • 10
  • 19

2 Answers2

15

this.renderer.createElement('svg') creates HTML element instead of SVGElement because Angular doesn't know you wanted svg:svg.

Try using this.renderer.createElement('svg', 'svg'), where second parameter is the Namespace. Every svg element must be created in the same way, e.g:

let rect = this.renderer.createElement('rect', 'svg')
this.renderer.appendChild(svg, rect)
mvnukov
  • 306
  • 1
  • 4
0

You have correctly added an svg element with a height and width to the view. But an svg element does not have a background-color attribute. You can think of it as the canvas on top of which you layer other elements that have shape and colour.

You need to add another element to this view to see anything. Remove the background-color attribute from the svg, then, as you have added the svg element to the view, you can use d3 to add, say, a rect to the view:

d3.select(this.svg)
  .append('rect')
  .attr('x', 0)
  .attr('y', 0)
  .attr('width', 600)
  .attr('height', 400)
  .attr('fill', 'blue');

alternatively, you could just do the following:

@Component({
  selector: 'bar-chart',
  template: `
    <div class='bar-chart' #barChart></div>
  `
})
export class BarChartComponent implements OnInit {

  @ViewChild('barChart')
  public chart: ElementRef;

  public svg: any;

  private width: number = 600;
  private height: number = 400;

  ngOnInit() {
    this.svg = d3.select(this.chart.nativeElement)
      .append('svg')
      .attr('width', this.width)
      .attr('height', this.height);

    this.svg
      .append('rect')
      .attr('x', 0)
      .attr('y', 0)
      .attr('width', this.width)
      .attr('height', this.height)
      .attr('fill', 'blue');
  }
}
lemmingworks
  • 169
  • 1
  • 5
  • Thanks for your efforts for answering this question, yes, I have seen examples that SVG element has background-color style attribute. Also I forgot to mention that I did achieve displaying the SVG by the alternative method that you have posted. But if you follow my first link that I have described in the question, they are recommending to use renderer rather directly binding SVG to the DOM – Srinivas Valekar Nov 25 '17 at 19:27
  • @SrinivasValekar There are examples with svg elements with background-color styling, but I don't think it's a good practice because it's not universally implemented by browsers. – lemmingworks Nov 26 '17 at 11:19
  • @SrinivasValekar I read the links, but my argument is that at some stage you have to use d3 to interact with the DOM. I don't see any advantage of adding the initial svg element using Renderer2 and then using d3 to interact with the DOM, than using d3 to add the svg to the DOM exposed by `nativeElement`. – lemmingworks Nov 26 '17 at 11:26
  • You actually don't need d3 to interact with the DOM, you've got Angular for that. The idea is to use d3 for math and angular for rendering and interacting as intended. – mvnukov Dec 15 '17 at 16:22