util.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import type { Datum, FieldInfo } from '@antv/ava';
  2. import { cloneDeep, uniq } from 'lodash';
  3. import { hasSubset, intersects } from '../advisor/utils';
  4. /**
  5. * Process date column to new Date().
  6. * @param field
  7. * @param dataProps
  8. * @returns
  9. */
  10. export function processDateEncode(field: string, dataProps: FieldInfo[]) {
  11. const dp = dataProps.find(dataProp => dataProp.name === field);
  12. if (dp?.recommendation === 'date') {
  13. return (d: any) => new Date(d[field]);
  14. }
  15. return field;
  16. }
  17. export function findOrdinalField(fields: FieldInfo[]) {
  18. return fields.find(field => field.levelOfMeasurements && intersects(field.levelOfMeasurements, ['Time', 'Ordinal']));
  19. }
  20. export function findNominalField(fields: FieldInfo[]) {
  21. return fields.find(field => field.levelOfMeasurements && hasSubset(field.levelOfMeasurements, ['Nominal']));
  22. }
  23. // 识别 x 轴是否只有一条数据(绘制的折线图是否只有一个点)
  24. export const isUniqueXValue = ({ data, xField }: { xField: string; data: Datum[] }): boolean => {
  25. const uniqXValues = uniq(data.map(datum => datum[xField]));
  26. return uniqXValues.length <= 1;
  27. };
  28. /** 获取线宽:当只有一条数据时,折线图需要特殊设置线宽,否则仅绘制 1px,看不见 */
  29. export const getLineSize = (
  30. datum: Datum,
  31. allData: Datum[],
  32. fields: {
  33. field4Split?: FieldInfo;
  34. field4X?: FieldInfo;
  35. },
  36. ) => {
  37. const { field4Split, field4X } = fields;
  38. if (field4Split?.name && field4X?.name) {
  39. const seriesValue = datum[field4Split.name];
  40. const splitData = allData.filter(item => field4Split.name && item[field4Split.name] === seriesValue);
  41. return isUniqueXValue({ data: splitData, xField: field4X.name }) ? 5 : undefined;
  42. }
  43. return field4X?.name && isUniqueXValue({ data: allData, xField: field4X.name }) ? 5 : undefined;
  44. };
  45. export const sortData = ({ data, chartType, xField }: { data: Datum[]; xField?: FieldInfo; chartType: string }) => {
  46. const sortedData = cloneDeep(data);
  47. try {
  48. // 折线图绘制需要将数据点按照日期从小到大的顺序排序和连线
  49. if (chartType.includes('line') && xField?.name && xField.recommendation === 'date') {
  50. sortedData.sort(
  51. (datum1, datum2) =>
  52. new Date(datum1[xField.name as string]).getTime() - new Date(datum2[xField.name as string]).getTime(),
  53. );
  54. return sortedData;
  55. }
  56. // 如果折线图横轴是数值类型,则按照数值大小排序
  57. if (chartType.includes('line') && xField?.name && ['float', 'integer'].includes(xField.recommendation)) {
  58. sortedData.sort(
  59. (datum1, datum2) => (datum1[xField.name as string] as number) - (datum2[xField.name as string] as number),
  60. );
  61. return sortedData;
  62. }
  63. } catch (err) {
  64. console.error(err);
  65. }
  66. return sortedData;
  67. };
  68. /** 数据空值处理:后端返回的空数据为 '-', 在展示为图表时会有问题,修改为 null */
  69. export const processNilData = (data: Datum[], emptyValue = '-') =>
  70. data.map(datum => {
  71. const processedDatum: Record<string, string | number | null> = {};
  72. Object.keys(datum).forEach(key => {
  73. processedDatum[key] = datum[key] === emptyValue ? null : datum[key];
  74. });
  75. return processedDatum;
  76. });