├── LICENSE ├── README.md ├── bower.json ├── export-csv.js ├── manifest.json └── package.json /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2017 Highsoft 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecation notice 2 | Given the popularity of this plugin, it has been taken in as a Highcharts module since v5.0.11 (2017-05-04), and 3 | development continues in the [official Highcharts repo](https://github.com/highcharts/highcharts/). This 4 | means it can be loaded from [code.highcharts.com](https://code.highcharts.com/modules/export-data.js) and 5 | is available with the [Highcharts npm package](https://www.npmjs.com/package/highcharts). Issues should now 6 | be reported in the [Highcharts repo](https://github.com/highcharts/highcharts/issues). 7 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "highcharts-export-csv", 3 | "version": "1.4.8", 4 | "description": "Highcharts plugin to export the chart data to CSV, XLS or HTML table", 5 | "keywords": [ 6 | "export", 7 | "csv", 8 | "xls" 9 | ], 10 | "authors": [ 11 | { "name": "Torstein Hønsi", "homepage": "https://github.com/highslide-software" } 12 | ], 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/highcharts/export-csv" 16 | }, 17 | "main": "export-csv.js", 18 | "license": "MIT", 19 | "ignore": [ 20 | "**/.*", 21 | "README.md" 22 | ], 23 | "homepage": "http://www.highcharts.com/plugin-registry/single/7/Export-CSV" 24 | } 25 | -------------------------------------------------------------------------------- /export-csv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A Highcharts plugin for exporting data from a rendered chart as CSV, XLS or HTML table 3 | * 4 | * Author: Torstein Honsi 5 | * Licence: MIT 6 | * Version: 1.4.8 7 | */ 8 | /*global Highcharts, window, document, Blob */ 9 | (function (factory) { 10 | if (typeof module === 'object' && module.exports) { 11 | module.exports = factory; 12 | } else { 13 | factory(Highcharts); 14 | } 15 | })(function (Highcharts) { 16 | 17 | 'use strict'; 18 | 19 | var each = Highcharts.each, 20 | pick = Highcharts.pick, 21 | seriesTypes = Highcharts.seriesTypes, 22 | downloadAttrSupported = document.createElement('a').download !== undefined; 23 | 24 | Highcharts.setOptions({ 25 | lang: { 26 | downloadCSV: 'Download CSV', 27 | downloadXLS: 'Download XLS', 28 | viewData: 'View data table' 29 | } 30 | }); 31 | 32 | 33 | /** 34 | * Get the data rows as a two dimensional array 35 | */ 36 | Highcharts.Chart.prototype.getDataRows = function () { 37 | var options = (this.options.exporting || {}).csv || {}, 38 | xAxis, 39 | xAxes = this.xAxis, 40 | rows = {}, 41 | rowArr = [], 42 | dataRows, 43 | names = [], 44 | i, 45 | x, 46 | xTitle, 47 | // Options 48 | dateFormat = options.dateFormat || '%Y-%m-%d %H:%M:%S', 49 | columnHeaderFormatter = options.columnHeaderFormatter || function (item, key, keyLength) { 50 | if (item instanceof Highcharts.Axis) { 51 | return (item.options.title && item.options.title.text) || 52 | (item.isDatetimeAxis ? 'DateTime' : 'Category'); 53 | } 54 | return item ? 55 | item.name + (keyLength > 1 ? ' ('+ key + ')' : '') : 56 | 'Category'; 57 | }, 58 | xAxisIndices = []; 59 | 60 | // Loop the series and index values 61 | i = 0; 62 | each(this.series, function (series) { 63 | var keys = series.options.keys, 64 | pointArrayMap = keys || series.pointArrayMap || ['y'], 65 | valueCount = pointArrayMap.length, 66 | requireSorting = series.requireSorting, 67 | categoryMap = {}, 68 | xAxisIndex = Highcharts.inArray(series.xAxis, xAxes), 69 | j; 70 | 71 | // Map the categories for value axes 72 | each(pointArrayMap, function (prop) { 73 | categoryMap[prop] = (series[prop + 'Axis'] && series[prop + 'Axis'].categories) || []; 74 | }); 75 | 76 | if (series.options.includeInCSVExport !== false && series.visible !== false) { // #55 77 | 78 | // Build a lookup for X axis index and the position of the first 79 | // series that belongs to that X axis. Includes -1 for non-axis 80 | // series types like pies. 81 | if (!Highcharts.find(xAxisIndices, function (index) { 82 | return index[0] === xAxisIndex; 83 | })) { 84 | xAxisIndices.push([xAxisIndex, i]); 85 | } 86 | 87 | // Add the column headers, usually the same as series names 88 | j = 0; 89 | while (j < valueCount) { 90 | names.push(columnHeaderFormatter(series, pointArrayMap[j], pointArrayMap.length)); 91 | j = j + 1; 92 | } 93 | 94 | each(series.points, function (point, pIdx) { 95 | var key = requireSorting ? point.x : pIdx, 96 | prop, 97 | val; 98 | 99 | j = 0; 100 | 101 | if (!rows[key]) { 102 | // Generate the row 103 | rows[key] = []; 104 | // Contain the X values from one or more X axes 105 | rows[key].xValues = []; 106 | } 107 | rows[key].x = point.x; 108 | rows[key].xValues[xAxisIndex] = point.x; 109 | 110 | // Pies, funnels, geo maps etc. use point name in X row 111 | if (!series.xAxis || series.exportKey === 'name') { 112 | rows[key].name = point.name; 113 | } 114 | 115 | while (j < valueCount) { 116 | prop = pointArrayMap[j]; // y, z etc 117 | val = point[prop]; 118 | rows[key][i + j] = pick(categoryMap[prop][val], val); // Pick a Y axis category if present 119 | j = j + 1; 120 | } 121 | 122 | }); 123 | i = i + j; 124 | } 125 | }); 126 | 127 | // Make a sortable array 128 | for (x in rows) { 129 | if (rows.hasOwnProperty(x)) { 130 | rowArr.push(rows[x]); 131 | } 132 | } 133 | 134 | var binding, xAxisIndex, column; 135 | dataRows = [names]; 136 | 137 | i = xAxisIndices.length; 138 | while (i--) { // Start from end to splice in 139 | xAxisIndex = xAxisIndices[i][0]; 140 | column = xAxisIndices[i][1]; 141 | xAxis = xAxes[xAxisIndex]; 142 | 143 | // Sort it by X values 144 | rowArr.sort(function (a, b) { 145 | return a.xValues[xAxisIndex] - b.xValues[xAxisIndex]; 146 | }); 147 | 148 | // Add header row 149 | xTitle = columnHeaderFormatter(xAxis); 150 | //dataRows = [[xTitle].concat(names)]; 151 | dataRows[0].splice(column, 0, xTitle); 152 | 153 | // Add the category column 154 | each(rowArr, function (row) { 155 | 156 | var category = row.name; 157 | if (!category) { 158 | if (xAxis.isDatetimeAxis) { 159 | if (row.x instanceof Date) { 160 | row.x = row.x.getTime(); 161 | } 162 | category = Highcharts.dateFormat(dateFormat, row.x); 163 | } else if (xAxis.categories) { 164 | category = pick( 165 | xAxis.names[row.x], 166 | xAxis.categories[row.x], 167 | row.x 168 | ) 169 | } else { 170 | category = row.x; 171 | } 172 | } 173 | 174 | // Add the X/date/category 175 | row.splice(column, 0, category); 176 | }); 177 | } 178 | dataRows = dataRows.concat(rowArr); 179 | 180 | return dataRows; 181 | }; 182 | 183 | /** 184 | * Get a CSV string 185 | */ 186 | Highcharts.Chart.prototype.getCSV = function (useLocalDecimalPoint) { 187 | var csv = '', 188 | rows = this.getDataRows(), 189 | options = (this.options.exporting || {}).csv || {}, 190 | itemDelimiter = options.itemDelimiter || ',', // use ';' for direct import to Excel 191 | lineDelimiter = options.lineDelimiter || '\n'; // '\n' isn't working with the js csv data extraction 192 | 193 | // Transform the rows to CSV 194 | each(rows, function (row, i) { 195 | var val = '', 196 | j = row.length, 197 | n = useLocalDecimalPoint ? (1.1).toLocaleString()[1] : '.'; 198 | while (j--) { 199 | val = row[j]; 200 | if (typeof val === "string") { 201 | val = '"' + val + '"'; 202 | } 203 | if (typeof val === 'number') { 204 | if (n === ',') { 205 | val = val.toString().replace(".", ","); 206 | } 207 | } 208 | row[j] = val; 209 | } 210 | // Add the values 211 | csv += row.join(itemDelimiter); 212 | 213 | // Add the line delimiter 214 | if (i < rows.length - 1) { 215 | csv += lineDelimiter; 216 | } 217 | }); 218 | return csv; 219 | }; 220 | 221 | /** 222 | * Build a HTML table with the data 223 | */ 224 | Highcharts.Chart.prototype.getTable = function (useLocalDecimalPoint) { 225 | var html = '', 226 | rows = this.getDataRows(); 227 | 228 | // Transform the rows to HTML 229 | each(rows, function (row, i) { 230 | var tag = i ? 'td' : 'th', 231 | val, 232 | j, 233 | n = useLocalDecimalPoint ? (1.1).toLocaleString()[1] : '.'; 234 | 235 | html += ''; 236 | for (j = 0; j < row.length; j = j + 1) { 237 | val = row[j]; 238 | // Add the cell 239 | if (typeof val === 'number') { 240 | val = val.toString(); 241 | if (n === ',') { 242 | val = val.replace('.', n); 243 | } 244 | html += '<' + tag + ' class="number">' + val + ''; 245 | 246 | } else { 247 | html += '<' + tag + '>' + (val === undefined ? '' : val) + ''; 248 | } 249 | } 250 | 251 | html += ''; 252 | 253 | // After the first row, end head and start body 254 | if (!i) { 255 | html += ''; 256 | } 257 | 258 | }); 259 | html += '
'; 260 | 261 | return html; 262 | }; 263 | 264 | function getContent(chart, href, extension, content, MIME) { 265 | var a, 266 | blobObject, 267 | name, 268 | options = (chart.options.exporting || {}).csv || {}, 269 | url = options.url || 'http://www.highcharts.com/studies/csv-export/download.php'; 270 | 271 | if (chart.options.exporting.filename) { 272 | name = chart.options.exporting.filename; 273 | } else if (chart.title) { 274 | name = chart.title.textStr.replace(/ /g, '-').toLowerCase(); 275 | } else { 276 | name = 'chart'; 277 | } 278 | 279 | // MS specific. Check this first because of bug with Edge (#76) 280 | if (window.Blob && window.navigator.msSaveOrOpenBlob) { 281 | // Falls to msSaveOrOpenBlob if download attribute is not supported 282 | blobObject = new Blob([content]); 283 | window.navigator.msSaveOrOpenBlob(blobObject, name + '.' + extension); 284 | 285 | // Download attribute supported 286 | } else if (downloadAttrSupported) { 287 | a = document.createElement('a'); 288 | a.href = href; 289 | a.download = name + '.' + extension; 290 | chart.container.append(a); // #111 291 | a.click(); 292 | a.remove(); 293 | 294 | } else { 295 | // Fall back to server side handling 296 | Highcharts.post(url, { 297 | data: content, 298 | type: MIME, 299 | extension: extension 300 | }); 301 | } 302 | } 303 | 304 | /** 305 | * Call this on click of 'Download CSV' button 306 | */ 307 | Highcharts.Chart.prototype.downloadCSV = function () { 308 | var csv = this.getCSV(true); 309 | getContent( 310 | this, 311 | 'data:text/csv,\uFEFF' + encodeURIComponent(csv), 312 | 'csv', 313 | csv, 314 | 'text/csv' 315 | ); 316 | }; 317 | 318 | /** 319 | * Call this on click of 'Download XLS' button 320 | */ 321 | Highcharts.Chart.prototype.downloadXLS = function () { 322 | var uri = 'data:application/vnd.ms-excel;base64,', 323 | template = '' + 324 | '' + 327 | '' + 328 | '' + 329 | '' + 330 | '' + 331 | this.getTable(true) + 332 | '', 333 | base64 = function (s) { 334 | return window.btoa(unescape(encodeURIComponent(s))); // #50 335 | }; 336 | getContent( 337 | this, 338 | uri + base64(template), 339 | 'xls', 340 | template, 341 | 'application/vnd.ms-excel' 342 | ); 343 | }; 344 | 345 | /** 346 | * View the data in a table below the chart 347 | */ 348 | Highcharts.Chart.prototype.viewData = function () { 349 | if (!this.dataTableDiv) { 350 | this.dataTableDiv = document.createElement('div'); 351 | this.dataTableDiv.className = 'highcharts-data-table'; 352 | 353 | // Insert after the chart container 354 | this.renderTo.parentNode.insertBefore( 355 | this.dataTableDiv, 356 | this.renderTo.nextSibling 357 | ); 358 | } 359 | 360 | this.dataTableDiv.innerHTML = this.getTable(); 361 | }; 362 | 363 | 364 | // Add "Download CSV" to the exporting menu. Use download attribute if supported, else 365 | // run a simple PHP script that returns a file. The source code for the PHP script can be viewed at 366 | // https://raw.github.com/highslide-software/highcharts.com/master/studies/csv-export/csv.php 367 | if (Highcharts.getOptions().exporting) { 368 | Highcharts.getOptions().exporting.buttons.contextButton.menuItems.push({ 369 | textKey: 'downloadCSV', 370 | onclick: function () { this.downloadCSV(); } 371 | }, { 372 | textKey: 'downloadXLS', 373 | onclick: function () { this.downloadXLS(); } 374 | }, { 375 | textKey: 'viewData', 376 | onclick: function () { this.viewData(); } 377 | }); 378 | } 379 | 380 | // Series specific 381 | if (seriesTypes.map) { 382 | seriesTypes.map.prototype.exportKey = 'name'; 383 | } 384 | if (seriesTypes.mapbubble) { 385 | seriesTypes.mapbubble.prototype.exportKey = 'name'; 386 | } 387 | if (seriesTypes.treemap) { 388 | seriesTypes.treemap.prototype.exportKey = 'name'; 389 | } 390 | 391 | }); 392 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Export Data", 3 | "version": "1.4.8", 4 | "title": "Export chart data to CSV, XLS, HTML or JS array", 5 | "demo": [ 6 | "http://jsfiddle.net/highcharts/cqjvD/", 7 | "http://jsfiddle.net/highcharts/2Jyn5/" 8 | ], 9 | "author": { 10 | "name": "Torstein Hønsi", 11 | "url": "https://github.com/highslide-software" 12 | }, 13 | "maintainers": [ 14 | { 15 | "name": "Torgrim Thorsen", 16 | "url": "https://github.com/SirAlexiner", 17 | "email": "Sir_Alexiner@hotmail.com" 18 | } 19 | ], 20 | "licenses": [ 21 | { 22 | "type": "MIT", 23 | "url": "https://github.com/highslide-software/export-csv/blob/master/LICENSE" 24 | } 25 | ], 26 | "description": "Highcharts plugin to export the chart data to CSV, XLS or HTML table.", 27 | "keywords": [ 28 | "export", 29 | "csv", 30 | "xls" 31 | ], 32 | "dependencies": { 33 | "Highcharts": ">=3.0.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "highcharts-export-csv", 3 | "version": "1.4.8", 4 | "description": "Highcharts plugin to export the chart data to CSV, XLS or HTML table", 5 | "keywords": [ 6 | "export", 7 | "csv", 8 | "xls" 9 | ], 10 | "main": "export-csv.js", 11 | "author": { 12 | "name": "Torstein Hønsi", 13 | "url": "https://github.com/highslide-software" 14 | }, 15 | "contributors": [ 16 | { 17 | "name": "Torgrim Thorsen", 18 | "url": "https://github.com/SirAlexiner", 19 | "email": "Sir_Alexiner@hotmail.com" 20 | } 21 | ], 22 | "repository": { 23 | "type": "git", 24 | "url": "https://github.com/highcharts/export-csv" 25 | }, 26 | "peerDependencies": { 27 | "highcharts": ">=5.0.6" 28 | }, 29 | "license": "MIT", 30 | "bugs": { 31 | "url": "https://github.com/highcharts/export-csv/issues" 32 | }, 33 | "homepage": "http://www.highcharts.com/plugin-registry/single/7/Export-CSV" 34 | } 35 | --------------------------------------------------------------------------------