-
Notifications
You must be signed in to change notification settings - Fork 46
/
stacked-column-connectors.js
110 lines (96 loc) · 3.41 KB
/
stacked-column-connectors.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
(function() {
'use strict';
/*
* Column connectors helpful when displaying a stacked column chart.
* A connector will not connect positve and negative columns. This is because
* in a stacked column a negative column may move many series below its previous
* location. This creates a messy collection of crisscrossing lines.
*
* @name stackedColumnConnectors
*/
d4.feature('stackedColumnConnectors', function(name) {
var sign = function(num) {
return (num) ? (num < 0) ? -1 : 1 : 0;
};
var sharedSigns = function(a, b, key) {
return (sign(a[key]) === sign(b[key]));
};
var processPoint = function(d, i, n, data, callback) {
var key = (d4.isOrdinalScale(this.y)) ? this.x.$key : this.y.$key;
if (i === 0 || !sharedSigns(data[n].values[i - 1], d, key)) {
return 0;
}
return callback.bind(this)();
};
return {
accessors: {
x1: function(d) {
if (d4.isOrdinalScale(this.x)) {
return this.x(d[this.x.$key]);
} else {
return this.x(d.y0 + d.y);
}
},
y1: function(d) {
if (d4.isOrdinalScale(this.y)) {
return this.y(d[this.y.$key]);
} else {
return this.y(d.y0 + d.y);
}
},
size: function() {
if (d4.isOrdinalScale(this.x)) {
return this.x.rangeBand();
} else {
return this.y.rangeBand();
}
},
classes: function(d, i) {
return 'series' + i;
}
},
render: function(scope, data, selection) {
var group = d4.appendOnce(selection, 'g.' + name);
var connectorGroups = group.selectAll('g')
.data(data);
connectorGroups.enter().append('g')
.attr('class', function(d, i) {
return 'series' + i + ' ' + this.y.$key;
}.bind(this));
var lines = connectorGroups.selectAll('line')
.data(function(d) {
return d.values;
}.bind(this));
lines.enter().append('line');
lines
.attr('class', d4.functor(scope.accessors.classes).bind(this))
.attr('stroke-dasharray', '5, 5')
.attr('x1', function(d, i, n) {
return processPoint.bind(this)(d, i, n, data, function() {
return d4.functor(scope.accessors.x1).bind(this)(d);
});
}.bind(this))
.attr('y1', function(d, i, n) {
var offset = (d4.isOrdinalScale(this.y)) ? d4.functor(scope.accessors.size).bind(this)(d) : 0;
return processPoint.bind(this)(d, i, n, data, function() {
return d4.functor(scope.accessors.y1).bind(this)(d) + offset;
});
}.bind(this))
.attr('x2', function(d, i, n) {
var offset = (d4.isOrdinalScale(this.x)) ? scope.accessors.size.bind(this)(d) : 0;
return processPoint.bind(this)(d, i, n, data, function() {
return d4.functor(scope.accessors.x1).bind(this)(data[n].values[i - 1]) + offset;
});
}.bind(this))
.attr('y2', function(d, i, n) {
return processPoint.bind(this)(d, i, n, data, function() {
return d4.functor(scope.accessors.y1).bind(this)(data[n].values[i - 1]);
});
}.bind(this));
connectorGroups.exit().remove();
lines.exit().remove();
return lines;
}
};
});
}).call(this);