Nitrof
Nitrof

Reputation: 151

change color of svg icon component with angular

Here beginner in typescript, more with css and first time playing with SVG.

I'm trying to make an heater svg icon that the four wave change color in function of the heater heating stage.

In the console log, it seem to work on the controller but I'm unable to display the color properly.

HTML:

<div>
  <svg width="20%" height="30%"  viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon">
    <g>
     <title>background</title>
     <rect x="-1" y="-1" width="1026" height="1026" id="canvas_background" fill="none"/>
    </g>

    <g>
    <title>Layer 1</title>
      <!--top line-->
      <path d="m910,782.001l-800,0c-8.837,0 -16,-7.163 -16,-16s7.163,-16 16,-16l800,0c8.837,0 16,7.163 16,16s-7.163,16 -16,16zm-800,112l800,0c8.837,0 16,7.163 16,16s-7.163,16 -16,16l-800,0c-8.837,0 -16,-7.163 -16,-16s7.163,-16 16,-16z" id="svg_5"/>

      <!--wave 1-->
      <path d="m29,844.001zm188.237,-149.935c-0.078,0.081 -0.145,0.169 -0.225,0.249c-0.048,0.048 -0.101,0.087 -0.149,0.135c-0.188,0.19 -0.37,0.384 -0.559,0.573l-0.036,-0.036c-6.289,5.554 -15.887,5.342 -21.902,-0.672c-6.014,-6.014 -6.227,-15.611 -0.672,-21.899l-0.036,-0.036c81.293,-81.282 81.293,-159.067 0,-240.35l0.708,-0.708c-93.799,-93.787 -93.799,-176.847 0,-270.634c6.253,-6.253 16.392,-6.253 22.645,0c6.253,6.252 6.253,16.39 0,22.642c-81.293,81.282 -81.293,144.067 0,225.35l-0.011,0.321l-0.696,0.386c93.484,93.472 93.787,190.818 0.933,284.679z" id="svg_1"/>
      <!--wave 2-->
      <path d="m218,843.001zm188.237,-149.935c-0.078,0.081 -0.145,0.169 -0.225,0.249c-0.048,0.048 -0.101,0.087 -0.149,0.135c-0.188,0.19 -0.37,0.384 -0.559,0.573l-0.036,-0.036c-6.289,5.554 -15.887,5.342 -21.902,-0.672c-6.014,-6.014 -6.227,-15.611 -0.672,-21.899l-0.036,-0.036c81.293,-81.282 81.293,-159.067 0,-240.35l0.708,-0.708c-93.799,-93.787 -93.799,-176.847 0,-270.634c6.253,-6.253 16.392,-6.253 22.645,0c6.253,6.252 6.253,16.39 0,22.642c-81.293,81.282 -81.293,144.067 0,225.35l-0.011,0.321l-0.696,0.386c93.484,93.472 93.787,190.818 0.933,284.679z" id="svg_2"/>
      <!--wave 3-->
      <path d="m426,843.001zm188.237,-149.935c-0.078,0.081 -0.145,0.169 -0.225,0.249c-0.048,0.048 -0.101,0.087 -0.149,0.135c-0.188,0.19 -0.37,0.384 -0.559,0.573l-0.036,-0.036c-6.289,5.554 -15.887,5.342 -21.902,-0.672c-6.014,-6.014 -6.227,-15.611 -0.672,-21.899l-0.036,-0.036c81.293,-81.282 81.293,-159.067 0,-240.35l0.708,-0.708c-93.799,-93.787 -93.799,-176.847 0,-270.634c6.253,-6.253 16.392,-6.253 22.645,0c6.253,6.252 6.253,16.39 0,22.642c-81.293,81.282 -81.293,144.067 0,225.35l-0.011,0.321l-0.696,0.386c93.484,93.472 93.787,190.818 0.933,284.679z" id="svg_3"/>
      <!--wave 4-->
      <path d="m631,843.001zm188.237,-149.935c-0.078,0.081 -0.145,0.169 -0.225,0.249c-0.048,0.048 -0.101,0.087 -0.149,0.135c-0.188,0.19 -0.37,0.384 -0.559,0.573l-0.036,-0.036c-6.289,5.554 -15.887,5.342 -21.902,-0.672c-6.014,-6.014 -6.227,-15.611 -0.672,-21.899l-0.036,-0.036c81.293,-81.282 81.293,-159.067 0,-240.35l0.708,-0.708c-93.799,-93.787 -93.799,-176.847 0,-270.634c6.253,-6.253 16.392,-6.253 22.645,0c6.253,6.252 6.253,16.39 0,22.642c-81.293,81.282 -81.293,144.067 0,225.35l-0.011,0.321l-0.696,0.386c93.484,93.472 93.787,190.818 0.933,284.679z" id="svg_4"/>        
    </g>
  </svg>
</div>

Script:

import { Component, Input, OnChanges } from '@angular/core';

@Component({
  selector: 'heater-svg',
  templateUrl: 'heater-svg.html'
})
export class HeaterSvgComponent implements OnChanges {
  @Input() stage: number = 0;

  constructor() {
  }

  ngOnChanges() {
    this.stageSet(this.stage);
  }

  stageSet(stagePercent: number) {
    let idList = ["svg_1", "svg_2", "svg_3", "svg_4" ];
    let stage: number = 0;

    if (stagePercent > 99) {
      stage = 4;
    } else if (stagePercent > 70) {
      stage = 3;
    } else if (stagePercent > 30) {
      stage = 2;
    } else if (stagePercent > 0) {
      stage = 1;
    }

    console.log(stage);  // <<<-----------------

    for (let i = 1; i < 5; i++) {
      let state = false;

      if (stage >= i) {
        state = true;
      }

      this.displayStage(idList[i-1], state);
    } 
  }

  displayStage(id: string, state: boolean) {
    let el = document.getElementById(id);

    if (el) {
      if (state) {
        console.log("fill in red");
        el.style.fill = '#ff3300';
      } else {
        el.style.fill = '#dadada';
      }
    }
  }
}

This is used in an ionic4 app, inside an ion-slide oc 10 slide:

<heater-svg [stage]="channel.percentOut"></heater-svg>

displayStage fires and console.log logs the data correctly, but el.style.fill does not work when I do not mute the else one, and even so, it only change the icon in the first slide...

Is component use some kind of instance for each use of the ccomponent or resource are some share?

Is getElementById a good way of doing it? Or is fill the better way to change the svg color? I think the data [stage] is processed correctly.

Upvotes: 0

Views: 1621

Answers (1)

Nitrof
Nitrof

Reputation: 151

As suggested by @smnbbrv, I dig into angular, but also some css and sass rules... Most of my problem was name scoping. I add to go trough getbyName instead of ById.

Also, I add to add and input to link the class instance to my data.

import { Component, Input, OnChanges } from '@angular/core';

@Component({
  selector: 'heater-svg',
  templateUrl: 'heater-svg.html',
})
export class HeaterSvgComponent implements OnChanges {

  @Input() id: number = 0;
  @Input('stage') stagePercent: number = 0;

  constructor() {
  }

  ngOnChanges() {
    let stage = this.getStageLevel(this.stagePercent);

    let els = document.getElementsByClassName('heater')[this.id];
    for (let i = 1; i <= 4; i++) {
      let state = false;      
      if (stage >= i) {
         state = true;
      }

      if (els) {
        let el = els.getElementsByClassName('wave')[i-1];//wave 0 is stage 1
        if (state) {
          this.setColor(el, '#ff3300');
        } else {
          this.setColor(el, '#dadada');
       }
      }
    } 
  }

  getStageLevel(percent: number) : number {
    let stage: number = 0;
    if (percent > 99) {
      stage = 4;
    } 
    else if (percent > 70) {
      stage = 3;
    }
    else if (percent > 30) {
      stage = 2;
    }
    else if (percent > 0) {
      stage = 1;
    } 
     return stage;
  }

  setColor(item, color) {
    item.style["fill"] = color;
  }

}

Upvotes: 1

Related Questions