Skip to content

Commit

Permalink
Optionally collapse or expand timeline.
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderby committed May 19, 2017
1 parent 6b9e8f8 commit 11beb48
Show file tree
Hide file tree
Showing 3 changed files with 213 additions and 69 deletions.
125 changes: 61 additions & 64 deletions examples/specs/timeline.js
@@ -1,14 +1,50 @@
var timeLineData = [
{start: '2015-02-03', end: '2015-03-02', team: 'Manchester', country: 'England'},
{start: '2015-02-12', end: '2015-03-01', team: 'Chelsea', country: 'England'},
{start: '2015-02-17', end: '2015-02-19', team: 'Liverpool', country: 'England'},
{start: '2015-03-04', end: '2015-03-10', team: 'Aston Villa', country: 'England'},
{start: '2015-02-24', end: '2015-03-03', team: 'Manchester', country: 'England'},
{start: '2015-03-04', end: '2015-03-10', team: 'Manchester', country: 'England'},
{start: '2015-02-29', end: '2015-03-09', team: 'Real', country: 'Spain'},
{start: '2015-02-24', end: '2015-03-03', team: 'Real', country: 'Spain'},
{start: '2015-03-04', end: '2015-03-10', team: 'Barcelona', country: 'Spain'},
{start: '2015-02-29', end: '2015-03-09', team: 'Valencia', country: 'Spain'},
{start: '2015-02-29', end: '2015-03-09', team: 'Borussia', country: 'Germany'},
{start: '2015-02-24', end: '2015-03-03', team: 'Borussia', country: 'Germany'},
{start: '2015-03-04', end: '2015-03-10', team: 'Borussia', country: 'Germany'},
{start: '2015-02-29', end: '2015-03-09', team: 'Schalke', country: 'Germany'},
{start: '2015-02-02', end: '2015-02-09', team: 'Bate', country: 'Belarus'},
{start: '2015-02-05', end: '2015-03-03', team: 'Dynamo', country: 'Belarus'},
{start: '2015-02-07', end: '2015-02-10', team: 'Dynamo', country: 'Belarus'},
{start: '2015-02-08', end: '2015-02-20', team: 'Dynamo', country: 'Belarus'},
{start: '2015-02-12', end: '2015-02-24', team: 'Dynamo', country: 'Belarus'},
{start: '2015-02-29', end: '2015-03-04', team: 'Shakhtyor', country: 'Belarus'}
].map(function (data) {
return {
team: data.team,
start: new Date(data.start),
end: new Date(data.end),
country: data.country
};
});

dev.spec({
type: 'horizontal-bar',
x: 'end',
y: ['team', 'type'],
color: 'type',
label: 'name',
y: ['country', 'team'],
color: 'team',
label: 'team',
plugins: [
tauCharts.api.plugins.get('tooltip')(),
tauCharts.api.plugins.get('legend')(),
tauCharts.api.plugins.get('bar-as-span')({
x0: 'start'
})
],
// settings:{
// fitModel: 'entire-view'
// },
data: timeLineData,
dimensions: {
'start': {
type: 'measure',
Expand All @@ -18,37 +54,35 @@ dev.spec({
type: 'measure',
scale: 'time'
},
'type': {
'country': {
type: 'category',
scale: 'ordinal'
},
'team': {
type: 'category',
scale: 'ordinal'
}
},
data: [
{ start: '2015-05-01', end: '2015-06-01', type: 'Bug', name: 'Broken tabs layout', team: 'Developers' },
{ start: '2015-05-10', end: '2015-06-20', type: 'Feature', name: 'Payment form', team: 'Developers' },
{ start: '2015-05-20', end: '2015-05-30', type: 'Feature', name: 'Scroll bar', team: 'Developers' },
{ start: '2015-06-10', end: '2015-06-15', type: 'Bug', name: 'Modal dialog collapsed', team: 'Developers' },
{ start: '2015-05-20', end: '2015-05-25', type: 'Sale', name: 'Tractors', team: 'Sales' },
{ start: '2015-05-25', end: '2015-05-30', type: 'Sale', name: 'Nails', team: 'Sales' },
{ start: '2015-05-26', end: '2015-06-01', type: 'Sale', name: 'Oil', team: 'Sales' }
]
}
});

dev.spec({
type: 'bar',
y: 'end',
x: ['team'],
color: 'type',
label: 'name',
type: 'horizontal-bar',
x: 'end',
y: ['country', 'team'],
color: 'team',
label: 'team',
plugins: [
tauCharts.api.plugins.get('tooltip')(),
tauCharts.api.plugins.get('legend')(),
tauCharts.api.plugins.get('bar-as-span')({
y0: 'start'
x0: 'start',
collapse: false
})
],
// settings:{
// fitModel: 'entire-view'
// },
data: timeLineData,
dimensions: {
'start': {
type: 'measure',
Expand All @@ -58,71 +92,34 @@ dev.spec({
type: 'measure',
scale: 'time'
},
'type': {
'country': {
type: 'category',
scale: 'ordinal'
},
'team': {
type: 'category',
scale: 'ordinal'
}
},
data: [
{ start: '2015-05-01', end: '2015-06-01', type: 'Bug', name: 'Broken tabs layout', team: 'Developers' },
{ start: '2015-05-10', end: '2015-06-20', type: 'Feature', name: 'Payment form', team: 'Developers' },
{ start: '2015-05-20', end: '2015-05-30', type: 'Feature', name: 'Scroll bar', team: 'Developers' },
{ start: '2015-06-10', end: '2015-06-15', type: 'Bug', name: 'Modal dialog collapsed', team: 'Developers' },
{ start: '2015-05-20', end: '2015-05-25', type: 'Sale', name: 'Tractors', team: 'Sales' },
{ start: '2015-05-25', end: '2015-05-30', type: 'Sale', name: 'Nails', team: 'Sales' },
{ start: '2015-05-26', end: '2015-06-01', type: 'Sale', name: 'Oil', team: 'Sales' }
]
}
});

dev.spec({
type: 'horizontal-bar',
x: 'end',
y: ['country', 'team'],
type: 'bar',
y: 'end',
x: ['country', 'team'],
color: 'team',
label: 'team',
plugins: [
tauCharts.api.plugins.get('tooltip')(),
tauCharts.api.plugins.get('legend')(),
tauCharts.api.plugins.get('bar-as-span')({
x0: 'start'
y0: 'start'
})
],
// settings:{
// fitModel: 'entire-view'
// },
data: [
{start: '2015-02-03', end: '2015-03-02', team: 'Manchester', country: 'England'},
{start: '2015-02-12', end: '2015-03-01', team: 'Chelsea', country: 'England'},
{start: '2015-02-17', end: '2015-02-19', team: 'Liverpool', country: 'England'},
{start: '2015-03-04', end: '2015-03-10', team: 'Aston Villa', country: 'England'},
{start: '2015-02-24', end: '2015-03-03', team: 'Manchester', country: 'England'},
{start: '2015-03-04', end: '2015-03-10', team: 'Manchester', country: 'England'},
{start: '2015-02-29', end: '2015-03-09', team: 'Real', country: 'Spain'},
{start: '2015-02-24', end: '2015-03-03', team: 'Real', country: 'Spain'},
{start: '2015-03-04', end: '2015-03-10', team: 'Barcelona', country: 'Spain'},
{start: '2015-02-29', end: '2015-03-09', team: 'Valencia', country: 'Spain'},
{start: '2015-02-29', end: '2015-03-09', team: 'Borussia', country: 'Germany'},
{start: '2015-02-24', end: '2015-03-03', team: 'Borussia', country: 'Germany'},
{start: '2015-03-04', end: '2015-03-10', team: 'Borussia', country: 'Germany'},
{start: '2015-02-29', end: '2015-03-09', team: 'Schalke', country: 'Germany'},
{start: '2015-02-02', end: '2015-02-09', team: 'Bate', country: 'Belarus'},
{start: '2015-02-05', end: '2015-03-03', team: 'Dynamo', country: 'Belarus'},
{start: '2015-02-07', end: '2015-02-10', team: 'Dynamo', country: 'Belarus'},
{start: '2015-02-08', end: '2015-02-20', team: 'Dynamo', country: 'Belarus'},
{start: '2015-02-12', end: '2015-02-24', team: 'Dynamo', country: 'Belarus'},
{start: '2015-02-29', end: '2015-03-04', team: 'Shakhtyor', country: 'Belarus'}
].map(function (data) {
return {
team: data.team,
start: new Date(data.start),
end: new Date(data.end),
country: data.country
};
}),
data: timeLineData,
dimensions: {
'start': {
type: 'measure',
Expand Down
16 changes: 14 additions & 2 deletions plugins/bar-as-span.js
Expand Up @@ -18,6 +18,7 @@ function BarAsSpan(settings) {

var xDim0 = settings.x0;
var yDim0 = settings.y0;
var collapse = (settings.collapse != null ? settings.collapse : true);

var transformX0 = function (model) {
return {
Expand Down Expand Up @@ -101,7 +102,8 @@ function BarAsSpan(settings) {
return map;
}, {});
var itemLine = new Map();
data.forEach(function (d) {

var collapseIteratee = function (d) {
var cat = d[catDim];
var lines = categoryLines[cat];
var lineNum = lines.findIndex(function (l) {
Expand All @@ -113,7 +115,17 @@ function BarAsSpan(settings) {
}
lines[lineNum].push(d);
itemLine.set(d, lineNum);
});
};
var expandIteratee = function (d) {
var cat = d[catDim];
var lines = categoryLines[cat];
var lineNum = lineNum = lines.length;
lines.push([]);
lines[lineNum].push(d);
itemLine.set(d, lineNum);
};

data.forEach(collapse ? collapseIteratee : expandIteratee);

Object.keys(categoryLines).forEach(function (key) {
totalLines[key] = categoryLines[key];
Expand Down
141 changes: 138 additions & 3 deletions test/bar-as-span-plugin.test.js
Expand Up @@ -116,11 +116,9 @@ define(function (require) {
assert.equal(row.every((cell) => spanMap[cell].y === spanMap[firstCell].y), true, 'all spans at row have equal Y');
assert.equal(row.every((cell) => labelMap[cell].y === labelMap[firstCell].y), true, 'all labels at row have equal Y');
assert.equal(row.slice(1).every((cell, i) => {
var prev = row[i - 1];
return (spanMap[cell].x > spanMap[firstCell].x);
}), true, 'next span at row has larger X');
assert.equal(row.slice(1).every((cell, i) => {
var prev = row[i - 1];
return (labelMap[cell].x > labelMap[firstCell].x);
}), true, 'next label at row has larger X');
if (i > 0) {
Expand All @@ -135,7 +133,144 @@ define(function (require) {

it('should place spans correct (vertical)', function () {

// Todo: Horizontall timeline is useless, write test when Waterfall chart will be finished.
// Todo: Horizontall timeline is useless, write normal test when Waterfall chart will be finished.
var chart = new tauCharts.Chart({
type: 'bar',
y: 'end',
x: ['team', 'type'],
color: 'type',
label: 'name',
plugins: [
BarAsSpanPlugin({
y0: 'start'
})
],
dimensions: {
'start': {
type: 'measure',
scale: 'time'
},
'end': {
type: 'measure',
scale: 'time'
},
'type': {
type: 'category',
scale: 'ordinal'
},
'team': {
type: 'category',
scale: 'ordinal'
}
},
data: [
{start: '2015-05-01', end: '2015-06-01', type: 'Bug', name: 'Broken tabs layout', team: 'Developers'},
{start: '2015-05-10', end: '2015-06-20', type: 'Feature', name: 'Payment form', team: 'Developers'},
{start: '2015-05-20', end: '2015-05-30', type: 'Feature', name: 'Scroll bar', team: 'Developers'},
{start: '2015-06-10', end: '2015-06-15', type: 'Bug', name: 'Modal dialog collapsed', team: 'Developers'},
{start: '2015-05-20', end: '2015-05-25', type: 'Sale', name: 'Tractors', team: 'Sales'},
{start: '2015-05-25', end: '2015-05-30', type: 'Sale', name: 'Nails', team: 'Sales'},
{start: '2015-05-26', end: '2015-06-01', type: 'Sale', name: 'Oil', team: 'Sales'}
].map(function (d) {
d.start = new Date(d.start);
d.end = new Date(d.end)
return d;
})
});

chart.renderTo(container);
var svg = chart.getSVG();

// Note: Approximately check layout.

var spans = Array.from(svg.querySelectorAll('.bar'));

spans.slice(1).forEach((node, i) => {
var s = d3.select(node);
var p = d3.select(spans[i]);
assert.equal(
Math.sign(s.data()[0].start - p.data()[0].start),
-Math.sign(s.node().getBoundingClientRect().bottom - p.node().getBoundingClientRect().bottom),
'span screen start correspods to data start'
);
})

});

it('should place spans correct (no collapse)', function () {

var chart = new tauCharts.Chart({
type: 'horizontal-bar',
x: 'end',
y: ['team', 'type'],
color: 'type',
label: 'name',
plugins: [
BarAsSpanPlugin({
x0: 'start',
collapse: false
})
],
dimensions: {
'start': {
type: 'measure',
scale: 'time'
},
'end': {
type: 'measure',
scale: 'time'
},
'type': {
type: 'category',
scale: 'ordinal'
},
'team': {
type: 'category',
scale: 'ordinal'
}
},
data: [
{start: '2015-05-01', end: '2015-06-01', type: 'Bug', name: 'Broken tabs layout', team: 'Developers'},
{start: '2015-05-10', end: '2015-06-20', type: 'Feature', name: 'Payment form', team: 'Developers'},
{start: '2015-05-20', end: '2015-05-30', type: 'Feature', name: 'Scroll bar', team: 'Developers'},
{start: '2015-06-10', end: '2015-06-15', type: 'Bug', name: 'Modal dialog collapsed', team: 'Developers'},
{start: '2015-05-20', end: '2015-05-25', type: 'Sale', name: 'Tractors', team: 'Sales'},
{start: '2015-05-25', end: '2015-05-30', type: 'Sale', name: 'Nails', team: 'Sales'},
{start: '2015-05-26', end: '2015-06-01', type: 'Sale', name: 'Oil', team: 'Sales'}
].map(function (d) {
d.start = new Date(d.start);
d.end = new Date(d.end)
return d;
})
});

chart.renderTo(container);
var svg = chart.getSVG();

// Note: Approximately check layout.

var spans = Array.from(svg.querySelectorAll('.bar'));

var groups = spans.reduce((map, node) => {
var s = d3.select(node);
var name = s.data()[0].name;
map[name] = (map[name] || []);
map[name].push(s);
return map;
}, {});

Object.keys(groups).forEach((key) => {
var group = groups[key];
group.sort((a, b) => a.data()[0].start - b.data()[0].start);
assert.equal(group.slice(1).every((node, i) => {
var s = d3.select(node);
var p = d3.select(group[i]);
return (
Number(s.attr('x')) > Number(p.attr('x')) &&
Number(s.attr('y')) > Number(p.attr('y'))
);
}), true, 'every next date is aligned bottom-right from previous');
});

});
});
Expand Down

0 comments on commit 11beb48

Please sign in to comment.