Click table, update line, hover over line, update table

前端 未结 2 344
心在旅途
心在旅途 2021-01-16 11:50

I\'m new to D3, but loving it so far. But I know my solutions lack... elegance.

I am trying to have 2 controls, a table and a graph displaying the data represented b

相关标签:
2条回答
  • 2021-01-16 12:37

    First, the reason why your mouseover method wasn't working is because in this line:

            .on("mouseover", SelectData(i));
    

    you are calling the SelectData method at the time you call the .on() method. So when you're done initializing, your last item is selected, but there is no function listening to the mouseover event. What you want is to pass the function name to the .on() method. If you make that function take two parameters (usually named d and i), then d3 will automatically pass the index value as the second parameter. I wrote up a rather long discussion about passing functions as parameters for someone else recently, you may find it useful.

    Furthermore, you're really not taking advantage of the d3 selection structure, which can do in one call all the things you're using for-loops to do. I'd suggest taking the time to read through some tutorials on how the d3 selections work.

    Now, to your main question:

    The usual solution for selecting an element whose data matches the data of a clicked element is to give all elements a class based on a unique ID from the data. Then you can easily select all the elements associated with a given data object. If the user selects an object with d.name=Sue, and you initialized all the elements with that name as a class name, then you can do d3.select("path.Sue") and also d3.select("td.Sue") to find the correct ones.

    Your example data doesn't seem to have any unique data id value, just the index number. So you don't even need a unique class, you can just use the nth-of-type(i+1) CSS selector. (It's i+1 because the CSS counting starts at 1, while the data count starts at 0.)

    However, I would suggest that you use a special CSS class to apply all your highlighting styles. That way, it will be easy to select the currently highlighted values to remove that class, instead of having to loop through everything to test whether or not it matches. You can use CSS transitions to transition the style after a class changes.

    Here's a fiddle version of your code, tidied up to use d3 properly and with the above method for highlighting data.

    http://fiddle.jshell.net/g8z5h/

    I haven't implemented the live version of your table, but I recommend you read the tutorial on nested selections to figure out how that will work.

    I did give each data block it's own row so that the nth-of-type() selector would work properly (the CSS numbering of elements only works if they are all siblings, they can't be table data elements split across multiple rows). If you need the original layout to work, you'll have to give elements class names based on their index value, and use those to select. I also moved the click event binding into the code, because JSFiddle wraps all its code in a window load event, so the SelectData function wasn't visible outside it.

    0 讨论(0)
  • 2021-01-16 12:38

    I have been referring this since i wanted to achieve the same thing in angular2 using d3. Here is my code...

      private drawLine() {
        this.line = d3Shape.line()
            .y((d: any) => this.y(d.rank))
            .defined(function(d : any) { return d.rank})
            .x((d: any) => this.x(d.year));
    
       var color = function(i) {
            var colors = ["#35559C","#D9469C","#70D45B","#915ABB","#FF7C26","#50C5F6","#ECBE4B"];
            return colors[i % colors.length];
        };
    
        var i = 0;
        var j=1;
        for(let d of this.lineData){
            this.g.append('path')
                .attr('d', this.line(d.values))
                .attr("class", "line")
                .attr("stroke", color(i))
                .attr("transform", "translate(0,"+this.margin.top+")")
                .attr("id","row-"+j)
                .on("mouseover",function(){
                    d3.select(this)
                        .attr("class","line1");
                    d3.select("tr#"+this.id)
                        .style("background-color","gainsboro")
                    //console.log( d3.select("tr#"+this.id))
                })
                .on('mouseout', function(){
                    d3.select(this)
                        .attr("class","line");
                    d3.select("tr#"+this.id)
                        .style("background-color","")
                });
    
                j++;
                i++;
                if(i > 9) {
                    i = 0;
                }
      }
    }
    private mouseover(event){
    d3.select(event.currentTarget)
        .style("background-color","gainsboro")
    d3.select("path#"+event.currentTarget.id)
        .attr("class","line1");
    
    }
    
    private mouseout(event){
    d3.select(event.currentTarget)
        .style("background-color","")
    d3.select("path#"+event.currentTarget.id)
        .attr("class","line");
    }
    

    while creating line i assigned id to it and the same id to every row in table.

    <tr *ngFor="let object of jsonFile; let i = index" id="{{'row-'+[i+1]}}" 
         (mouseover)="mouseover($event)" (mouseout)="mouseout($event)">
        <td *ngFor="let column of columnHeaders" [ngStyle]="{'width': 
               column.length}">
            <div *ngIf="isString(column.columnType) == true">
              {{object[column.id] | trim}}
            </div>
            <div *ngIf="isString(column.columnType) == false">
              {{object[column.id]}}
            </div>
        </td>
      </tr>
    

    and called the mouseover and mouseout function in table row. I would like to have some recommendations if m wrong somewhere.. :)

    0 讨论(0)
提交回复
热议问题