UNPKG

d2recharts

Version:

data driven react components of echarts

230 lines (214 loc) 5.64 kB
'use strict'; /** * data-set module * @module data-set * @see module:index */ const _ = require('lodash'); const try2get = require('try2get'); const Connector = require('../connector/base'); const util = require('../util/index'); function isValidDataSet(dataSet) { /** * Simply check the data structure of the data set. * @function isValidDataSet * @param {Array} data * @return {Boolean} * @example * // a valid data structure should be like this: * // `schema` is not strictly required. * { * data: [ * {genre: 'Sports', sold: 275}, * {genre: 'Strategy', sold: 115}, * {genre: 'Action', sold: 120}, * {genre: 'Shooter', sold: 350}, * {genre: 'Other', sold: 150} * ], * schema: [ * {name: 'genre', comments: '种类'}, * {name: 'sold', comments: '销量', formatter: '', type: 'number'} * ] * } * @example * isValidDataSet(dataSet); */ if (!_.isPlainObject(dataSet)) { return false; } const data = dataSet.data; if (!_.isArray(data)) { return false; } if (data.length && _.some(data, row => !_.isPlainObject(row))) { return false; } for (let i = 1; i < data.length; i++) { if (data[i] && !util.containsSameItems(_.keys(data[i]), _.keys(data[i - 1]))) { return false; } } return true; } class DataSet { constructor(source) { source = source || []; const me = this; if (source.constructor === me.constructor) { return source; } if (_.isArray(source)) { return new DataSet({ data: source, }); } if (!isValidDataSet(source)) { throw new TypeError('new DataSet(source): invalid data set'); } me.data = source.data; me.schema = source.schema || []; return me.processData(); } processData() { const me = this; const data = me.data; /* * schema info of every column: * [ * { * name, * index, * comments, * } * ] */ if (!me.schema.length) { if (data.length) { const keys = _.keys(data[0]); me.schema = _.map(keys, (name, index) => ({ index, name, })); } } // comments (default is name) _.each(me.schema, (colInfo) => { if (!_.has(colInfo, 'comments')) { colInfo.comments = colInfo.displayName || colInfo.name; } }); // 整理schema和data const currentSchemaNames = _.map(me.schema, item => item.name); _.each(me.data, (row) => { _.forIn(row, (value, key) => { if (!_.includes(currentSchemaNames, key)) { // 补全schema me.schema.push({ name: key, comments: key, index: currentSchemaNames.length, }); currentSchemaNames.push(key); } }); }); _.each(me.data, (row) => { _.each(currentSchemaNames, (name) => { if (!_.has(row, name)) { // 补全data row[name] = ''; } }); }); // flatten rows me.flattenRows = _.map(me.data, (row) => { const resultRow = []; _.each(me.schema, (colInfo, index) => { colInfo.index = index; resultRow.push(row[colInfo.name]); }); return resultRow; }); // colValuesByName me.colValuesByName = {}; _.each(me.data, (row) => { _.forIn(row, (value, key) => { me.colValuesByName[key] = me.colValuesByName[key] || []; me.colValuesByName[key].push(value); }); }); // type (by guessing or pre-defined) // colNames by type // col by name // cols by type // unique column values rate me.colNamesByType = { string: [], number: [], }; me.colsByType = {}; me.colByName = {}; _.each(me.schema, (colInfo) => { const name = colInfo.name; const colValues = me.colValuesByName[name]; colInfo.values = colValues; // add values const type = colInfo.type = colInfo.type || util.guessItemsTypes(colValues); if (!me.colNamesByType[type]) { me.colNamesByType[type] = []; } if (!me.colsByType[type]) { me.colsByType[type] = []; } if (colValues.length) { colInfo.uniqueRate = _.uniq(colValues).length / colValues.length; } else { colInfo.uniqueRate = 0; } me.colNamesByType[type].push(colInfo.name); me.colsByType[type].push(colInfo); me.colByName[colInfo.name] = colInfo; }); // alias me.cols = me.schema; // rows and cols info me.rowsCount = data.length; me.colsCount = me.cols.length; return me; } isEmpty() { const me = this; if (me.rowsCount === 0 && me.colsCount === 0) { return true; } return false; } } // connectors const connectors = []; _.assign(DataSet, { registerConnector(connector) { if (connector instanceof Connector) { connectors.push(connector); } else { try { connectors.push(new Connector(connector)); } catch (e) { } } connectors.sort((a, b) => (b.priority - a.priority)); }, registerConnectors(cs) { _.each(cs, (connector) => { DataSet.registerConnector(connector); }); }, try2init(source) { // the default DataSet is an empty DataSet return try2get.one(_.map(connectors, connector => () => connector.toDataSet(source))); }, }); require('../connector/csv')(DataSet); require('../connector/default')(DataSet); require('../connector/flatten-data')(DataSet); require('../connector/mock')(DataSet); module.exports = DataSet;