Angular svg different instances sharing same defs

2019-08-03 00:11发布

I have an angular component, where I am changing the battery svg status fill by using the def.

    <svg #batteryIcon width="95%" height="95%" viewBox="0 0 260 399">
    <defs>
        <linearGradient #batteryLG id="batteryLG" x1="0.5" y1="1" x2="0.5" y2="0">
            <stop offset="0%" stop-opacity="1" stop-color="royalblue" />
            <stop [attr.offset]="value" stop-opacity="1" stop-color="royalblue" />
            <stop [attr.offset]="value" stop-opacity="0" stop-color="royalblue" />
            <stop offset="100%" stop-opacity="0" stop-color="royalblue" />
        </linearGradient>

    </defs>
<svg:rect id="rect" fill="url(#batteryLG)" x="-30" y="0" width=25% height="100%" ></svg:rect>
   </svg>

This works fine if i have a single instance of the component. If i have multiple components which have different values for "value", all the components show the fill of the first component.

Not sure where I made a mistake

Similar issue : Updating offsets dynamically

PS: I actually have a long path for battery icon.. Somehow Stackoverflow isn't accepting a long path. That's the reason i replaced the path with rect. If it was a rect I can change the height of it to achieve what I need :)

标签: angular svg
1条回答
不美不萌又怎样
2楼-- · 2019-08-03 00:39

The problem is that the linearGradient elements all have the same id, namely batteryLG. You could make every id unique, allowing each shape to refer to its own gradient. One way to achieve that is to define a static counter in the component class, increment it for each instance, and include its value in a batteryLinearGradientId property of the component:

export class MySvgComponent {
  @Input() value: number;
  private static counter = 0;
  batteryLinearGradientId = "batteryLinearGradient_" + MySvgComponent.counter++;
}

You can then bind that property to the id in the template, and refer to it in the URL of the rect fill attribute:

<svg #batteryIcon width="95%" height="95%" viewBox="0 0 260 399">
    <defs>
        <linearGradient [id]="batteryLinearGradientId" x1="0.5" y1="1" x2="0.5" y2="0">
            <stop offset="0%" stop-color="royalblue" />
            <stop [attr.offset]="value + '%'" stop-color="royalblue" />
            <stop [attr.offset]="value + '%'" stop-color="yellow" />
            <stop offset="100%" stop-color="yellow" />
        </linearGradient>
    </defs>
    <svg:rect [attr.fill]="'url(#' + batteryLinearGradientId + ')'" x="-30" y="0" width=25% height="100%"></svg:rect>
</svg>

See this stackblitz for a demo. Please note that I modified the definition of the gradient stops, to simplify the demo.

查看更多
登录 后发表回答