|
1 (function(){d3.csv = function(url, callback) { |
|
2 d3.text(url, "text/csv", function(text) { |
|
3 callback(text && d3.csv.parse(text)); |
|
4 }); |
|
5 }; |
|
6 d3.csv.parse = function(text) { |
|
7 var header; |
|
8 return d3.csv.parseRows(text, function(row, i) { |
|
9 if (i) { |
|
10 var o = {}, j = -1, m = header.length; |
|
11 while (++j < m) o[header[j]] = row[j]; |
|
12 return o; |
|
13 } else { |
|
14 header = row; |
|
15 return null; |
|
16 } |
|
17 }); |
|
18 }; |
|
19 |
|
20 d3.csv.parseRows = function(text, f) { |
|
21 var EOL = {}, // sentinel value for end-of-line |
|
22 EOF = {}, // sentinel value for end-of-file |
|
23 rows = [], // output rows |
|
24 re = /\r\n|[,\r\n]/g, // field separator regex |
|
25 n = 0, // the current line number |
|
26 t, // the current token |
|
27 eol; // is the current token followed by EOL? |
|
28 |
|
29 re.lastIndex = 0; // work-around bug in FF 3.6 |
|
30 |
|
31 /** @private Returns the next token. */ |
|
32 function token() { |
|
33 if (re.lastIndex >= text.length) return EOF; // special case: end of file |
|
34 if (eol) { eol = false; return EOL; } // special case: end of line |
|
35 |
|
36 // special case: quotes |
|
37 var j = re.lastIndex; |
|
38 if (text.charCodeAt(j) === 34) { |
|
39 var i = j; |
|
40 while (i++ < text.length) { |
|
41 if (text.charCodeAt(i) === 34) { |
|
42 if (text.charCodeAt(i + 1) !== 34) break; |
|
43 i++; |
|
44 } |
|
45 } |
|
46 re.lastIndex = i + 2; |
|
47 var c = text.charCodeAt(i + 1); |
|
48 if (c === 13) { |
|
49 eol = true; |
|
50 if (text.charCodeAt(i + 2) === 10) re.lastIndex++; |
|
51 } else if (c === 10) { |
|
52 eol = true; |
|
53 } |
|
54 return text.substring(j + 1, i).replace(/""/g, "\""); |
|
55 } |
|
56 |
|
57 // common case |
|
58 var m = re.exec(text); |
|
59 if (m) { |
|
60 eol = m[0].charCodeAt(0) !== 44; |
|
61 return text.substring(j, m.index); |
|
62 } |
|
63 re.lastIndex = text.length; |
|
64 return text.substring(j); |
|
65 } |
|
66 |
|
67 while ((t = token()) !== EOF) { |
|
68 var a = []; |
|
69 while ((t !== EOL) && (t !== EOF)) { |
|
70 a.push(t); |
|
71 t = token(); |
|
72 } |
|
73 if (f && !(a = f(a, n++))) continue; |
|
74 rows.push(a); |
|
75 } |
|
76 |
|
77 return rows; |
|
78 }; |
|
79 d3.csv.format = function(rows) { |
|
80 return rows.map(d3_csv_formatRow).join("\n"); |
|
81 }; |
|
82 |
|
83 function d3_csv_formatRow(row) { |
|
84 return row.map(d3_csv_formatValue).join(","); |
|
85 } |
|
86 |
|
87 function d3_csv_formatValue(text) { |
|
88 return /[",\n]/.test(text) |
|
89 ? "\"" + text.replace(/\"/g, "\"\"") + "\"" |
|
90 : text; |
|
91 } |
|
92 })(); |