Skip to content

Commit 461bcdd

Browse files
panthonyÆndrew Rininsland
authored andcommitted
Clearer handling of tooltip ordering with data_order option (c3js#1813)
If data is grouped: - the tooltip will keep the same ordering as the stacked values If data is not grouped: - the tooltip will use the data_order option to sort the values Also adds an optional 'tooltip_order' option. If set, it will override the data_order option.
1 parent f7f99e0 commit 461bcdd

File tree

5 files changed

+407
-40
lines changed

5 files changed

+407
-40
lines changed

spec/tooltip-spec.js

Lines changed: 321 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,29 @@ describe('c3 chart tooltip', function () {
22
'use strict';
33

44
var chart;
5-
var tooltipConfiguration;
5+
var tooltipConfiguration = {};
6+
var dataOrder = 'desc';
7+
var dataGroups;
68

79
var args = function () {
810
return {
911
data: {
1012
columns: [
11-
['data1', 30, 200, 100, 400, 150, 250],
12-
['data2', 50, 20, 10, 40, 15, 25],
13-
['data3', 150, 120, 110, 140, 115, 125]
13+
['data1', 30, 200, 100, 400, 150, 250], // 1130
14+
['data2', 50, 20, 10, 40, 15, 25], // 160
15+
['data3', 150, 120, 110, 140, 115, 125] // 760
1416
],
17+
order: dataOrder,
18+
groups: dataGroups
1519
},
1620
tooltip: tooltipConfiguration
1721
};
1822
};
1923

2024
beforeEach(function (done) {
2125
chart = window.initChart(chart, args(), done);
26+
dataOrder = 'desc';
27+
dataGroups = undefined;
2228
});
2329

2430
describe('tooltip position', function () {
@@ -99,24 +105,320 @@ describe('c3 chart tooltip', function () {
99105
});
100106
});
101107

102-
describe('tooltip getTooltipContent', function () {
103-
beforeAll(function () {
108+
describe('tooltip with data_order as desc with grouped data', function() {
109+
beforeAll(function() {
110+
dataOrder = 'desc';
111+
dataGroups = [ [ 'data1', 'data2', 'data3' ]];
112+
});
113+
114+
it('should display each data in descending order', function() {
115+
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
116+
117+
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
118+
return node.className;
119+
});
120+
121+
expect(classes[0]).toBe(''); // header
122+
expect(classes[1]).toBe('c3-tooltip-name--data1'); // 1130
123+
expect(classes[2]).toBe('c3-tooltip-name--data3'); // 760
124+
expect(classes[3]).toBe('c3-tooltip-name--data2'); // 160
125+
});
126+
});
127+
128+
describe('tooltip with data_order as asc with grouped data', function() {
129+
beforeAll(function() {
130+
dataOrder = 'asc';
131+
dataGroups = [ [ 'data1', 'data2', 'data3' ]];
132+
});
133+
134+
it('should display each data in ascending order', function() {
135+
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
136+
137+
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
138+
return node.className;
139+
});
140+
141+
expect(classes[0]).toBe(''); // header
142+
expect(classes[1]).toBe('c3-tooltip-name--data2'); // 160
143+
expect(classes[2]).toBe('c3-tooltip-name--data3'); // 760
144+
expect(classes[3]).toBe('c3-tooltip-name--data1'); // 1130
145+
});
146+
});
147+
148+
describe('tooltip with data_order as NULL with grouped data', function() {
149+
beforeAll(function() {
150+
dataOrder = null;
151+
dataGroups = [ [ 'data1', 'data2', 'data3' ]];
152+
});
153+
154+
it('should display each data in given order', function() {
155+
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
156+
157+
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
158+
return node.className;
159+
});
160+
161+
expect(classes[0]).toBe(''); // header
162+
expect(classes[1]).toBe('c3-tooltip-name--data1');
163+
expect(classes[2]).toBe('c3-tooltip-name--data2');
164+
expect(classes[3]).toBe('c3-tooltip-name--data3');
165+
});
166+
});
167+
168+
describe('tooltip with data_order as Function with grouped data', function() {
169+
beforeAll(function() {
170+
var order = [ 'data2', 'data1', 'data3' ];
171+
dataOrder = function(data1, data2) {
172+
return order.indexOf(data1.id) - order.indexOf(data2.id);
173+
};
174+
dataGroups = [ [ 'data1', 'data2', 'data3' ]];
175+
});
176+
177+
it('should display each data in order given by function', function() {
178+
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
179+
180+
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
181+
return node.className;
182+
});
183+
184+
expect(classes[0]).toBe(''); // header
185+
expect(classes[1]).toBe('c3-tooltip-name--data2');
186+
expect(classes[2]).toBe('c3-tooltip-name--data1');
187+
expect(classes[3]).toBe('c3-tooltip-name--data3');
188+
});
189+
});
190+
191+
describe('tooltip with data_order as Array with grouped data', function() {
192+
beforeAll(function() {
193+
dataOrder = [ 'data2', 'data1', 'data3' ];
194+
dataGroups = [ [ 'data1', 'data2', 'data3' ]];
195+
});
196+
197+
it('should display each data in order given by array', function() {
198+
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
199+
200+
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
201+
return node.className;
202+
});
203+
204+
expect(classes[0]).toBe(''); // header
205+
expect(classes[1]).toBe('c3-tooltip-name--data2');
206+
expect(classes[2]).toBe('c3-tooltip-name--data1');
207+
expect(classes[3]).toBe('c3-tooltip-name--data3');
208+
});
209+
});
210+
211+
describe('tooltip with data_order as desc with un-grouped data', function() {
212+
beforeAll(function() {
213+
dataOrder = 'desc';
214+
});
215+
216+
it('should display each tooltip value descending order', function() {
217+
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
218+
219+
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
220+
return node.className;
221+
});
222+
223+
expect(classes[0]).toBe(''); // header
224+
expect(classes[1]).toBe('c3-tooltip-name--data3'); // 110
225+
expect(classes[2]).toBe('c3-tooltip-name--data1'); // 100
226+
expect(classes[3]).toBe('c3-tooltip-name--data2'); // 10
227+
});
228+
});
229+
230+
describe('tooltip with data_order as asc with un-grouped data', function() {
231+
beforeAll(function() {
232+
dataOrder = 'asc';
233+
});
234+
235+
it('should display each tooltip value in ascending order', function() {
236+
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
237+
238+
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
239+
return node.className;
240+
});
241+
242+
expect(classes[0]).toBe(''); // header
243+
expect(classes[1]).toBe('c3-tooltip-name--data2'); // 10
244+
expect(classes[2]).toBe('c3-tooltip-name--data1'); // 100
245+
expect(classes[3]).toBe('c3-tooltip-name--data3'); // 110
246+
});
247+
});
248+
249+
describe('tooltip with data_order as NULL with un-grouped data', function() {
250+
beforeAll(function() {
251+
dataOrder = null;
252+
});
253+
254+
it('should display each tooltip value in given data order', function() {
255+
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
256+
257+
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
258+
return node.className;
259+
});
260+
261+
expect(classes[0]).toBe(''); // header
262+
expect(classes[1]).toBe('c3-tooltip-name--data1');
263+
expect(classes[2]).toBe('c3-tooltip-name--data2');
264+
expect(classes[3]).toBe('c3-tooltip-name--data3');
265+
});
266+
});
267+
268+
describe('tooltip with data_order as Function with un-grouped data', function() {
269+
beforeAll(function() {
270+
var order = [ 'data2', 'data1', 'data3' ];
271+
dataOrder = function(data1, data2) {
272+
return order.indexOf(data1.id) - order.indexOf(data2.id);
273+
};
274+
});
275+
276+
it('should display each tooltip value in data order given by function', function() {
277+
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
278+
279+
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
280+
return node.className;
281+
});
282+
283+
expect(classes[0]).toBe(''); // header
284+
expect(classes[1]).toBe('c3-tooltip-name--data2');
285+
expect(classes[2]).toBe('c3-tooltip-name--data1');
286+
expect(classes[3]).toBe('c3-tooltip-name--data3');
287+
});
288+
});
289+
290+
describe('tooltip with data_order as Array with un-grouped data', function() {
291+
beforeAll(function() {
292+
dataOrder = [ 'data2', 'data1', 'data3' ];
293+
});
294+
295+
it('should display each tooltip value in data order given by array', function() {
296+
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
297+
298+
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
299+
return node.className;
300+
});
301+
302+
expect(classes[0]).toBe(''); // header
303+
expect(classes[1]).toBe('c3-tooltip-name--data2');
304+
expect(classes[2]).toBe('c3-tooltip-name--data1');
305+
expect(classes[3]).toBe('c3-tooltip-name--data3');
306+
});
307+
});
308+
309+
describe('tooltip with tooltip_order as desc', function() {
310+
beforeAll(function() {
104311
tooltipConfiguration = {
105-
data_order: 'desc'
106-
};
312+
order: 'desc'
313+
};
314+
315+
// this should be ignored
316+
dataOrder = 'asc';
317+
dataGroups = [ [ 'data1', 'data2', 'data3' ]];
318+
});
319+
320+
it('should display each tooltip value descending order', function() {
321+
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
322+
323+
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
324+
return node.className;
325+
});
326+
327+
expect(classes[0]).toBe(''); // header
328+
expect(classes[1]).toBe('c3-tooltip-name--data3'); // 110
329+
expect(classes[2]).toBe('c3-tooltip-name--data1'); // 100
330+
expect(classes[3]).toBe('c3-tooltip-name--data2'); // 10
107331
});
332+
});
333+
334+
describe('tooltip with tooltip_order as asc', function() {
335+
beforeAll(function() {
336+
tooltipConfiguration = {
337+
order: 'asc'
338+
};
108339

109-
it('should sort values desc', function () {
110-
var eventRect = d3.select('.c3-event-rect-2').node();
111-
window.setMouseEvent(chart, 'mousemove', 100, 100, eventRect);
340+
// this should be ignored
341+
dataOrder = 'desc';
342+
dataGroups = [ [ 'data1', 'data2', 'data3' ]];
343+
});
344+
345+
it('should display each tooltip value in ascending order', function() {
346+
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
347+
348+
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
349+
return node.className;
350+
});
112351

113-
var tooltipTable = d3.select('.c3-tooltip')[0];
114-
var expected = ["", "c3-tooltip-name--data3",
115-
"c3-tooltip-name--data1", "c3-tooltip-name--data2"];
116-
var i;
117-
for (i = 0; i < tooltipTable[0].rows.length; i++) {
118-
expect(tooltipTable[0].rows[i].className).toBe(expected[i]);
119-
}
352+
expect(classes[0]).toBe(''); // header
353+
expect(classes[1]).toBe('c3-tooltip-name--data2'); // 10
354+
expect(classes[2]).toBe('c3-tooltip-name--data1'); // 100
355+
expect(classes[3]).toBe('c3-tooltip-name--data3'); // 110
356+
});
357+
});
358+
359+
describe('tooltip with tooltip_order as NULL', function() {
360+
beforeAll(function() {
361+
tooltipConfiguration = {
362+
order: null
363+
};
364+
});
365+
366+
it('should display each tooltip value in given order', function() {
367+
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
368+
369+
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
370+
return node.className;
371+
});
372+
373+
expect(classes[0]).toBe(''); // header
374+
expect(classes[1]).toBe('c3-tooltip-name--data1');
375+
expect(classes[2]).toBe('c3-tooltip-name--data2');
376+
expect(classes[3]).toBe('c3-tooltip-name--data3');
377+
});
378+
});
379+
380+
describe('tooltip with tooltip_order as Function', function() {
381+
beforeAll(function() {
382+
var order = [ 'data2', 'data1', 'data3' ];
383+
tooltipConfiguration = {
384+
order: function(data1, data2) {
385+
return order.indexOf(data1.id) - order.indexOf(data2.id);
386+
}
387+
};
388+
});
389+
390+
it('should display each tooltip value in data order given by function', function() {
391+
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
392+
393+
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
394+
return node.className;
395+
});
396+
397+
expect(classes[0]).toBe(''); // header
398+
expect(classes[1]).toBe('c3-tooltip-name--data2');
399+
expect(classes[2]).toBe('c3-tooltip-name--data1');
400+
expect(classes[3]).toBe('c3-tooltip-name--data3');
401+
});
402+
});
403+
404+
describe('tooltip with tooltip_order as Array', function() {
405+
beforeAll(function() {
406+
tooltipConfiguration = {
407+
order: [ 'data2', 'data1', 'data3' ]
408+
};
409+
});
410+
411+
it('should display each tooltip value in data order given by array', function() {
412+
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
413+
414+
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
415+
return node.className;
416+
});
417+
418+
expect(classes[0]).toBe(''); // header
419+
expect(classes[1]).toBe('c3-tooltip-name--data2');
420+
expect(classes[2]).toBe('c3-tooltip-name--data1');
421+
expect(classes[3]).toBe('c3-tooltip-name--data3');
422+
});
120423
});
121-
});
122424
});

src/config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ c3_chart_internal_fn.getDefaultConfig = function () {
121121
axis_y_label: {},
122122
axis_y_tick_format: undefined,
123123
axis_y_tick_outer: true,
124-
axis_y_tick_values: null,
124+
axis_y_tick_values: null,
125125
axis_y_tick_rotate: 0,
126126
axis_y_tick_count: undefined,
127127
axis_y_tick_time_value: undefined,
@@ -203,6 +203,7 @@ c3_chart_internal_fn.getDefaultConfig = function () {
203203
regions: [],
204204
// tooltip - show when mouseover on each data
205205
tooltip_show: true,
206+
tooltip_order: undefined,
206207
tooltip_grouped: true,
207208
tooltip_format_title: undefined,
208209
tooltip_format_name: undefined,

src/data.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,11 @@ c3_chart_internal_fn.orderTargets = function (targets) {
233233
});
234234
} else if (isFunction(config.data_order)) {
235235
targets.sort(config.data_order);
236-
} // TODO: accept name array for order
236+
} else if (isArray(config.data_order)) {
237+
targets.sort(function (t1, t2) {
238+
return config.data_order.indexOf(t1.id) - config.data_order.indexOf(t2.id);
239+
});
240+
}
237241
return targets;
238242
};
239243
c3_chart_internal_fn.filterByX = function (targets, x) {

0 commit comments

Comments
 (0)