Quite good looking graph derived from d3.js http://c3js.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

248 lines
8.4 KiB

import { c3_chart_internal_fn } from './core';
import { isValue, isUndefined, isDefined, notEmpty } from './util';
c3_chart_internal_fn.convertUrlToData = function (url, mimeType, headers, keys, done) {
var $$ = this, type = mimeType ? mimeType : 'csv';
var req = $$.d3.request(url);
if (headers) {
Object.keys(headers).forEach(function (header) {
req.header(header, headers[header]);
});
}
req.get(function (error, data) {
var d;
var dataResponse = data.response || data.responseText; // Fixes IE9 XHR issue; see #1345
if (!data) {
throw new Error(error.responseURL + ' ' + error.status + ' (' + error.statusText + ')');
}
if (type === 'json') {
d = $$.convertJsonToData(JSON.parse(dataResponse), keys);
} else if (type === 'tsv') {
d = $$.convertTsvToData(dataResponse);
} else {
d = $$.convertCsvToData(dataResponse);
}
done.call($$, d);
});
};
c3_chart_internal_fn.convertXsvToData = function (xsv, parser) {
var rows = parser(xsv), d;
if (rows.length === 1) {
d = [{}];
rows[0].forEach(function (id) {
d[0][id] = null;
});
} else {
d = parser(xsv);
}
return d;
};
c3_chart_internal_fn.convertCsvToData = function (csv) {
return this.convertXsvToData(csv, this.d3.csvParse);
};
c3_chart_internal_fn.convertTsvToData = function (tsv) {
return this.convertXsvToData(tsv, this.d3.tsvParse);
};
c3_chart_internal_fn.convertJsonToData = function (json, keys) {
var $$ = this,
new_rows = [], targetKeys, data;
if (keys) { // when keys specified, json would be an array that includes objects
if (keys.x) {
targetKeys = keys.value.concat(keys.x);
$$.config.data_x = keys.x;
} else {
targetKeys = keys.value;
}
new_rows.push(targetKeys);
json.forEach(function (o) {
var new_row = [];
targetKeys.forEach(function (key) {
// convert undefined to null because undefined data will be removed in convertDataToTargets()
var v = $$.findValueInJson(o, key);
if (isUndefined(v)) {
v = null;
}
new_row.push(v);
});
new_rows.push(new_row);
});
data = $$.convertRowsToData(new_rows);
} else {
Object.keys(json).forEach(function (key) {
new_rows.push([key].concat(json[key]));
});
data = $$.convertColumnsToData(new_rows);
}
return data;
};
c3_chart_internal_fn.findValueInJson = function (object, path) {
path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties (replace [] with .)
path = path.replace(/^\./, ''); // strip a leading dot
var pathArray = path.split('.');
for (var i = 0; i < pathArray.length; ++i) {
var k = pathArray[i];
if (k in object) {
object = object[k];
} else {
return;
}
}
return object;
};
/**
* Converts the rows to normalized data.
* @param {any[][]} rows The row data
* @return {Object[]}
*/
c3_chart_internal_fn.convertRowsToData = (rows) => {
const newRows = [];
const keys = rows[0];
for (let i = 1; i < rows.length; i++) {
const newRow = {};
for (let j = 0; j < rows[i].length; j++) {
if (isUndefined(rows[i][j])) {
throw new Error("Source data is missing a component at (" + i + "," + j + ")!");
}
newRow[keys[j]] = rows[i][j];
}
newRows.push(newRow);
}
return newRows;
};
/**
* Converts the columns to normalized data.
* @param {any[][]} columns The column data
* @return {Object[]}
*/
c3_chart_internal_fn.convertColumnsToData = (columns) => {
const newRows = [];
for (let i = 0; i < columns.length; i++) {
const key = columns[i][0];
for (let j = 1; j < columns[i].length; j++) {
if (isUndefined(newRows[j - 1])) {
newRows[j - 1] = {};
}
if (isUndefined(columns[i][j])) {
throw new Error("Source data is missing a component at (" + i + "," + j + ")!");
}
newRows[j - 1][key] = columns[i][j];
}
}
return newRows;
};
c3_chart_internal_fn.convertDataToTargets = function (data, appendXs) {
var $$ = this, config = $$.config,
ids = $$.d3.keys(data[0]).filter($$.isNotX, $$),
xs = $$.d3.keys(data[0]).filter($$.isX, $$),
targets;
// save x for update data by load when custom x and c3.x API
ids.forEach(function (id) {
var xKey = $$.getXKey(id);
if ($$.isCustomX() || $$.isTimeSeries()) {
// if included in input data
if (xs.indexOf(xKey) >= 0) {
$$.data.xs[id] = (appendXs && $$.data.xs[id] ? $$.data.xs[id] : []).concat(
data.map(function (d) { return d[xKey]; })
.filter(isValue)
.map(function (rawX, i) { return $$.generateTargetX(rawX, id, i); })
);
}
// if not included in input data, find from preloaded data of other id's x
else if (config.data_x) {
$$.data.xs[id] = $$.getOtherTargetXs();
}
// if not included in input data, find from preloaded data
else if (notEmpty(config.data_xs)) {
$$.data.xs[id] = $$.getXValuesOfXKey(xKey, $$.data.targets);
}
// MEMO: if no x included, use same x of current will be used
} else {
$$.data.xs[id] = data.map(function (d, i) { return i; });
}
});
// check x is defined
ids.forEach(function (id) {
if (!$$.data.xs[id]) {
throw new Error('x is not defined for id = "' + id + '".');
}
});
// convert to target
targets = ids.map(function (id, index) {
var convertedId = config.data_idConverter(id);
return {
id: convertedId,
id_org: id,
values: data.map(function (d, i) {
var xKey = $$.getXKey(id), rawX = d[xKey],
value = d[id] !== null && !isNaN(d[id]) ? +d[id] : null, x;
// use x as categories if custom x and categorized
if ($$.isCustomX() && $$.isCategorized() && !isUndefined(rawX)) {
if (index === 0 && i === 0) {
config.axis_x_categories = [];
}
x = config.axis_x_categories.indexOf(rawX);
if (x === -1) {
x = config.axis_x_categories.length;
config.axis_x_categories.push(rawX);
}
} else {
x = $$.generateTargetX(rawX, id, i);
}
// mark as x = undefined if value is undefined and filter to remove after mapped
if (isUndefined(d[id]) || $$.data.xs[id].length <= i) {
x = undefined;
}
return {x: x, value: value, id: convertedId};
}).filter(function (v) { return isDefined(v.x); })
};
});
// finish targets
targets.forEach(function (t) {
var i;
// sort values by its x
if (config.data_xSort) {
t.values = t.values.sort(function (v1, v2) {
var x1 = v1.x || v1.x === 0 ? v1.x : Infinity,
x2 = v2.x || v2.x === 0 ? v2.x : Infinity;
return x1 - x2;
});
}
// indexing each value
i = 0;
t.values.forEach(function (v) {
v.index = i++;
});
// this needs to be sorted because its index and value.index is identical
$$.data.xs[t.id].sort(function (v1, v2) {
return v1 - v2;
});
});
// cache information about values
$$.hasNegativeValue = $$.hasNegativeValueInTargets(targets);
$$.hasPositiveValue = $$.hasPositiveValueInTargets(targets);
// set target types
if (config.data_type) {
$$.setTargetType($$.mapToIds(targets).filter(function (id) { return ! (id in config.data_types); }), config.data_type);
}
// cache as original id keyed
targets.forEach(function (d) {
$$.addCache(d.id_org, d);
});
return targets;
};