forked from taliator/sparklines
-
Notifications
You must be signed in to change notification settings - Fork 0
/
svg.sparklines.js
150 lines (132 loc) · 4.79 KB
/
svg.sparklines.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
139
140
141
142
143
144
145
146
147
148
149
150
// Dependency on svg.js library
var sparklines = function sparklines ( el /*, aspectRatio */ ) {
var maxWidth = el.clientWidth;
var padding = 0;
var dataset = {
grid: el.getAttribute( 'data-grid' ),
scale: el.getAttribute( 'data-scale' ),
values: el.getAttribute( 'data-values' ),
dashed: el.getAttribute( 'data-dashed' )
};
var values = ( dataset.values )
? dataset.values
.split( ',' )
.map( function ( value ) {
return ( value ) ? parseFloat( value ) : 0;
})
: [];
var aspectRatio = arguments.length > 1
? arguments[ 1 ]
: false;
var gridSettings = dataset.grid;
// filled = el.classList.contains( 'sparkline-filled' ),
// grid = el.classList.contains( 'sparkline-grid' ),
// @TODO check for class inclusion to determine grid inclusion, allow for "x-only" and "y-only"
var plot, grid, path, scale, max, min, xStep, yStep, maxHeight, pathArray, y1, y2;
var buildGrid = function ( ) {
var xGridLine;
var yGridLine;
pathArray.forEach( function ( segment ) {
if ( gridSettings.indexOf( 'x' ) > - 1 ) {
xGridLine = plot.line(
segment[ 1 ],
padding,
segment[ 1 ],
maxHeight - padding );
xGridLine.addClass( 'grid' );
}
if ( gridSettings.indexOf( 'y' ) > - 1 ) {
yGridLine = plot.line(
padding,
segment[ 2 ],
maxWidth - ( padding * 2 ),
segment[ 2 ] );
yGridLine.addClass( 'grid' );
}
});
};
var calculateY = function ( y ) {
var aVal = maxHeight - ( 2 * padding );
var bVal = ( y - min ) / ( max - min );
return Math.round( aVal * bVal ) + padding;
};
var buildPathArray = function () {
var pathValues = values.map( function ( value, index ) {
var xValue = ( index * xStep ) + padding;
var yValue = calculateY( value );
return [ ( index == 0 ) ? 'M' : 'L', xValue, yValue ];
});
// @TODO
// if ( filled ) {
// pathString = 'M 0 ' + y1 + ' L ' + maxWidth + ' ' + ( y2 );
// }
return pathValues;
};
if ( ! values.length ) {
return;
}
// Figure out aspect ratio, if not passed in
if ( ! aspectRatio ) {
// Use the element height
if ( el.clientHeight > 0 ) {
aspectRatio = el.clientWidth / el.clientHeight;
}
// If the element has 0 height, check the parent
else if ( el.parentElement.clientHeight > 0 ) {
aspectRatio = el.clientWidth / el.parentElement.clientHeight;
}
// If we can't get a height, use a sensible default
else {
aspectRatio = 2.5;
}
}
maxHeight = Math.round( maxWidth / aspectRatio );
padding = maxHeight * 0.05;
// Get or calculate max and min Y values
if ( undefined !== dataset.scale ) {
scale = dataset.scale.split( ',' ).map(
function ( value ) {
return ( value ) ? parseFloat( value ) : 0;
});
min = scale[ 0 ];
max = scale[ 1 ];
}
else {
max = Math.max.apply( null, values );
min = Math.min.apply( null, values );
}
// Calculate the how far apart each X and Y point should be
xStep = Math.floor( ( maxWidth - ( 2 * padding ) ) / ( values.length - 1 ) );
yStep = ( maxHeight - ( 2 * padding ) - 1 ) / ( max - 1 );
// Build the SVG container
plot = SVG( el );
plot.viewbox( 0, 0, maxWidth, maxHeight )
.attr( 'preserveAspectRatio', 'none' )
.addClass( 'plot' );
// Check if we are building a path or a line
if ( values.length === 2 ) {
y1 = calculateY( values[ 0 ] ).toFixed( 2 );
y2 = calculateY( values[ 1 ] ).toFixed( 2 );
pathArray = [ [ 'M', padding, y1 ], [ 'L', maxWidth - ( padding * 2 ), y2 ] ];
}
else if ( values.length > 2 ) {
// Both the grid and plot need the path array
pathArray = buildPathArray( );
}
else {
y1 = calculateY( values[ 0 ] ).toFixed( 2 );
pathArray = [ [ 'M', padding, y1 ], [ 'L', maxWidth - ( padding * 2 ), y1 ] ];
}
// Build the grid lines first so they render under the plot
if ( gridSettings ) {
buildGrid();
}
path = plot.path( pathArray );
path.fill( 'none' )
.transform( { scaleX: 1, scaleY: -1 } )
.translate( 0, maxHeight )
.attr( 'stroke-linejoin', 'round' );
if ( dataset.dashed ) {
path.attr( 'stroke-dasharray', ( strokeWidth * 1.5 ) + '%, ' + ( strokeWidth * .75 ) + '%' );
}
};