Dynamically added svg elements and dc.js range charts filtering

123 views
Skip to first unread message

Sofia Rodrigues

unread,
Nov 29, 2016, 1:07:20 PM11/29/16
to dc-js user group
Hello,

So I'm back with the previous chart and a few additions >.>


I'm not sure how to solve the problem I am facing now due to the addition of a barChart as a rangeChart.

Basically, the annotated circles will of course not move when the chart is filtered... Is this solved with D3 or Dc? 

I'm torn between two possible ideas:
- keeping the current annotated circles and find a way to filter/move them with the chart
- style the lineChart dots through d3 instead (which would involve adding a 2nd circle for the stroke) but would keep the Xytips :o <-- though when the dot goes out of bounds, its style is reset of course...

I'd honestly prefer to keep the annotated circles moving/being filtered as well, but is this even a viable/possible solution?

Thank you for reading as I continue to beat my head against the wall x_x

Sofia Rodrigues

unread,
Nov 29, 2016, 4:14:12 PM11/29/16
to dc-js user group
Nevermind (kinda), I found that the position does update using chart.x() so I just have to figure out how to update the circles using d3 @_@

Gordon Woodhull

unread,
Nov 29, 2016, 8:40:11 PM11/29/16
to dc.js user group
Hi Sofia,

This is pretty sophisticated stuff you're doing, so it's no wonder if it's a bit overwhelming. If you want to do this kind of deep customization, dc.js does not save you from learning d3.js (and there are those that would argue dc means you now have two things to learn). 

I'd approach this a different way. 

When we did the regression line, that was separate data, because it was calculated from scratch. But here it's more convenient to with the existing dots and modify them. This way a lot less code is duplicated and you don't have to rewrite so much of what dc.js is doing.

So instead of an array of all the annotations, I'd keep a map of just the extra info about the annotations:

    var annotateDots = {};
    annotateDots[data[3].date.getTime()] = {"radius": 8, "color" : "green"};
    annotateDots[data[7].date.getTime()] = {"radius": 8, "color" : "purple"};
    annotateDots[data[0].date.getTime()] = {"radius": 8, "color" : "red"};

I'm using the date as the key into this object so that it will be easy to look up later. I have to use .getTime() in order to get the date object as an integer.

It's kind of tricky to get it working with transitions, so I've skipped that for now. Instead, I'll just remove any existing annotations at the end of the pretransition event, in line 126

        chartBody.selectAll('circle.annotation').remove();

And I'll add a new renderlet which fires after transitions are done:

.on('renderlet', function(chart) {
        var chartBody = chart.select('g.chart-body');
        var circles = chartBody.selectAll("circle.dot"); // #1
        circles.each(function(d, i) { // #2
          var annotation = annotateDots[d.data.key.getTime()]; // #3
          if(annotation) {
            var that = this;
            var dot = d3.select(this); // #4
            dot
              .attr('fill', annotation.color) // #5
              .attr('opacity', 1); 
            d3.select(this.parentElement) // #6
              .insert('circle', function() { return that; }) // #7
              .attr({ // #8
                class: 'annotation',
                cx: dot.attr('cx'),
                cy: dot.attr('cy'),
                r: annotation.radius,
                fill: 'none',
                stroke: annotation.color
              })
          }
        })
          
         console.log('circles: ', circles);

          
          handleDataPointClick();

      });

1. select the existing dots (from the line chart, not ours)
2. loop over them 
3. see if we have an annotation for the date of this dot
4. "this" is the element, make a d3 selection from this
5. change the color to what we want
6. select the parent so we can 7. add a sibling to the current dot, inserting directly before it
8. and set all the attributes for the outline circle at once.

It's all kind of busy, with a bit too much change and animation, but it sort of works:

Cheers,
Gordon


-- 
You received this message because you are subscribed to the Google Groups "dc-js user group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dc-js-user-gro...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/dc-js-user-group/4bd047f6-9c69-48aa-850f-2e74ad356ec8%40googlegroups.com.

Sofia Rodrigues

unread,
Nov 30, 2016, 1:25:58 PM11/30/16
to dc-js user group
This is so much simpler than mine @_@ I managed to incorporate it into my code so thank youuuuuuuuuu :D It works just fine!

Sofia Rodrigues

unread,
Dec 1, 2016, 9:53:43 AM12/1/16
to dc-js user group
Just one last thing, if I want to add new annotations once the chart has been rendered, is the only way to get it to show the outer circle a redraw on the chart? I tried with d3 but even though the element was there, it didn't render until I did a redraw (and then adding with d3 wasn't necessary since the renderlet handled it)
Reply all
Reply to author
Forward
0 new messages