multi-line-chart.ts 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import type { Datum } from '@antv/ava';
  2. import { hasSubset } from '../advisor/utils';
  3. import type { ChartKnowledge, CustomChart, GetChartConfigProps, Specification } from '../types';
  4. import { findNominalField, findOrdinalField, getLineSize, processDateEncode, sortData } from './util';
  5. const MULTI_LINE_CHART = 'multi_line_chart';
  6. const getChartSpec = (data: GetChartConfigProps['data'], dataProps: GetChartConfigProps['dataProps']) => {
  7. const ordinalField = findOrdinalField(dataProps);
  8. const nominalField = findNominalField(dataProps);
  9. // 放宽折线图的 x 轴条件,优先选择 time, ordinal, nominal 类型,没有的话使用第一个字段作兜底
  10. const field4X = ordinalField ?? nominalField ?? dataProps[0];
  11. const remainFields = dataProps.filter(field => field.name !== field4X?.name);
  12. const field4Y = remainFields.filter(
  13. field => field.levelOfMeasurements && hasSubset(field.levelOfMeasurements, ['Interval']),
  14. ) ?? [remainFields[0]];
  15. const field4Nominal = remainFields
  16. .filter(field => !field4Y.find(y => y.name === field.name))
  17. .find(field => field.levelOfMeasurements && hasSubset(field.levelOfMeasurements, ['Nominal']));
  18. if (!field4X || !field4Y) return null;
  19. const spec: Specification = {
  20. type: 'view',
  21. autoFit: true,
  22. data: sortData({ data, chartType: MULTI_LINE_CHART, xField: field4X }),
  23. children: [],
  24. };
  25. field4Y.forEach(field => {
  26. const singleLine: Specification = {
  27. type: 'line',
  28. encode: {
  29. x: processDateEncode(field4X.name as string, dataProps),
  30. y: field.name,
  31. size: (datum: Datum) => getLineSize(datum, data, { field4Split: field4Nominal, field4X }),
  32. },
  33. legend: {
  34. size: false,
  35. },
  36. };
  37. if (field4Nominal) {
  38. singleLine.encode.color = field4Nominal.name;
  39. }
  40. spec.children.push(singleLine);
  41. });
  42. return spec;
  43. };
  44. const ckb: ChartKnowledge = {
  45. id: MULTI_LINE_CHART,
  46. name: 'multi_line_chart',
  47. alias: ['multi_line_chart'],
  48. family: ['LineCharts'],
  49. def: 'multi_line_chart uses lines with segments to show changes in data in a ordinal dimension',
  50. purpose: ['Comparison', 'Trend'],
  51. coord: ['Cartesian2D'],
  52. category: ['Statistic'],
  53. shape: ['Lines'],
  54. dataPres: [
  55. { minQty: 1, maxQty: 1, fieldConditions: ['Time', 'Ordinal'] },
  56. { minQty: 1, maxQty: '*', fieldConditions: ['Interval'] },
  57. { minQty: 0, maxQty: 1, fieldConditions: ['Nominal'] },
  58. ],
  59. channel: ['Color', 'Direction', 'Position'],
  60. recRate: 'Recommended',
  61. toSpec: getChartSpec,
  62. };
  63. /* 订制一个图表需要的所有参数 */
  64. export const multi_line_chart: CustomChart = {
  65. /* 图表唯一 Id */
  66. chartType: 'multi_line_chart',
  67. /* 图表知识 */
  68. chartKnowledge: ckb as ChartKnowledge,
  69. /** 图表中文名 */
  70. chineseName: '折线图',
  71. };
  72. export default multi_line_chart;