1

I'm creating a line (path) which changes color when it is clicked. In order to change color I'm adding a class. This action will also act as switching the class from one path (line) to another.

Below is my working code.

public drawLines() {
    this._containerSvg.append( 'line:defs' ).append( 'line:marker' )
        .attr( 'id', 'triangle' )
        .attr( 'refX', 6 )
        .attr( 'refY', 6 )
        .attr( 'markerWidth', 30 )
        .attr( 'markerHeight', 30 )
        .attr( 'markerUnits', 'userSpaceOnUse' )
        .attr( 'orient', 'auto' )
        .append( 'path' )
        .attr( 'd', 'M 0 0 12 6 0 12 3 6' )
        .style( 'fill', 'black' );

    this._containerSvg.selectAll( 'line' )
        .data( this._connectLines, ( line : Line ) => {
            return line.id
        } )
        .enter()
        .append( 'line' )
        .attr( 'id', ( line : Line ) => line.id )
        .attr( 'x1', ( line : Line ) => line.x1 )
        .attr( 'y1', ( line : Line ) => line.y1 )
        .attr( 'x2', ( line : Line ) => line.x2 )
        .attr( 'y2', ( line : Line ) => line.y2 )
        .style( 'stroke', 'black' )
        .style( 'stroke-width', '4px' )
        .style( 'cursor', 'pointer' )
        .attr( 'marker-end', 'url(#triangle)' )
        .on( 'click', ( line ) => {
            this._selectedLine = line;
            this.updateLines();
        } );
}

updateLines() {
    this._containerSvg.selectAll( 'line' )
        .data( this._connectLines, ( line : Line ) => {
            return line.id;
        } )
        .attr( 'x1', ( line : Line ) => line.x1 )
        .attr( 'y1', ( line : Line ) => line.y1 )
        .attr( 'x2', ( line : Line ) => line.x2 )
        .attr( 'y2', ( line : Line ) => line.y2 )
        .attr( 'class', ( line : Line ) => this._selectedLine === line ? 'selected' : '' )
}

CSS File.

svg line.selected {
   stroke: green !important;
}

Whenever the line is selected it is changing it to green but not the arrow. How can I change the color of arrow as well when the line is selected?

Thanks in advance.

Kirataka
  • 484
  • 8
  • 26
  • You cannot style marker instances that way. For an explanation have a look at my [answer](https://stackoverflow.com/a/35371604/4235784) to [*"Click event does not work on the mark-end of path in SVG"*](/q/35370613). – altocumulus Mar 05 '19 at 13:11
  • Possible duplicate of [Change color of marker-end on mouseover](https://stackoverflow.com/questions/34155956/change-color-of-marker-end-on-mouseover). Brief but spot-on. – altocumulus Mar 05 '19 at 13:13
  • Further reading: [*"Changing an SVG marker's color - CSS?"*](/q/16664584). As explained in Erik Dahlström's [answer](/a/16665510/4235784) the `` element can only inherit styles from its ancestors, not its referencing element. This, unfortunately, rules out the clever approach Sara Soueidan proposed for the `` element in her article [*Styling SVG Content with CSS*](https://tympanus.net/codrops/2015/07/16/styling-svg-use-content-css/). – altocumulus Mar 06 '19 at 11:37

1 Answers1

2

Well thanks for the tip(somewhat :D) @altocumulus.

Somehow I managed to get the results. I just made a same id's for both marker and line and I implemented the same class concept which I implemented for the line. Below is my code.

Changed little bit as my posted question.

drawLines() {
    this._containerSvg.selectAll( 'defs' )
        .data( this._connectLines, ( line : Line ) => {
            return line.id;
        } )
        .enter()
        .append( 'marker' )
        .attr( 'id', ( line : Line ) => line.id )
        .attr( 'refX', 6 )
        .attr( 'refY', 6 )
        .attr( 'markerWidth', 30 )
        .attr( 'markerHeight', 30 )
        .attr( 'markerUnits', 'userSpaceOnUse' )
        .attr( 'orient', 'auto' )
        .append( 'path' )
        .attr( 'd', 'M 0 0 12 6 0 12 3 6' );

    this._containerSvg.selectAll( 'line' )
        .data( this._connectLines, ( line : Line ) => {
            return line.id;
        } )
        .enter()
        .append( 'line' )
        .attr( 'id', ( line : Line ) => line.id )
        .attr( 'x1', ( line : Line ) => line.x1 )
        .attr( 'y1', ( line : Line ) => line.y1 )
        .attr( 'x2', ( line : Line ) => line.x2 )
        .attr( 'y2', ( line : Line ) => line.y2 )
        .attr( 'end', ( line : Line ) => line.endCircle.circlePosition )
        .attr( 'start', ( line : Line ) => line.startCircle.circlePosition )
        .attr( 'stroke-width', 4 )
        .attr( 'marker-end', ( line : Line ) => 'url(#' + line.id + ')' )
        .style( 'stroke', 'black' )
        .style( 'cursor', 'pointer' )
        .on( 'click', ( line ) => {
            this._selectedLine = line;
            this.updateLines();
            d3.selectAll( 'circle' ).remove();
        } );
}

updateLines() {
    this._containerSvg.selectAll( 'line' )
        .data( this._connectLines, ( line : Line ) => {
            return line.id;
        } )
        .attr( 'x1', ( line : Line ) => line.x1 )
        .attr( 'y1', ( line : Line ) => line.y1 )
        .attr( 'x2', ( line : Line ) => line.x2 )
        .attr( 'y2', ( line : Line ) => line.y2 )
        .attr( 'class', ( line : Line ) => this._selectedLine === line ? 'selected' : '' );

    this._containerSvg.selectAll( 'marker > path' )
        .data( this._connectLines, ( line : Line ) => {
            return line.id;
        } )
        .attr( 'class', ( line : Line ) => this._selectedLine === line ? 'selected' : '' );
}

And in CSS

svg path.selected {
   fill: green !important;
}

This will work. B)

Kirataka
  • 484
  • 8
  • 26
  • 2
    It's an error to have two occurences of the same id in your document. It may work for you in some browser but it might as well break without notice in the future or in any other browsers. Just use some suffix for the markers like `.attr( 'id', ( line : Line ) => line.id + "_marker" )`. These can then be reference as `'url(#' + line.id + '_marker)'`. – altocumulus Mar 06 '19 at 11:30