forked from tomgp/d3-ternary
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ternary.js
138 lines (119 loc) · 3.43 KB
/
ternary.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
'use strict';
if( !tgp ){ var tgp = {}; }
if( !tgp.d3 ){ tgp.d3 = {};}
tgp.d3.ternaryPlot = function(){
var ternary = {};
var height = Math.sqrt( 1*1 - (1/2)*(1/2));
var path;
function rescale(range){
if(!range.length) range = [0, 1];
ternary.scale = d3.scale.linear().domain([0, 1]).range(range);
}
function line(interpolator){
if(!interpolator) interpolator = 'linear'
path = d3.svg.line()
.x(function(d) { return d[0]; })
.y(function(d) { return d[1]; })
.interpolate(interpolator);
}
rescale([0, 400]);
line();
ternary.range = function(range){
rescale(range);
return ternary;
};
//map teranry coordinate [a, b, c] to an [x, y] position
ternary.point = function(coords){
var pos = [0,0];
var sum = d3.sum(coords);
if(sum !== 0) {
var normalized = coords.map( function(d){ return d/sum; } );
pos[0] = ternary.scale ( normalized[1] + normalized[2] / 2 );
pos[1] = ternary.scale ( height * normalized[0] + height * normalized[1] );
}
return pos;
};
//create an SVG path from a set of points
ternary.line = function(coordsList, accessor, interpolator){ //path generator wrapper
if(interpolator) line(interpolator)
if(!accessor) accessor = function(d){ return d; }
var positions = coordsList.map( function(d){
return ternary.point( accessor(d) );
});
return path(positions);
};
ternary.rule = function(value, axis){
var ends = [];
if(axis == 0){
ends = [
[value, 0, 100-value],
[value, 100-value, 0]
];
}else if(axis == 1){
ends = [
[0, value, 100-value],
[100-value, value, 0]
];
}else if(axis == 2){
ends = [
[0, 100-value, value],
[100-value, 0, value]
];
}
return ternary.line(ends);
}
// this inverse of point i.e. take an x,y positon and get the ternary coordinate
ternary.getValues = function(pos){ //NOTE! haven't checked if this works yet
pos = pos.map(ternary.scale.inverse);
var c = 1 - pos[1];
var b = pos[0] - c/2;
var a = y - b;
return [a, b, c];
};
return ternary;
}
tgp.d3.ternaryAxes = function(plot){
var axes = {};
var parent = d3.select('svg');
var defaultTicks = d3.range(0,101,25);
var ticks = [defaultTicks, defaultTicks, defaultTicks];
var minorTicks = [[],[],[]];
axes.draw = function(parentSelector){
if(parentSelector) parent = d3.select(parentSelector);
var minor = parent.append('g').attr('id','minor-ticks');
var major = parent.append('g').attr('id','major-ticks')
//minor ticks
for (i = 0; i<minorTicks.length; i++){
for (j = 0; j<minorTicks[i].length; j++){
minor.append('path').attr({
'class':'ternary-tick minor',
'd':plot.rule(minorTicks[i][j], i)
})
}
}
//major ticks
for (var i=0; i<ticks.length; i++){
for (var j=0; j<ticks[i].length; j++){
major.append('path').attr({
'class':'ternary-tick',
'd':plot.rule(ticks[i][j], i)
})
}
}
}
axes.ticks = function(tickArrays){ // an array containing 1 - 3 three arrays the first array will be copied over empty spaces at the end
if(!tickArrays) tickArrays = [defaultTicks,defaultTicks,defaultTicks];
if(!tickArrays[1]) tickArrays[1] = tickArrays[0];
if(!tickArrays[2]) tickArrays[2] = tickArrays[0];
ticks = tickArrays;
return axes;
}
axes.minorTicks = function(tickArrays){
if(!tickArrays) tickArrays = [[],[],[]];
if(!tickArrays[1]) tickArrays[1] = tickArrays[0];
if(!tickArrays[2]) tickArrays[2] = tickArrays[0];
minorTicks = tickArrays;
return axes;
}
return axes;
}