billboard.js
Version:
Re-usable easy interface JavaScript chart library, based on D3 v4+
225 lines (183 loc) • 4.43 kB
text/typescript
/**
* Copyright (c) 2017 ~ present NAVER Corp.
* billboard.js project is licensed under the MIT license
*/
/* eslint-disable */
import {
csvParse as d3CsvParse,
csvParseRows as d3CsvParseRows,
tsvParse as d3TsvParse,
tsvParseRows as d3TsvParseRows
} from "d3-dsv";
export {columns, csv, json, rows, tsv, url};
/***** Functions to be executed on Web Worker *****
* NOTE: Don't allowed to use
* - arrow function syntax
* - Utils functions
*/
/**
* Convert Columns data
* @param {object} columns
* @returns {Array}
* @private
*/
function columns(columns) {
const newRows: any[] = [];
columns.forEach(function(col, i) {
const key = col[0];
col.forEach(function(v, j) {
if (j > 0) {
if (typeof newRows[j - 1] === "undefined") {
newRows[j - 1] = {};
}
if (typeof v === "undefined") {
throw new Error(`Source data is missing a component at (${i}, ${j})!`);
}
newRows[j - 1][key] = v;
}
});
});
return newRows;
}
/**
* Convert Rows data
* @param {object} columns
* @returns {Array}
* @private
*/
function rows(rows) {
const keys = rows[0];
const newRows: any[] = [];
rows.forEach(function(row, i) {
if (i > 0) {
const newRow = {};
row.forEach(function(v, j) {
if (typeof v === "undefined") {
throw new Error(`Source data is missing a component at (${i}, ${j})!`);
}
newRow[keys[j]] = v;
});
newRows.push(newRow);
}
});
return newRows;
}
/**
* Convert JSON data
* @param {object} columns
* @returns {Array}
* @private
*/
function json(json, keysParam) {
const newRows: string[][] = [];
let targetKeys: string[];
let data;
if (Array.isArray(json)) {
const findValueInJson = function(object, path) {
if (object[path] !== undefined) {
return object[path];
}
const convertedPath = path.replace(/\[(\w+)\]/g, ".$1"); // convert indexes to properties (replace [] with .)
const pathArray = convertedPath.replace(/^\./, "").split("."); // strip a leading dot
let target = object;
pathArray.some(function(k) {
return !(
target = target && k in target ? target[k] : undefined
);
});
return target;
};
if (keysParam.x) {
targetKeys = keysParam.value.concat(keysParam.x);
} else {
targetKeys = keysParam.value;
}
newRows.push(targetKeys);
json.forEach(function(o) {
const newRow = targetKeys.map(function(key) {
// convert undefined to null because undefined data will be removed in convertDataToTargets()
let v = findValueInJson(o, key);
if (typeof v === "undefined") {
v = null;
}
return v;
});
newRows.push(newRow);
});
data = rows(newRows);
} else {
Object.keys(json).forEach(function(key) {
const tmp = json[key].concat();
tmp.unshift?.(key);
newRows.push(tmp);
});
data = columns(newRows);
}
return data;
}
/***** Functions can't be executed on Web Worker *****/
/**
* Convert URL data
* @param {string} url Remote URL
* @param {string} mimeType MIME type string: json | csv | tsv
* @param {object} headers Header object
* @param {object} keys Key object
* @param {Function} done Callback function
* @private
*/
function url(url: string, mimeType = "csv", headers: object, keys: object, done: Function): void {
const req = new XMLHttpRequest();
const converter = {csv, tsv, json};
req.open("GET", url);
if (headers) {
Object.keys(headers).forEach(function(key) {
req.setRequestHeader(key, headers[key]);
});
}
req.onreadystatechange = function() {
if (req.readyState === 4) {
if (req.status === 200) {
const response = req.responseText;
response && done.call(this, converter[mimeType](
mimeType === "json" ? JSON.parse(response) : response,
keys
));
} else {
throw new Error(`${url}: Something went wrong loading!`);
}
}
};
req.send();
}
/**
* Convert CSV/TSV data
* @param {object} parser Parser object
* @param {object} xsv Data
* @returns {object}
* @private
*/
function convertCsvTsvToData(parser, xsv) {
const rows = parser.rows(xsv);
let d;
if (rows.length === 1) {
d = [{}];
rows[0].forEach(id => {
d[0][id] = null;
});
} else {
d = parser.parse(xsv);
}
return d;
}
function csv(xsv) {
return convertCsvTsvToData({
rows: d3CsvParseRows,
parse: d3CsvParse
}, xsv);
}
function tsv(tsv) {
return convertCsvTsvToData({
rows: d3TsvParseRows,
parse: d3TsvParse
}, tsv);
}