Browse Source

Add support for tooltip ordering, fix #1050 #1764 [REPOST PR #1813] (#2070)

Updates PR #1813 by @panthony.
pull/1367/merge
Alex Gervais 8 years ago committed by Ændrew Rininsland
parent
commit
c376e13442
  1. 106
      c3.js
  2. 2
      c3.min.css
  3. 2
      c3.min.js
  4. 331
      spec/tooltip-spec.js
  5. 1
      src/config.js
  6. 8
      src/data.js
  7. 94
      src/tooltip.js
  8. 3
      src/util.js

106
c3.js

@ -88,6 +88,9 @@ var isValue = function (v) {
var isFunction = function (o) { var isFunction = function (o) {
return typeof o === 'function'; return typeof o === 'function';
}; };
var isArray = function (o) {
return Array.isArray(o);
};
var isString = function (o) { var isString = function (o) {
return typeof o === 'string'; return typeof o === 'string';
}; };
@ -853,8 +856,6 @@ var c3_chart_fn;
var c3_chart_internal_fn; var c3_chart_internal_fn;
var c3_chart_internal_axis_fn; var c3_chart_internal_axis_fn;
var d3 = window.d3 ? window.d3 : typeof require !== 'undefined' ? require("d3") : undefined;
function API(owner) { function API(owner) {
this.owner = owner; this.owner = owner;
} }
@ -895,7 +896,7 @@ function Chart(config) {
function ChartInternal(api) { function ChartInternal(api) {
var $$ = this; var $$ = this;
$$.d3 = d3; $$.d3 = window.d3 ? window.d3 : typeof require !== 'undefined' ? require("d3") : undefined;
$$.api = api; $$.api = api;
$$.config = $$.getDefaultConfig(); $$.config = $$.getDefaultConfig();
$$.data = {}; $$.data = {};
@ -4586,6 +4587,7 @@ c3_chart_internal_fn.getDefaultConfig = function () {
// tooltip - show when mouseover on each data // tooltip - show when mouseover on each data
tooltip_show: true, tooltip_show: true,
tooltip_grouped: true, tooltip_grouped: true,
tooltip_order: undefined,
tooltip_format_title: undefined, tooltip_format_title: undefined,
tooltip_format_name: undefined, tooltip_format_name: undefined,
tooltip_format_value: undefined, tooltip_format_value: undefined,
@ -5107,7 +5109,11 @@ c3_chart_internal_fn.orderTargets = function (targets) {
}); });
} else if (isFunction(config.data_order)) { } else if (isFunction(config.data_order)) {
targets.sort(config.data_order); targets.sort(config.data_order);
} // TODO: accept name array for order } else if (isArray(config.data_order)) {
targets.sort(function (t1, t2) {
return config.data_order.indexOf(t1.id) - config.data_order.indexOf(t2.id);
});
}
return targets; return targets;
}; };
c3_chart_internal_fn.filterByX = function (targets, x) { c3_chart_internal_fn.filterByX = function (targets, x) {
@ -7968,31 +7974,85 @@ c3_chart_internal_fn.initTooltip = function () {
.style("display", "block"); .style("display", "block");
} }
}; };
c3_chart_internal_fn.getTooltipSortFunction = function() {
var $$ = this, config = $$.config;
if (config.data_groups.length === 0 || config.tooltip_order !== undefined) {
// if data are not grouped or if an order is specified
// for the tooltip values we sort them by their values
var order = config.tooltip_order;
if (order === undefined) {
order = config.data_order;
}
var valueOf = function(obj) {
return obj ? obj.value : null;
};
// if data are not grouped, we sort them by their value
if (isString(order) && order.toLowerCase() === 'asc') {
return function(a, b) {
return valueOf(a) - valueOf(b);
};
} else if (isString(order) && order.toLowerCase() === 'desc') {
return function (a, b) {
return valueOf(b) - valueOf(a);
};
} else if (isFunction(order)) {
// if the function is from data_order we need
// to wrap the returned function in order to format
// the sorted value to the expected format
var sortFunction = order;
if (config.tooltip_order === undefined) {
sortFunction = function (a, b) {
return order(a ? {
id: a.id,
values: [ a ]
} : null, b ? {
id: b.id,
values: [ b ]
} : null);
};
}
return sortFunction;
} else if (isArray(order)) {
return function(a, b) {
return order.indexOf(a.id) - order.indexOf(b.id);
};
}
} else {
// if data are grouped, we follow the order of grouped targets
var ids = $$.orderTargets($$.data.targets).map(function(i) {
return i.id;
});
// if it was either asc or desc we need to invert the order
// returned by orderTargets
if ($$.isOrderAsc() || $$.isOrderDesc()) {
ids = ids.reverse();
}
return function(a, b) {
return ids.indexOf(a.id) - ids.indexOf(b.id);
};
}
};
c3_chart_internal_fn.getTooltipContent = function (d, defaultTitleFormat, defaultValueFormat, color) { c3_chart_internal_fn.getTooltipContent = function (d, defaultTitleFormat, defaultValueFormat, color) {
var $$ = this, config = $$.config, var $$ = this, config = $$.config,
titleFormat = config.tooltip_format_title || defaultTitleFormat, titleFormat = config.tooltip_format_title || defaultTitleFormat,
nameFormat = config.tooltip_format_name || function (name) { return name; }, nameFormat = config.tooltip_format_name || function (name) { return name; },
valueFormat = config.tooltip_format_value || defaultValueFormat, valueFormat = config.tooltip_format_value || defaultValueFormat,
text, i, title, value, name, bgcolor, text, i, title, value, name, bgcolor;
orderAsc = $$.isOrderAsc();
if (config.data_groups.length === 0) { var tooltipSortFunction = this.getTooltipSortFunction();
d.sort(function(a, b){ if(tooltipSortFunction) {
var v1 = a ? a.value : null, v2 = b ? b.value : null; d.sort(tooltipSortFunction);
return orderAsc ? v1 - v2 : v2 - v1;
});
} else {
var ids = $$.orderTargets($$.data.targets).map(function (i) {
return i.id;
});
d.sort(function(a, b) {
var v1 = a ? a.value : null, v2 = b ? b.value : null;
if (v1 > 0 && v2 > 0) {
v1 = a ? ids.indexOf(a.id) : null;
v2 = b ? ids.indexOf(b.id) : null;
}
return orderAsc ? v1 - v2 : v2 - v1;
});
} }
for (i = 0; i < d.length; i++) { for (i = 0; i < d.length; i++) {

2
c3.min.css vendored

@ -1 +1 @@
.c3 svg{font:10px sans-serif;-webkit-tap-highlight-color:transparent}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:gray;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-item-hidden{opacity:.15}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-title{font:14px sans-serif}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777;opacity:.9}.c3-tooltip tr{border:1px solid #CCC}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#FFF}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{display:inline-block;width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs-title{dominant-baseline:middle;font-size:1.3em}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max,.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000} .c3 svg{font:10px sans-serif;-webkit-tap-highlight-color:transparent}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:grey;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-item-hidden{opacity:.15}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-title{font:14px sans-serif}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777;opacity:.9}.c3-tooltip tr{border:1px solid #ccc}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#fff}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{display:inline-block;width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs-title{dominant-baseline:middle;font-size:1.3em}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max{fill:#777}.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000}

2
c3.min.js vendored

File diff suppressed because one or more lines are too long

331
spec/tooltip-spec.js

@ -2,16 +2,20 @@ describe('c3 chart tooltip', function () {
'use strict'; 'use strict';
var chart; var chart;
var tooltipConfiguration; var tooltipConfiguration = {};
var dataOrder = 'desc';
var dataGroups;
var args = function () { var args = function () {
return { return {
data: { data: {
columns: [ columns: [
['data1', 30, 200, 100, 400, 150, 250], ['data1', 30, 200, 100, 400, 150, 250], // 1130
['data2', 50, 20, 10, 40, 15, 25], ['data2', 50, 20, 10, 40, 15, 25], // 160
['data3', 150, 120, 110, 140, 115, 125] ['data3', 150, 120, 110, 140, 115, 125] // 760
], ],
order: dataOrder,
groups: dataGroups,
}, },
tooltip: tooltipConfiguration tooltip: tooltipConfiguration
}; };
@ -19,6 +23,8 @@ describe('c3 chart tooltip', function () {
beforeEach(function (done) { beforeEach(function (done) {
chart = window.initChart(chart, args(), done); chart = window.initChart(chart, args(), done);
dataOrder = 'desc';
dataGroups = undefined;
}); });
describe('tooltip position', function () { describe('tooltip position', function () {
@ -118,4 +124,321 @@ describe('c3 chart tooltip', function () {
} }
}); });
}); });
describe('tooltip with data_order as desc with grouped data', function() {
beforeAll(function() {
dataOrder = 'desc';
dataGroups = [ [ 'data1', 'data2', 'data3' ]];
});
it('should display each data in descending order', function() {
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
return node.className;
});
expect(classes[0]).toBe(''); // header
expect(classes[1]).toBe('c3-tooltip-name--data1'); // 1130
expect(classes[2]).toBe('c3-tooltip-name--data3'); // 760
expect(classes[3]).toBe('c3-tooltip-name--data2'); // 160
});
});
describe('tooltip with data_order as asc with grouped data', function() {
beforeAll(function() {
dataOrder = 'asc';
dataGroups = [ [ 'data1', 'data2', 'data3' ]];
});
it('should display each data in ascending order', function() {
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
return node.className;
});
expect(classes[0]).toBe(''); // header
expect(classes[1]).toBe('c3-tooltip-name--data2'); // 160
expect(classes[2]).toBe('c3-tooltip-name--data3'); // 760
expect(classes[3]).toBe('c3-tooltip-name--data1'); // 1130
});
});
describe('tooltip with data_order as NULL with grouped data', function() {
beforeAll(function() {
dataOrder = null;
dataGroups = [ [ 'data1', 'data2', 'data3' ]];
});
it('should display each data in given order', function() {
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
return node.className;
});
expect(classes[0]).toBe(''); // header
expect(classes[1]).toBe('c3-tooltip-name--data1');
expect(classes[2]).toBe('c3-tooltip-name--data2');
expect(classes[3]).toBe('c3-tooltip-name--data3');
});
});
describe('tooltip with data_order as Function with grouped data', function() {
beforeAll(function() {
var order = [ 'data2', 'data1', 'data3' ];
dataOrder = function(data1, data2) {
return order.indexOf(data1.id) - order.indexOf(data2.id);
};
dataGroups = [ [ 'data1', 'data2', 'data3' ]];
});
it('should display each data in order given by function', function() {
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
return node.className;
});
expect(classes[0]).toBe(''); // header
expect(classes[1]).toBe('c3-tooltip-name--data2');
expect(classes[2]).toBe('c3-tooltip-name--data1');
expect(classes[3]).toBe('c3-tooltip-name--data3');
});
});
describe('tooltip with data_order as Array with grouped data', function() {
beforeAll(function() {
dataOrder = [ 'data2', 'data1', 'data3' ];
dataGroups = [ [ 'data1', 'data2', 'data3' ]];
});
it('should display each data in order given by array', function() {
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
return node.className;
});
expect(classes[0]).toBe(''); // header
expect(classes[1]).toBe('c3-tooltip-name--data2');
expect(classes[2]).toBe('c3-tooltip-name--data1');
expect(classes[3]).toBe('c3-tooltip-name--data3');
});
});
describe('tooltip with data_order as desc with un-grouped data', function() {
beforeAll(function() {
dataOrder = 'desc';
});
it('should display each tooltip value descending order', function() {
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
return node.className;
});
expect(classes[0]).toBe(''); // header
expect(classes[1]).toBe('c3-tooltip-name--data3'); // 110
expect(classes[2]).toBe('c3-tooltip-name--data1'); // 100
expect(classes[3]).toBe('c3-tooltip-name--data2'); // 10
});
});
describe('tooltip with data_order as asc with un-grouped data', function() {
beforeAll(function() {
dataOrder = 'asc';
});
it('should display each tooltip value in ascending order', function() {
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
return node.className;
});
expect(classes[0]).toBe(''); // header
expect(classes[1]).toBe('c3-tooltip-name--data2'); // 10
expect(classes[2]).toBe('c3-tooltip-name--data1'); // 100
expect(classes[3]).toBe('c3-tooltip-name--data3'); // 110
});
});
describe('tooltip with data_order as NULL with un-grouped data', function() {
beforeAll(function() {
dataOrder = null;
});
it('should display each tooltip value in given data order', function() {
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
return node.className;
});
expect(classes[0]).toBe(''); // header
expect(classes[1]).toBe('c3-tooltip-name--data1');
expect(classes[2]).toBe('c3-tooltip-name--data2');
expect(classes[3]).toBe('c3-tooltip-name--data3');
});
});
describe('tooltip with data_order as Function with un-grouped data', function() {
beforeAll(function() {
var order = [ 'data2', 'data1', 'data3' ];
dataOrder = function(data1, data2) {
return order.indexOf(data1.id) - order.indexOf(data2.id);
};
});
it('should display each tooltip value in data order given by function', function() {
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
return node.className;
});
expect(classes[0]).toBe(''); // header
expect(classes[1]).toBe('c3-tooltip-name--data2');
expect(classes[2]).toBe('c3-tooltip-name--data1');
expect(classes[3]).toBe('c3-tooltip-name--data3');
});
});
describe('tooltip with data_order as Array with un-grouped data', function() {
beforeAll(function() {
dataOrder = [ 'data2', 'data1', 'data3' ];
});
it('should display each tooltip value in data order given by array', function() {
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
return node.className;
});
expect(classes[0]).toBe(''); // header
expect(classes[1]).toBe('c3-tooltip-name--data2');
expect(classes[2]).toBe('c3-tooltip-name--data1');
expect(classes[3]).toBe('c3-tooltip-name--data3');
});
});
describe('tooltip with tooltip_order as desc', function() {
beforeAll(function() {
tooltipConfiguration = {
order: 'desc'
};
// this should be ignored
dataOrder = 'asc';
dataGroups = [ [ 'data1', 'data2', 'data3' ]];
});
it('should display each tooltip value descending order', function() {
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
return node.className;
});
expect(classes[0]).toBe(''); // header
expect(classes[1]).toBe('c3-tooltip-name--data3'); // 110
expect(classes[2]).toBe('c3-tooltip-name--data1'); // 100
expect(classes[3]).toBe('c3-tooltip-name--data2'); // 10
});
});
describe('tooltip with tooltip_order as asc', function() {
beforeAll(function() {
tooltipConfiguration = {
order: 'asc'
};
// this should be ignored
dataOrder = 'desc';
dataGroups = [ [ 'data1', 'data2', 'data3' ]];
});
it('should display each tooltip value in ascending order', function() {
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
return node.className;
});
expect(classes[0]).toBe(''); // header
expect(classes[1]).toBe('c3-tooltip-name--data2'); // 10
expect(classes[2]).toBe('c3-tooltip-name--data1'); // 100
expect(classes[3]).toBe('c3-tooltip-name--data3'); // 110
});
});
describe('tooltip with tooltip_order as NULL', function() {
beforeAll(function() {
tooltipConfiguration = {
order: null
};
});
it('should display each tooltip value in given order', function() {
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
return node.className;
});
expect(classes[0]).toBe(''); // header
expect(classes[1]).toBe('c3-tooltip-name--data1');
expect(classes[2]).toBe('c3-tooltip-name--data2');
expect(classes[3]).toBe('c3-tooltip-name--data3');
});
});
describe('tooltip with tooltip_order as Function', function() {
beforeAll(function() {
var order = [ 'data2', 'data1', 'data3' ];
tooltipConfiguration = {
order: function(data1, data2) {
return order.indexOf(data1.id) - order.indexOf(data2.id);
}
};
});
it('should display each tooltip value in data order given by function', function() {
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
return node.className;
});
expect(classes[0]).toBe(''); // header
expect(classes[1]).toBe('c3-tooltip-name--data2');
expect(classes[2]).toBe('c3-tooltip-name--data1');
expect(classes[3]).toBe('c3-tooltip-name--data3');
});
});
describe('tooltip with tooltip_order as Array', function() {
beforeAll(function() {
tooltipConfiguration = {
order: [ 'data2', 'data1', 'data3' ]
};
});
it('should display each tooltip value in data order given by array', function() {
window.setMouseEvent(chart, 'mousemove', 100, 100, d3.select('.c3-event-rect-2').node());
var classes = d3.selectAll('.c3-tooltip tr')[0].map(function(node) {
return node.className;
});
expect(classes[0]).toBe(''); // header
expect(classes[1]).toBe('c3-tooltip-name--data2');
expect(classes[2]).toBe('c3-tooltip-name--data1');
expect(classes[3]).toBe('c3-tooltip-name--data3');
});
});
}); });

1
src/config.js

@ -208,6 +208,7 @@ c3_chart_internal_fn.getDefaultConfig = function () {
// tooltip - show when mouseover on each data // tooltip - show when mouseover on each data
tooltip_show: true, tooltip_show: true,
tooltip_grouped: true, tooltip_grouped: true,
tooltip_order: undefined,
tooltip_format_title: undefined, tooltip_format_title: undefined,
tooltip_format_name: undefined, tooltip_format_name: undefined,
tooltip_format_value: undefined, tooltip_format_value: undefined,

8
src/data.js

@ -1,6 +1,6 @@
import CLASS from './class'; import CLASS from './class';
import { c3_chart_internal_fn } from './core'; import { c3_chart_internal_fn } from './core';
import { isValue, isFunction, notEmpty, hasValue } from './util'; import { isValue, isFunction, isArray, notEmpty, hasValue } from './util';
c3_chart_internal_fn.isX = function (key) { c3_chart_internal_fn.isX = function (key) {
var $$ = this, config = $$.config; var $$ = this, config = $$.config;
@ -237,7 +237,11 @@ c3_chart_internal_fn.orderTargets = function (targets) {
}); });
} else if (isFunction(config.data_order)) { } else if (isFunction(config.data_order)) {
targets.sort(config.data_order); targets.sort(config.data_order);
} // TODO: accept name array for order } else if (isArray(config.data_order)) {
targets.sort(function (t1, t2) {
return config.data_order.indexOf(t1.id) - config.data_order.indexOf(t2.id);
});
}
return targets; return targets;
}; };
c3_chart_internal_fn.filterByX = function (targets, x) { c3_chart_internal_fn.filterByX = function (targets, x) {

94
src/tooltip.js

@ -1,6 +1,6 @@
import CLASS from './class'; import CLASS from './class';
import { c3_chart_internal_fn } from './core'; import { c3_chart_internal_fn } from './core';
import { isValue, isString, sanitise } from './util'; import { isValue, isFunction, isArray, isString, sanitise } from './util';
c3_chart_internal_fn.initTooltip = function () { c3_chart_internal_fn.initTooltip = function () {
var $$ = this, config = $$.config, i; var $$ = this, config = $$.config, i;
@ -28,31 +28,85 @@ c3_chart_internal_fn.initTooltip = function () {
.style("display", "block"); .style("display", "block");
} }
}; };
c3_chart_internal_fn.getTooltipSortFunction = function() {
var $$ = this, config = $$.config;
if (config.data_groups.length === 0 || config.tooltip_order !== undefined) {
// if data are not grouped or if an order is specified
// for the tooltip values we sort them by their values
var order = config.tooltip_order;
if (order === undefined) {
order = config.data_order;
}
var valueOf = function(obj) {
return obj ? obj.value : null;
};
// if data are not grouped, we sort them by their value
if (isString(order) && order.toLowerCase() === 'asc') {
return function(a, b) {
return valueOf(a) - valueOf(b);
};
} else if (isString(order) && order.toLowerCase() === 'desc') {
return function (a, b) {
return valueOf(b) - valueOf(a);
};
} else if (isFunction(order)) {
// if the function is from data_order we need
// to wrap the returned function in order to format
// the sorted value to the expected format
var sortFunction = order;
if (config.tooltip_order === undefined) {
sortFunction = function (a, b) {
return order(a ? {
id: a.id,
values: [ a ]
} : null, b ? {
id: b.id,
values: [ b ]
} : null);
};
}
return sortFunction;
} else if (isArray(order)) {
return function(a, b) {
return order.indexOf(a.id) - order.indexOf(b.id);
};
}
} else {
// if data are grouped, we follow the order of grouped targets
var ids = $$.orderTargets($$.data.targets).map(function(i) {
return i.id;
});
// if it was either asc or desc we need to invert the order
// returned by orderTargets
if ($$.isOrderAsc() || $$.isOrderDesc()) {
ids = ids.reverse();
}
return function(a, b) {
return ids.indexOf(a.id) - ids.indexOf(b.id);
};
}
};
c3_chart_internal_fn.getTooltipContent = function (d, defaultTitleFormat, defaultValueFormat, color) { c3_chart_internal_fn.getTooltipContent = function (d, defaultTitleFormat, defaultValueFormat, color) {
var $$ = this, config = $$.config, var $$ = this, config = $$.config,
titleFormat = config.tooltip_format_title || defaultTitleFormat, titleFormat = config.tooltip_format_title || defaultTitleFormat,
nameFormat = config.tooltip_format_name || function (name) { return name; }, nameFormat = config.tooltip_format_name || function (name) { return name; },
valueFormat = config.tooltip_format_value || defaultValueFormat, valueFormat = config.tooltip_format_value || defaultValueFormat,
text, i, title, value, name, bgcolor, text, i, title, value, name, bgcolor;
orderAsc = $$.isOrderAsc();
if (config.data_groups.length === 0) { var tooltipSortFunction = this.getTooltipSortFunction();
d.sort(function(a, b){ if(tooltipSortFunction) {
var v1 = a ? a.value : null, v2 = b ? b.value : null; d.sort(tooltipSortFunction);
return orderAsc ? v1 - v2 : v2 - v1;
});
} else {
var ids = $$.orderTargets($$.data.targets).map(function (i) {
return i.id;
});
d.sort(function(a, b) {
var v1 = a ? a.value : null, v2 = b ? b.value : null;
if (v1 > 0 && v2 > 0) {
v1 = a ? ids.indexOf(a.id) : null;
v2 = b ? ids.indexOf(b.id) : null;
}
return orderAsc ? v1 - v2 : v2 - v1;
});
} }
for (i = 0; i < d.length; i++) { for (i = 0; i < d.length; i++) {

3
src/util.js

@ -6,6 +6,9 @@ export var isValue = function (v) {
export var isFunction = function (o) { export var isFunction = function (o) {
return typeof o === 'function'; return typeof o === 'function';
}; };
export var isArray = function (o) {
return Array.isArray(o);
};
export var isString = function (o) { export var isString = function (o) {
return typeof o === 'string'; return typeof o === 'string';
}; };

Loading…
Cancel
Save