Reputation: 33
I am trying to create a gauge like component in Angular using SVG to draw the shapes. I would like to center the text within a rectangle. The text will change depending on the value of the gauge, therefore, I would like to either adjust the font size such that the value fits in the rectangle. Alternatively, I could adjust the number format (e.g. scientific notation if the string is too long) such that it fits the rectangle.
The problem I am having is that when I attempt the measure the dimensions of the svg elements (both the rectangle and the text), the getBoundingClientRect()
for the native elements return zero. I am getting the native element via @ViewChild() : ElementRef
. Is there a better way to do this?
I have put together a stackblitz that shows the issue when attempting to get the dimensions of the text. It differs to my local copy in that the rectangle does return a dimension. I am using Angular 5.2.11, perhaps the difference is due to differing versions? Edit: I have updated the stackblitz: https://stackblitz.com/edit/angular-oz72py
I am adding the app.component.ts and its html template below
import { Component,OnInit, ViewChild,ElementRef } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
@ViewChild('containerRect') containerRect : ElementRef;
@ViewChild('valueText') valueText : ElementRef;
valueStr="2512323.0";
ngOnInit()
{
console.log('container bounds:',
this.containerRect.nativeElement.getBoundingClientRect().width);
console.log('text bounds:',
this.valueText.nativeElement.getBoundingClientRect().width)
}
}
The app.component.html:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120">
<svg:rect x="0" y="0" width="100%" height="100%" fill="00AA00"/>
<svg:circle cx="60" cy="60" r="60" fill="#C3002F"/>
<svg:path d="M 60 110
A 50 50 0 1 1 110 60
L 100 60
A 40 40 1 1 0 60 100
Z"
fill="#DDDDDD" fill-opacity="1"/>
<svg:path d="M 60 110
A 50 50 0 0 1 10 60
L 20 60
A 40 40 1 0 0 60 100
Z"
fill="#888888" fill-opacity="1"/>
<svg:rect #containerRect x="29.090373558749814"
y="51.717790556719336"
width="61.81925288250037"
height="16.564418886561327"
fill="#00AA00"/>
<svg:text #valueText font-size="14px"
x="50%" text-anchor="middle" dy="0.95em"
y="51.717790556719336">{{valueStr}}</svg:text>
</svg>
Upvotes: 2
Views: 2907
Reputation: 101820
The DOM is not ready when ngOnInit()
runs.
Instead, put your code in an ngAfterViewInit()
ngAfterViewInit()
{
console.log('container boundsx:',
this.containerRect.nativeElement.getBBox().width);
console.log('text bounds:',
this.valueText.nativeElement.getBBox().width)
}
I also recommend that you use getBBox()
instead of getBoundingClientRect()
. The getBBox()
method returns values in SVG units. So it should be a bit more accurate, won't be affected by any scaling, and matches exactly the sizes in the SVG file.
Upvotes: 2