billboard.js
Version:
Re-usable easy interface JavaScript chart library, based on D3 v4+
167 lines (166 loc) • 4.17 kB
JavaScript
/*!
* Copyright (c) 2017 ~ present NAVER Corp.
* billboard.js project is licensed under the MIT license
*
* billboard.js, JavaScript chart library
* https://naver.github.io/billboard.js/
*
* @version 4.1.1
*/
import { csvParse, csvParseRows, tsvParse, tsvParseRows } from "../../module/dsv.js";
//#region src/ChartInternal/data/convert.helper.ts
/**
* Copyright (c) 2017 ~ present NAVER Corp.
* billboard.js project is licensed under the MIT license
*/
/***** 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 = [];
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 = [];
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 = [];
let targetKeys;
let data;
if (Array.isArray(json)) {
const findValueInJson = function(object, path) {
if (object[path] !== void 0) return object[path];
const pathArray = path.replace(/\[(\w+)\]/g, ".$1").replace(/^\./, "").split(".");
let target = object;
pathArray.some(function(k) {
return !(target = target && typeof target === "object" && k in target ? target[k] : void 0);
});
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) {
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 = [].concat(json[key]);
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, mimeType = "csv", headers, keys, done) {
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: csvParseRows,
parse: csvParse
}, xsv);
}
function tsv(tsv) {
return convertCsvTsvToData({
rows: tsvParseRows,
parse: tsvParse
}, tsv);
}
//#endregion
export { columns, csv, json, rows, tsv, url };