我需要能够为 SVG 元素设置 CSS 类

Posted

技术标签:

【中文标题】我需要能够为 SVG 元素设置 CSS 类【英文标题】:I need to be able to set CSS class for SVG element 【发布时间】:2016-10-06 01:51:33 【问题描述】:

我正在创建一个包含 Angular2 指令的应用程序,该指令显示一个包含路径元素的 SVG 图像,当单击这些路径元素时,这些元素会向应用程序组件发出事件。这运作良好。但是,我还希望能够通过从指令外部的选择器更改它们的 CSS 类来突出显示元素。

作为一个简单的示例,我将http://www.petercollingridge.co.uk/sites/files/peter/Australia_compass_with_names.svg 处的 AU 地图的简化版本“包装”到一个指令中,并添加了代码以将点击事件添加到 SVG 元素,如下所示:

import Component, Renderer, ElementRef, Input, Output, EventEmitter, OnInit, OnChanges, OnDestroy from '@angular/core';

@Component(
    selector: '[map]',
    template: `
    <svg>
        <g id="map-transform" transform="matrix(1 0 0 1 0 0)">
            <path
            id="WA"
            class="territory"
            fill="#a9a9a9"
            d="m 38.3, 168.2 c -1.9,-0.6 -3.6,-1.1 -3.8,-1.3 -0.2,-0.2 0.8,-2.5 2.25,-5.2 1.4,-2.7 2.6,-5.5 2.6,-6.2 0,-0.8 -1.8,-4.25 -4,-7.7 -2.2,-3.5 -4,-7.1 -4,-8.1 l 0,-1.8 -6.4,-10.3 -6.4,-10.3 1.8,0 -7,-14.8 0.2,-7.3 c 0.1,-4 0.1,-8.9 0.1,-10.9 l -0.1,-3.5 5.5,-6 c 3,-3.3 5.5,-6.3 5.5,-6.7 0,-0.4 0.9,-0.8 1.9,-0.8 l 1.9,0 9.8,-6.1 13.8,-2.2 4.1,-2.6 8.4,-15 -1.2,-3 3.3,-5 1.8,1.1 4,-2.5 0,-3.1 4.6,-4.3 8.5,0 3.4,3.8 c 1.9,2.1 3.4,4.3 3.4,5 l 0,1.3 2.5,-0.6 L 97.5,33.2 c 0,38.3 0,77 0,113.8 l -4.6,1.6 -4.5,2.2 -2.3,5.6 -1.6,0.5 c -0.9,0.3 -4.8,1 -8.6,1.6 l -7,1.1 -8.2,4.9 -8.2,4.9 -5.3,0 c -2.9,0 -6.9,-0.5 -8.8,-1.1 z"/>

        <path
            id="QLD"
            class="territory"
            fill="#a9a9a9"
            d="m 200.3,123.9 c -11.8,-0.7 -14.8,-0.8 -22.8,-1.3 0,-8.5 0,-21 0,-21 l -16,0 c 0,0 0,-39.3 0,-60 l 6,3.5 5.2,3.5 4.4,0 6,-9.8 3.4,-24.6 2.8,-5.7 c 1.6,-3.1 3.3,-6 3.9,-6.3 l 1,-0.6 1.8,4.3 c 1,2.4 2.2,6.6 2.6,9.3 0.4,2.8 1.2,7.1 1.7,9.8 l 1,4.8 4.8,0 3.2,5 2.8,11 c 1.5,6.1 3.3,11.7 4,12.5 0.6,0.8 3.4,2.9 6.2,4.6 l 5,3.2 5,10 3.8,1 1.2,5.2 11.2,14.8 1.2,7.1 c 0.7,3.9 1.5,8.7 1.9,10.8 l 0.6,3.7 -1.3,5.1 -4.6,-1.1 -1.3,1.6 c -1.6,2 -3.7,2 -4.4,0.1 l -0.6,-1.5 -2.4,0 c -1.3,0 -4.3,0.7 -6.7,1.5 -2.3,0.8 -5.4,1.4 -6.9,1.3 -1.4,-0.1 -12.3,-0.7 -24.1,-1.4 z"/>    

        <path
            id="VIC"
            class="territory"
            fill="#a9a9a9"
            d="m 219.5,177.3 0.8,1 c 0,0.6 2.3,2.7 5,4.8 l 5,3.8 -11.4,3.4 -5.7,5.4 -6.9,-3.7 -2.8,1.4 c -1.5,0.8 -3,1.5 -3.3,1.6 -0.3,0.1 -2.3,-0.9 -4.5,-2.2 c -2.2,-1.3 -6.3,-3.1 -9,-4 l -5,-1.6 -2.3,-2 -2.1,-2.1 c 0,-9 0,-17.9 0,-26.6 l 3.9,-1.3 3.1,0 1.6,3.4 1.9,0.5 2.4,0.5 1.5,0.9 4.7,6 3.2,3.9 c 3.2,0.9 6.5,1.7 9.2,2.4 3,0.8 4.7,0.9 6.2,1 l 2.9,2.6"/>

        <path
            id="NSW"
            class="territory"
            fill="#a9a9a9"
            d="m 220.5,176.4 -2.4,-2.7 -2.4,-1.5 c -2.1,-0.3 -6.2,-1.1 -9.1,-1.8 l -5.4,-1.4 -8.2,-10.4 -2.8,-0.7 -2.8,-0.7 -1,-1.9 -1,-1.9 -3.9,0 -4,1.5 0,-30.9 c 5.8,0.4 22.5,1.4 25.3,1.6 l 23.5,1.4 4.8,-1.2 c 4.6,-1.1 5.7,-2.1 8.3,-2 0,0 0.9,2.3 1.9,2.8 1.1,0.5 2.5,0.1 3.7,-0.3 1.1,-0.4 2,-2 3.1,-1.8 l 2.8,0.5 -1.3,5.1 c -0.7,2.7 -2.1,7.5 -2.9,10.9 -1.8,8.3 -3.1,11.6 -5.3,13.4 l -1.8,1.5 -4.1,12.5 c -2.2,6.9 -4.2,13.5 -4.4,14.7 l -0.3,2.2 -5.3,-4 -4.4,-4.2" />

        <path
            id="SA"
            class="territory"
            fill="#a9a9a9"
            d="m 176,181 -6.8,-9.4 0.7,-3.7 0.7,-3.7 -5.6,-6 -2.2,0.8 0.7,-7.8 -1.1,0 c -1.1,0 -2.2,1.1 -4.6,4.5 l -1.4,2 1,-4.8 c 0.6,-2.7 0.8,-5 0.6,-5.3 -0.8,-0.8 -6.1,2.5 -7.9,4.8 -0.9,1.2 -1.9,2 -2.1,1.8 -0.2,-0.3 -1.6,-2.6 -3.1,-5.2 l -2.7,-4.7 -11.4,-2.6 -19.2,0.2 -5.8,2.6 C 102.7,146.2 99,147.2 99,147 l 0,-44 77,0 z"/>    

        <g
            id="NT"
            class="territory"
            fill="#a9a9a9">
            <path
                d="m 99,33 3.9,0.4 c 2,0.2 4.4,-0.5 5.5,-1 l 1.9,-1 0,-2.5 0,-2.5 -2,0 0,-4 1.9,-1.7 c 1,-0.9 1.7,-2 1.5,-2.4 l -0.5,-0.7 6.8,-4.2 11.5,-1.4 0.8,-2.4 -5.6,-3 1.7,0 c 0.9,0 2,0.4 2.3,1 0.3,0.6 1.2,0.9 1.8,0.8 0.6,-0.1 3.4,0.8 6.2,2.1 l 5,2.4 7.5,0 0,3.7 -4.2,4 1.2,3.2 -3,5.8 17,11.2 0,60.8 -61,0 z" />
            <path
                d="m 115,8.7 -2.8,-0.4 0.8,-2.4 4.2,0 c 2.3,0 4.2,0.2 4.2,0.5 0,0.8 -2.3,3 -2.9,2.8 -0.3,-0 -1.8,-0.3 -3.4,-0.6 z"/>
        </g>

        <g
            id="TAS"
            class="territory"
            fill="#a9a9a9">
            <path
                d="m 202.7,223.9 -2.7,-3.6 -0.1,-3.4 c -0.1,-1.9 -0.4,-3.7 -0.8,-4.1 -0.4,-0.4 -0.7,-1.8 -0.7,-3.1 l 0,-2.3 1,0 c 0.6,0 2.4,0.7 4.2,1.6 l 3.1,1.6 9.6,-1.2 0,7.2 -3.4,5.8 -2.6,-1 -1.7,3 c -0.9,1.6 -2,3 -2.4,3 -0.4,0 -1.9,-1.6 -3.4,-3.6 z" />
        </g>

        <g 
            id="ACT"
            class="territory"
            fill="#a9a9a9">
            <path
            stroke-
            stroke="#ffffff"
            d="m 222,165.7 0.1,2.8 0.4,1.4 1,1 0.4,-0.9 0.2,2.9 2.6,1.6 1,-2.2 0,-3.6 c 0,0 -0.3,-0.5 -0.6,-1.1 0.8,-0.3 1.2,0.1 1.2,0.1 l 0.1,-3.4 1.5,-2 2.4,0.3 0.5,-1 -2.7,-1.3 c 0,0 -0.7,-1.8 -1.8,-2.4 -1.6,1.1 -4,2 -5.2,3.9 -0.4,0.7 -0.5,2.3 -0.5,2.3 z"/>
        </g>
    </g>
</svg>
`
)
export class Map implements OnInit, OnDestroy 
    @Input() public territory:string;
    @Output() territorySelected = new EventEmitter<any>();
    private element:ElementRef;
    private ctx: any;

    listenFunc: Function;   
    globalListenFunc: Function;

    constructor(elementRef: ElementRef, renderer: Renderer) 

        this.listenFunc = renderer.listen(elementRef.nativeElement, 'click', (event) => 
        this.territorySelected.emit(event);
        );
    
    ngOnInit() 
        console.log(this.ctx);
    
    removeListeners() 
        this.listenFunc();
        this.globalListenFunc();
    

    highlightTerritory(id: string)
    
        console.log('highlighting territory ' + id);
        // need to understand how to access the elements in the SVG and update the CSS class to highlight the territory
    
    public ngOnChanges(changes: [propName: string]: any)         
        if (changes['territory'])          
            this.highlightComponent(changes['territory'].currentValue);
        
    

    ngOnDestroy() 
        // Remove the listeners!
        this.listenFunc();
        this.globalListenFunc();
    

我希望能够允许用户从应用程序的另一个子组件中选择一个地区,例如包含所有地区的下拉菜单,并以与单击它相同的方式在地图中突出显示该地区在地图上会做。对输入进行编码并捕获更改非常简单。它正在查找关联的 SVG 元素并更新我正在努力解决的填充颜色。

我们将不胜感激地收到有关在 NG2 中实现这一目标的最适当方式(使用最佳实践!)的任何帮助。

【问题讨论】:

【参考方案1】:

我找到了一个简单的解决方案,那就是使用 d3.js,然后使用 select 函数。

我在 app.component.js 文件中包含了对 d3.js 的引用,然后在 map.component.ts 文件中添加了以下声明:

declare var d3:any;

最后,我将 highlightTerritory 函数更改为:

highlightTerritory(id: string) 
    console.log('highlighting ' + id);
    d3.selectAll('.territory').style('fill', '#a9a9a9');
    d3.select("#" + id).style("fill", "purple");

效果如我所愿。

【讨论】:

【参考方案2】:

你可以使用

(click)="highlightTerritory('XXX')"

[class.className]="selected == 'XXX'"

获取选定区域并更新选定区域的类别。

Plunker example

我没有从你的代码中理解你需要什么

@Output() territorySelected = new EventEmitter<any>();

您可以使用它将更改绑定到父级上的功能

<map (territorySelected)="dosSomething($event)"></map> 

但我无法从您的问题中看出这是不是故意的。如果没有,那么你不需要它(也不需要'this.territorySelected.emit(id);`)

【讨论】:

非常感谢君特。这对于在点击地图时突出显示区域当然很有效。但是,我的问题与以编程方式从应用程序中的另一个事件中突出显示区域有关(例如从下拉列表中选择区域)。抱歉,如果不清楚。 我有点麻烦,看看实际问题是什么。您只需将this.selected 设置为地区ID。在我的示例中,我在单击它时执行此操作。从哪里设置this.selected 并不重要。你到底在苦苦挣扎的部分是什么? 感谢君特的澄清。这是非常感谢的,也是我正在研究的一个更清洁的实现。再次感谢。

以上是关于我需要能够为 SVG 元素设置 CSS 类的主要内容,如果未能解决你的问题,请参考以下文章

CSS中行内元素应该如何才能够设置宽度?

使用 CSS 设置 svg <image> 元素的 xlink:href 属性

使用 Adob​​e Illustrator 设置 CSS 类属性 [关闭]

SVG 元素的 CSS 动画在 Chrome 中不起作用

在悬停另一个元素时更改 SVG 填充颜色

在 React 中用内联 svg 替换图像元素