问题
I use dc.js lineChart and barChart. Now I need to mark the maximum and minimum values on my lineChart with 'renderArea(true)'.
I want something like in the picture below or maybe something else, but I don't know how to add this feature.

Update:
Gordon's answer is perfect. Unfortunately, my chart doesn't show the hint with 'mouseover' on marked points

One more update:
How can I redraw these points after zooming?

回答1:
This isn't something supported directly by dc.js, but you can annotate the chart with a renderlet. Gladly, dc.js makes it easy to escape out to d3 when you need custom annotations like this.
We'll use the fact that by default the line chart draws invisible dots at each data point (which only appear when they are hovered over). We'll grab the coordinates from those and use them to draw or update our own dots in another layer.
Usually we'd want to use a pretransition event handler, but those dots don't seem to have positions until after the transition, so we'll have to handle the renderlet event instead:
chart.on('renderlet', function(chart) { // 1
// create a layer for the highlights, only once
// insert it after the tooltip/dots layer
var highlightLayer = chart.select('g.chart-body') // 2
.selectAll('g.highlight-dots').data([0]);
highlightLayer
.enter().insert('g', 'g.dc-tooltip-list').attr('class', 'highlight-dots');
chart.selectAll('g.dc-tooltip').each(function(_, stacki) { // 3
var dots = d3.select(this).selectAll('circle.dot'); // 4
var data = dots.data();
var mini = 0, maxi = 0;
data.forEach(function(d, i) { // 5
if(i===0) return;
if(d.y < data[mini].y)
mini = i;
if(d.y > data[maxi].y)
maxi = i;
});
var highlightData = [mini, maxi].map(function(i) { // 6
var dot = dots.filter(function(_, j) { return j === i; });
return {
x: dot.attr('cx'),
y: dot.attr('cy'),
color: dot.attr('fill')
}
});
var highlights = highlightLayer.selectAll('circle.minmax-highlight._' + stacki).data(highlightData);
highlights
.enter().append('circle') // 7
.attr({
class: 'minmax-highlight _' + stacki,
r: 10,
'fill-opacity': 0.2,
'stroke-opacity': 0.8
});
highlights.attr({ // 8
cx: function(d) { return d.x; },
cy: function(d) { return d.y; },
stroke: function(d) { return d.color; },
fill: function(d) { return d.color; }
});
});
});
This is fairly complicated, so let's look at it step-by-step:
- We're listening for the renderlet event, which fires after everything has transitioned
- We'll create another layer. The
.data([0]).enter().insert(stuff)
trick is a degenerate case of the d3 general update pattern that just makes sure an item is added exactly once. We specify the selector for the existing tooltip/dots layer as the second parameter to.insert()
, in order to put this layer before in DOM order, which means behind. Also, we'll hold onto the update selection because that is either the inserted node or the existing node. - We iterate through each of the stacks of tooltip-dots
- In each stack, we'll select all the existing dots,
- and iterate over all their data, finding the minimum and maximum indices
mini
andmaxi
. - Now we'll create a two-element data array for binding to the min/max highlight dots, pulling data from the existing dots
- Now we're finally ready to draw stuff. We'll use the same degenerate update pattern to draw two dots with class
minmax-highlight _1
,_2
, etc. - And use the color and positions that we remembered in step 6
Note that the min and max for each stack is not necessarily the same as the total min and max, so the highlighted points for a higher stack might not be the highest or lowest points.
Not so simple, but not too hard if you're willing to do some d3 hacking.
Example fiddle: http://jsfiddle.net/gordonwoodhull/7vptdou5/31/
来源:https://stackoverflow.com/questions/44389484/how-to-highlight-max-and-min-points-on-linechart