@visactor/vseed 0.4.16 → 0.4.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,35 @@
1
1
  import { FoldMeasureId } from "../../../../../dataReshape/constant.js";
2
+ const reverseStackCornerRadius = (cornerRadius)=>{
3
+ if (!Array.isArray(cornerRadius)) return cornerRadius;
4
+ const [topLeft = 0, topRight = 0, bottomRight = 0, bottomLeft = 0] = cornerRadius;
5
+ return [
6
+ bottomRight,
7
+ bottomLeft,
8
+ topLeft,
9
+ topRight
10
+ ];
11
+ };
12
+ const mergeStackCornerRadius = (cornerRadius)=>{
13
+ if (!Array.isArray(cornerRadius)) return cornerRadius;
14
+ const [topLeft = 0, topRight = 0, bottomRight = 0, bottomLeft = 0] = cornerRadius;
15
+ return [
16
+ Math.max(topLeft, bottomRight),
17
+ Math.max(topRight, bottomLeft),
18
+ Math.max(bottomRight, topLeft),
19
+ Math.max(bottomLeft, topRight)
20
+ ];
21
+ };
22
+ const getStackRangeCornerRadius = (cornerRadius, datum)=>{
23
+ const stackStart = datum?.['__VCHART_STACK_START'];
24
+ const stackEnd = datum?.['__VCHART_STACK_END'];
25
+ if ('number' != typeof stackStart || 'number' != typeof stackEnd) return;
26
+ const hasPositivePart = stackStart > 0 || stackEnd > 0;
27
+ const hasNegativePart = stackStart < 0 || stackEnd < 0;
28
+ if (hasPositivePart && hasNegativePart) return mergeStackCornerRadius(cornerRadius);
29
+ if (hasPositivePart) return cornerRadius;
30
+ if (hasNegativePart) return reverseStackCornerRadius(cornerRadius);
31
+ return 0;
32
+ };
2
33
  const stackCornerRadius_stackCornerRadius = (spec, context)=>{
3
34
  const { advancedVSeed, vseed } = context;
4
35
  const { chartType } = vseed;
@@ -7,7 +38,11 @@ const stackCornerRadius_stackCornerRadius = (spec, context)=>{
7
38
  return {
8
39
  ...spec,
9
40
  stackCornerRadius: (_, datum)=>{
10
- if (datum && datum[datum[FoldMeasureId]] > 0) return stackCornerRadius;
41
+ const stackRangeCornerRadius = getStackRangeCornerRadius(stackCornerRadius, datum);
42
+ if (void 0 !== stackRangeCornerRadius) return stackRangeCornerRadius;
43
+ const value = datum?.[datum?.[FoldMeasureId]];
44
+ if (value > 0) return stackCornerRadius;
45
+ if (value < 0) return reverseStackCornerRadius(stackCornerRadius);
11
46
  return 0;
12
47
  }
13
48
  };
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline/spec/chart/pipes/stack/stackCornerRadius.js","sources":["webpack://@visactor/vseed/./src/pipeline/spec/chart/pipes/stack/stackCornerRadius.ts"],"sourcesContent":["import type { IBarChartSpec } from '@visactor/vchart'\nimport { FoldMeasureId } from 'src/dataReshape/constant'\nimport type { Datum, VChartSpecPipe, StackCornerRadius } from 'src/types'\n\nexport const stackCornerRadius: VChartSpecPipe = (spec, context) => {\n const { advancedVSeed, vseed } = context\n const { chartType } = vseed\n const stackCornerRadius = advancedVSeed.config?.[chartType as 'column']?.stackCornerRadius as StackCornerRadius\n\n if (chartType === 'dualAxis' && (spec as any).type !== 'bar') {\n return spec\n }\n\n return {\n ...spec,\n stackCornerRadius: (_: unknown, datum: Datum) => {\n if (datum && datum[datum[FoldMeasureId]] > 0) {\n return stackCornerRadius\n }\n\n return 0\n },\n } as IBarChartSpec\n}\n"],"names":["stackCornerRadius","spec","context","advancedVSeed","vseed","chartType","_","datum","FoldMeasureId"],"mappings":";AAIO,MAAMA,sCAAoC,CAACC,MAAMC;IACtD,MAAM,EAAEC,aAAa,EAAEC,KAAK,EAAE,GAAGF;IACjC,MAAM,EAAEG,SAAS,EAAE,GAAGD;IACtB,MAAMJ,oBAAoBG,cAAc,MAAM,EAAE,CAACE,UAAsB,EAAE;IAEzE,IAAIA,AAAc,eAAdA,aAA6BJ,AAAsB,UAAtBA,KAAa,IAAI,EAChD,OAAOA;IAGT,OAAO;QACL,GAAGA,IAAI;QACP,mBAAmB,CAACK,GAAYC;YAC9B,IAAIA,SAASA,KAAK,CAACA,KAAK,CAACC,cAAc,CAAC,GAAG,GACzC,OAAOR;YAGT,OAAO;QACT;IACF;AACF"}
1
+ {"version":3,"file":"pipeline/spec/chart/pipes/stack/stackCornerRadius.js","sources":["webpack://@visactor/vseed/./src/pipeline/spec/chart/pipes/stack/stackCornerRadius.ts"],"sourcesContent":["import type { IBarChartSpec } from '@visactor/vchart'\nimport { FoldMeasureId } from 'src/dataReshape/constant'\nimport type { Datum, VChartSpecPipe, StackCornerRadius } from 'src/types'\n\nconst reverseStackCornerRadius = (cornerRadius: StackCornerRadius): StackCornerRadius => {\n if (!Array.isArray(cornerRadius)) {\n return cornerRadius\n }\n\n const [topLeft = 0, topRight = 0, bottomRight = 0, bottomLeft = 0] = cornerRadius\n\n return [bottomRight, bottomLeft, topLeft, topRight]\n}\n\nconst mergeStackCornerRadius = (cornerRadius: StackCornerRadius): StackCornerRadius => {\n if (!Array.isArray(cornerRadius)) {\n return cornerRadius\n }\n\n const [topLeft = 0, topRight = 0, bottomRight = 0, bottomLeft = 0] = cornerRadius\n\n return [\n Math.max(topLeft, bottomRight),\n Math.max(topRight, bottomLeft),\n Math.max(bottomRight, topLeft),\n Math.max(bottomLeft, topRight),\n ]\n}\n\nconst getStackRangeCornerRadius = (\n cornerRadius: StackCornerRadius,\n datum: Datum,\n): StackCornerRadius | 0 | undefined => {\n const stackStart = datum?.['__VCHART_STACK_START']\n const stackEnd = datum?.['__VCHART_STACK_END']\n\n if (typeof stackStart !== 'number' || typeof stackEnd !== 'number') {\n return undefined\n }\n\n const hasPositivePart = stackStart > 0 || stackEnd > 0\n const hasNegativePart = stackStart < 0 || stackEnd < 0\n\n if (hasPositivePart && hasNegativePart) {\n // Mixed positive/negative stack range: merge normal/reverse corners for whole-bar style.\n return mergeStackCornerRadius(cornerRadius)\n }\n\n if (hasPositivePart) {\n return cornerRadius\n }\n\n if (hasNegativePart) {\n return reverseStackCornerRadius(cornerRadius)\n }\n\n return 0\n}\n\nexport const stackCornerRadius: VChartSpecPipe = (spec, context) => {\n const { advancedVSeed, vseed } = context\n const { chartType } = vseed\n const stackCornerRadius = advancedVSeed.config?.[chartType as 'column']?.stackCornerRadius as StackCornerRadius\n\n if (chartType === 'dualAxis' && (spec as any).type !== 'bar') {\n return spec\n }\n\n return {\n ...spec,\n stackCornerRadius: (_: unknown, datum: Datum) => {\n const stackRangeCornerRadius = getStackRangeCornerRadius(stackCornerRadius, datum)\n\n if (stackRangeCornerRadius !== undefined) {\n return stackRangeCornerRadius\n }\n\n const value = datum?.[datum?.[FoldMeasureId]]\n\n if (value > 0) {\n return stackCornerRadius\n }\n\n if (value < 0) {\n return reverseStackCornerRadius(stackCornerRadius)\n }\n\n return 0\n },\n } as IBarChartSpec\n}\n"],"names":["reverseStackCornerRadius","cornerRadius","Array","topLeft","topRight","bottomRight","bottomLeft","mergeStackCornerRadius","Math","getStackRangeCornerRadius","datum","stackStart","stackEnd","hasPositivePart","hasNegativePart","stackCornerRadius","spec","context","advancedVSeed","vseed","chartType","_","stackRangeCornerRadius","undefined","value","FoldMeasureId"],"mappings":";AAIA,MAAMA,2BAA2B,CAACC;IAChC,IAAI,CAACC,MAAM,OAAO,CAACD,eACjB,OAAOA;IAGT,MAAM,CAACE,UAAU,CAAC,EAAEC,WAAW,CAAC,EAAEC,cAAc,CAAC,EAAEC,aAAa,CAAC,CAAC,GAAGL;IAErE,OAAO;QAACI;QAAaC;QAAYH;QAASC;KAAS;AACrD;AAEA,MAAMG,yBAAyB,CAACN;IAC9B,IAAI,CAACC,MAAM,OAAO,CAACD,eACjB,OAAOA;IAGT,MAAM,CAACE,UAAU,CAAC,EAAEC,WAAW,CAAC,EAAEC,cAAc,CAAC,EAAEC,aAAa,CAAC,CAAC,GAAGL;IAErE,OAAO;QACLO,KAAK,GAAG,CAACL,SAASE;QAClBG,KAAK,GAAG,CAACJ,UAAUE;QACnBE,KAAK,GAAG,CAACH,aAAaF;QACtBK,KAAK,GAAG,CAACF,YAAYF;KACtB;AACH;AAEA,MAAMK,4BAA4B,CAChCR,cACAS;IAEA,MAAMC,aAAaD,OAAO,CAAC,uBAAuB;IAClD,MAAME,WAAWF,OAAO,CAAC,qBAAqB;IAE9C,IAAI,AAAsB,YAAtB,OAAOC,cAA2B,AAAoB,YAApB,OAAOC,UAC3C;IAGF,MAAMC,kBAAkBF,aAAa,KAAKC,WAAW;IACrD,MAAME,kBAAkBH,aAAa,KAAKC,WAAW;IAErD,IAAIC,mBAAmBC,iBAErB,OAAOP,uBAAuBN;IAGhC,IAAIY,iBACF,OAAOZ;IAGT,IAAIa,iBACF,OAAOd,yBAAyBC;IAGlC,OAAO;AACT;AAEO,MAAMc,sCAAoC,CAACC,MAAMC;IACtD,MAAM,EAAEC,aAAa,EAAEC,KAAK,EAAE,GAAGF;IACjC,MAAM,EAAEG,SAAS,EAAE,GAAGD;IACtB,MAAMJ,oBAAoBG,cAAc,MAAM,EAAE,CAACE,UAAsB,EAAE;IAEzE,IAAIA,AAAc,eAAdA,aAA6BJ,AAAsB,UAAtBA,KAAa,IAAI,EAChD,OAAOA;IAGT,OAAO;QACL,GAAGA,IAAI;QACP,mBAAmB,CAACK,GAAYX;YAC9B,MAAMY,yBAAyBb,0BAA0BM,mBAAmBL;YAE5E,IAAIY,AAA2BC,WAA3BD,wBACF,OAAOA;YAGT,MAAME,QAAQd,OAAO,CAACA,OAAO,CAACe,cAAc,CAAC;YAE7C,IAAID,QAAQ,GACV,OAAOT;YAGT,IAAIS,QAAQ,GACV,OAAOxB,yBAAyBe;YAGlC,OAAO;QACT;IACF;AACF"}
@@ -1,4 +1,4 @@
1
- import type { BodyCellStyle, Datum } from '../../../../../types';
1
+ import type { BodyCellStyle, Datum, TotalType } from '../../../../../types';
2
2
  /**
3
3
  * 计算线性颜色映射(使用 tinycolor2)
4
4
  * @param value 实际值
@@ -16,7 +16,7 @@ export declare const pickBodyCellStyle: (bodyCellStyle: BodyCellStyle) => Record
16
16
  /**
17
17
  * 计算数据列的最小值和最大值
18
18
  */
19
- export declare const getColumnMinMax: (allData: Datum[], field: string) => {
19
+ export declare const getColumnMinMax: (allData: Datum[], field: string, totalAggregation?: TotalType) => {
20
20
  min: number;
21
21
  max: number;
22
22
  };
@@ -24,19 +24,46 @@ const pickBodyCellStyle = (bodyCellStyle)=>Object.keys(tableStyleMap).reduce((ac
24
24
  if (key in bodyCellStyle) acc[tableStyleMap[key]] = bodyCellStyle[key];
25
25
  return acc;
26
26
  }, {});
27
- const getColumnMinMax = (allData, field)=>{
27
+ const getColumnMinMax = (allData, field, totalAggregation)=>{
28
28
  let min = 1 / 0;
29
29
  let max = -1 / 0;
30
+ let sum = 0;
31
+ let count = 0;
32
+ const hasTotal = !!totalAggregation;
33
+ const aggregationType = 'string' == typeof totalAggregation ? totalAggregation : 'sum';
30
34
  for (const datum of allData){
31
35
  const value = Number(datum[field]);
32
36
  if (!Number.isNaN(value)) {
33
37
  min = Math.min(min, value);
34
38
  max = Math.max(max, value);
39
+ sum += value;
40
+ count += 1;
35
41
  }
36
42
  }
43
+ const baseMin = min === 1 / 0 ? 0 : min;
44
+ const baseMax = max === -1 / 0 ? 0 : max;
45
+ if (!hasTotal) return {
46
+ min: baseMin,
47
+ max: baseMax
48
+ };
49
+ const total = (()=>{
50
+ switch(aggregationType){
51
+ case 'avg':
52
+ return count ? sum / count : 0;
53
+ case 'max':
54
+ return baseMax;
55
+ case 'min':
56
+ return baseMin;
57
+ case 'count':
58
+ return count;
59
+ case 'sum':
60
+ default:
61
+ return sum;
62
+ }
63
+ })();
37
64
  return {
38
- min: min === 1 / 0 ? 0 : min,
39
- max: max === -1 / 0 ? 0 : max
65
+ min: Math.min(baseMin, total),
66
+ max: Math.max(baseMax, total)
40
67
  };
41
68
  };
42
69
  const applyColorScale = (value, scale)=>{
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline/spec/table/pipes/cellStyle/common.js","sources":["webpack://@visactor/vseed/./src/pipeline/spec/table/pipes/cellStyle/common.ts"],"sourcesContent":["import { isArray, isNullish } from 'remeda'\nimport tinycolor from 'tinycolor2'\nimport { InnerRowIndex } from 'src/dataReshape'\nimport type { BodyCellStyle, Datum } from 'src/types'\n\nconst tableStyleMap = {\n backgroundColor: 'bgColor',\n textColor: 'color',\n textFontSize: 'fontSize',\n borderColor: 'borderColor',\n borderLineWidth: 'borderLineWidth',\n barPositiveColor: 'barPositiveColor',\n barNegativeColor: 'barNegativeColor',\n}\n\n/**\n * 计算线性颜色映射(使用 tinycolor2)\n * @param value 实际值\n * @param minValue 最小值\n * @param maxValue 最大值\n * @param minColor 最小值颜色\n * @param maxColor 最大值颜色\n * @returns RGB 颜色字符串\n */\nexport const interpolateColor = (\n value: number,\n minValue: number,\n maxValue: number,\n minColor: string,\n maxColor: string,\n): string => {\n const startColor = tinycolor(minColor).toRgb()\n const endColor = tinycolor(maxColor).toRgb()\n\n // 归一化值到 [0, 1]\n const normalized = (value - minValue) / (maxValue - minValue)\n const t = Math.max(0, Math.min(1, normalized))\n\n // 线性插值\n const r = Math.round(startColor.r + (endColor.r - startColor.r) * t)\n const g = Math.round(startColor.g + (endColor.g - startColor.g) * t)\n const b = Math.round(startColor.b + (endColor.b - startColor.b) * t)\n\n return `rgb(${r}, ${g}, ${b})`\n}\n\n/**\n * 从 bodyCellStyle 提取要应用到单元格的样式\n */\nexport const pickBodyCellStyle = (bodyCellStyle: BodyCellStyle) => {\n return (Object.keys(tableStyleMap) as Array<keyof typeof tableStyleMap>).reduce<Record<string, any>>((acc, key) => {\n if (key in bodyCellStyle) {\n acc[tableStyleMap[key]] = bodyCellStyle[key]\n }\n\n return acc\n }, {})\n}\n\n/**\n * 计算数据列的最小值和最大值\n */\nexport const getColumnMinMax = (allData: Datum[], field: string): { min: number; max: number } => {\n let min = Infinity\n let max = -Infinity\n\n for (const datum of allData) {\n const value = Number(datum[field])\n if (!Number.isNaN(value)) {\n min = Math.min(min, value)\n max = Math.max(max, value)\n }\n }\n\n return {\n min: min === Infinity ? 0 : min,\n max: max === -Infinity ? 0 : max,\n }\n}\n\n/**\n * 应用 scale 颜色映射\n */\nexport const applyColorScale = (\n value: any,\n scale: { minValue: number; maxValue: number; minColor: string; maxColor: string } | undefined,\n): string | undefined => {\n if (!scale) return undefined\n\n const numValue = Number(value)\n if (Number.isNaN(numValue) || isNullish(value)) return undefined\n\n const minValue = scale.minValue\n const maxValue = scale.maxValue\n\n if (minValue === maxValue) {\n return scale.minColor\n }\n\n return interpolateColor(numValue, minValue, maxValue, scale.minColor, scale.maxColor)\n}\n\nexport const getCellOriginalDataByDatum = (datum: any, hasDynamicFilter: boolean, originalDatum: Datum) => {\n const tableInstance = datum?.table\n let originRowData =\n tableInstance && hasDynamicFilter ? tableInstance?.getCellOriginRecord(datum?.col, datum?.row) : null\n if (originRowData && isArray(originRowData)) {\n originRowData = originRowData[0]\n }\n return originRowData\n ? {\n ...originalDatum,\n [InnerRowIndex]: originRowData?.[InnerRowIndex], // 内部行号字段\n }\n : null\n}\n"],"names":["tableStyleMap","interpolateColor","value","minValue","maxValue","minColor","maxColor","startColor","tinycolor","endColor","normalized","t","Math","r","g","b","pickBodyCellStyle","bodyCellStyle","Object","acc","key","getColumnMinMax","allData","field","min","Infinity","max","datum","Number","applyColorScale","scale","numValue","isNullish","getCellOriginalDataByDatum","hasDynamicFilter","originalDatum","tableInstance","originRowData","isArray","InnerRowIndex"],"mappings":";;;AAKA,MAAMA,gBAAgB;IACpB,iBAAiB;IACjB,WAAW;IACX,cAAc;IACd,aAAa;IACb,iBAAiB;IACjB,kBAAkB;IAClB,kBAAkB;AACpB;AAWO,MAAMC,mBAAmB,CAC9BC,OACAC,UACAC,UACAC,UACAC;IAEA,MAAMC,aAAaC,WAAUH,UAAU,KAAK;IAC5C,MAAMI,WAAWD,WAAUF,UAAU,KAAK;IAG1C,MAAMI,aAAcR,AAAAA,CAAAA,QAAQC,QAAO,IAAMC,CAAAA,WAAWD,QAAO;IAC3D,MAAMQ,IAAIC,KAAK,GAAG,CAAC,GAAGA,KAAK,GAAG,CAAC,GAAGF;IAGlC,MAAMG,IAAID,KAAK,KAAK,CAACL,WAAW,CAAC,GAAIE,AAAAA,CAAAA,SAAS,CAAC,GAAGF,WAAW,CAAC,AAAD,IAAKI;IAClE,MAAMG,IAAIF,KAAK,KAAK,CAACL,WAAW,CAAC,GAAIE,AAAAA,CAAAA,SAAS,CAAC,GAAGF,WAAW,CAAC,AAAD,IAAKI;IAClE,MAAMI,IAAIH,KAAK,KAAK,CAACL,WAAW,CAAC,GAAIE,AAAAA,CAAAA,SAAS,CAAC,GAAGF,WAAW,CAAC,AAAD,IAAKI;IAElE,OAAO,CAAC,IAAI,EAAEE,EAAE,EAAE,EAAEC,EAAE,EAAE,EAAEC,EAAE,CAAC,CAAC;AAChC;AAKO,MAAMC,oBAAoB,CAACC,gBACxBC,OAAO,IAAI,CAAClB,eAAqD,MAAM,CAAsB,CAACmB,KAAKC;QACzG,IAAIA,OAAOH,eACTE,GAAG,CAACnB,aAAa,CAACoB,IAAI,CAAC,GAAGH,aAAa,CAACG,IAAI;QAG9C,OAAOD;IACT,GAAG,CAAC;AAMC,MAAME,kBAAkB,CAACC,SAAkBC;IAChD,IAAIC,MAAMC;IACV,IAAIC,MAAM,CAACD;IAEX,KAAK,MAAME,SAASL,QAAS;QAC3B,MAAMpB,QAAQ0B,OAAOD,KAAK,CAACJ,MAAM;QACjC,IAAI,CAACK,OAAO,KAAK,CAAC1B,QAAQ;YACxBsB,MAAMZ,KAAK,GAAG,CAACY,KAAKtB;YACpBwB,MAAMd,KAAK,GAAG,CAACc,KAAKxB;QACtB;IACF;IAEA,OAAO;QACL,KAAKsB,QAAQC,QAAW,IAAID;QAC5B,KAAKE,QAAQ,CAACD,QAAW,IAAIC;IAC/B;AACF;AAKO,MAAMG,kBAAkB,CAC7B3B,OACA4B;IAEA,IAAI,CAACA,OAAO;IAEZ,MAAMC,WAAWH,OAAO1B;IACxB,IAAI0B,OAAO,KAAK,CAACG,aAAaC,UAAU9B,QAAQ;IAEhD,MAAMC,WAAW2B,MAAM,QAAQ;IAC/B,MAAM1B,WAAW0B,MAAM,QAAQ;IAE/B,IAAI3B,aAAaC,UACf,OAAO0B,MAAM,QAAQ;IAGvB,OAAO7B,iBAAiB8B,UAAU5B,UAAUC,UAAU0B,MAAM,QAAQ,EAAEA,MAAM,QAAQ;AACtF;AAEO,MAAMG,6BAA6B,CAACN,OAAYO,kBAA2BC;IAChF,MAAMC,gBAAgBT,OAAO;IAC7B,IAAIU,gBACFD,iBAAiBF,mBAAmBE,eAAe,oBAAoBT,OAAO,KAAKA,OAAO,OAAO;IACnG,IAAIU,iBAAiBC,QAAQD,gBAC3BA,gBAAgBA,aAAa,CAAC,EAAE;IAElC,OAAOA,gBACH;QACE,GAAGF,aAAa;QAChB,CAACI,cAAc,EAAEF,eAAe,CAACE,cAAc;IACjD,IACA;AACN"}
1
+ {"version":3,"file":"pipeline/spec/table/pipes/cellStyle/common.js","sources":["webpack://@visactor/vseed/./src/pipeline/spec/table/pipes/cellStyle/common.ts"],"sourcesContent":["import { isArray, isNullish } from 'remeda'\nimport tinycolor from 'tinycolor2'\nimport { InnerRowIndex } from 'src/dataReshape'\nimport type { BodyCellStyle, Datum, TotalType } from 'src/types'\n\nconst tableStyleMap = {\n backgroundColor: 'bgColor',\n textColor: 'color',\n textFontSize: 'fontSize',\n borderColor: 'borderColor',\n borderLineWidth: 'borderLineWidth',\n barPositiveColor: 'barPositiveColor',\n barNegativeColor: 'barNegativeColor',\n}\n\n/**\n * 计算线性颜色映射(使用 tinycolor2)\n * @param value 实际值\n * @param minValue 最小值\n * @param maxValue 最大值\n * @param minColor 最小值颜色\n * @param maxColor 最大值颜色\n * @returns RGB 颜色字符串\n */\nexport const interpolateColor = (\n value: number,\n minValue: number,\n maxValue: number,\n minColor: string,\n maxColor: string,\n): string => {\n const startColor = tinycolor(minColor).toRgb()\n const endColor = tinycolor(maxColor).toRgb()\n\n // 归一化值到 [0, 1]\n const normalized = (value - minValue) / (maxValue - minValue)\n const t = Math.max(0, Math.min(1, normalized))\n\n // 线性插值\n const r = Math.round(startColor.r + (endColor.r - startColor.r) * t)\n const g = Math.round(startColor.g + (endColor.g - startColor.g) * t)\n const b = Math.round(startColor.b + (endColor.b - startColor.b) * t)\n\n return `rgb(${r}, ${g}, ${b})`\n}\n\n/**\n * 从 bodyCellStyle 提取要应用到单元格的样式\n */\nexport const pickBodyCellStyle = (bodyCellStyle: BodyCellStyle) => {\n return (Object.keys(tableStyleMap) as Array<keyof typeof tableStyleMap>).reduce<Record<string, any>>((acc, key) => {\n if (key in bodyCellStyle) {\n acc[tableStyleMap[key]] = bodyCellStyle[key]\n }\n\n return acc\n }, {})\n}\n\n/**\n * 计算数据列的最小值和最大值\n */\nexport const getColumnMinMax = (\n allData: Datum[],\n field: string,\n totalAggregation?: TotalType,\n): { min: number; max: number } => {\n let min = Infinity\n let max = -Infinity\n let sum = 0\n let count = 0\n\n const hasTotal = !!totalAggregation\n const aggregationType: TotalType = typeof totalAggregation === 'string' ? totalAggregation : 'sum'\n\n for (const datum of allData) {\n const value = Number(datum[field])\n if (!Number.isNaN(value)) {\n min = Math.min(min, value)\n max = Math.max(max, value)\n sum += value\n count += 1\n }\n }\n\n const baseMin = min === Infinity ? 0 : min\n const baseMax = max === -Infinity ? 0 : max\n\n if (!hasTotal) {\n return {\n min: baseMin,\n max: baseMax,\n }\n }\n\n const total = (() => {\n switch (aggregationType) {\n case 'avg':\n return count ? sum / count : 0\n case 'max':\n return baseMax\n case 'min':\n return baseMin\n case 'count':\n return count\n case 'sum':\n default:\n return sum\n }\n })()\n\n return {\n min: Math.min(baseMin, total),\n max: Math.max(baseMax, total),\n }\n}\n\n/**\n * 应用 scale 颜色映射\n */\nexport const applyColorScale = (\n value: any,\n scale: { minValue: number; maxValue: number; minColor: string; maxColor: string } | undefined,\n): string | undefined => {\n if (!scale) return undefined\n\n const numValue = Number(value)\n if (Number.isNaN(numValue) || isNullish(value)) return undefined\n\n const minValue = scale.minValue\n const maxValue = scale.maxValue\n\n if (minValue === maxValue) {\n return scale.minColor\n }\n\n return interpolateColor(numValue, minValue, maxValue, scale.minColor, scale.maxColor)\n}\n\nexport const getCellOriginalDataByDatum = (datum: any, hasDynamicFilter: boolean, originalDatum: Datum) => {\n const tableInstance = datum?.table\n let originRowData =\n tableInstance && hasDynamicFilter ? tableInstance?.getCellOriginRecord(datum?.col, datum?.row) : null\n if (originRowData && isArray(originRowData)) {\n originRowData = originRowData[0]\n }\n return originRowData\n ? {\n ...originalDatum,\n [InnerRowIndex]: originRowData?.[InnerRowIndex], // 内部行号字段\n }\n : null\n}\n"],"names":["tableStyleMap","interpolateColor","value","minValue","maxValue","minColor","maxColor","startColor","tinycolor","endColor","normalized","t","Math","r","g","b","pickBodyCellStyle","bodyCellStyle","Object","acc","key","getColumnMinMax","allData","field","totalAggregation","min","Infinity","max","sum","count","hasTotal","aggregationType","datum","Number","baseMin","baseMax","total","applyColorScale","scale","numValue","isNullish","getCellOriginalDataByDatum","hasDynamicFilter","originalDatum","tableInstance","originRowData","isArray","InnerRowIndex"],"mappings":"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"}
@@ -2,6 +2,16 @@ import { array } from "@visactor/vutils";
2
2
  import { isString } from "remeda";
3
3
  import { matchesFieldSelector, selector, selectorWithDynamicFilter } from "../../../../../dataSelector/selector.js";
4
4
  import { applyColorScale, getCellOriginalDataByDatum, getColumnMinMax, pickBodyCellStyle } from "./common.js";
5
+ const isPivotTotalCell = (styleArg)=>{
6
+ const cellHeaderPaths = styleArg?.cellHeaderPaths;
7
+ if (!cellHeaderPaths) return false;
8
+ if ('sub-total' === cellHeaderPaths.role || 'grand-total' === cellHeaderPaths.role) return true;
9
+ const headerPaths = [
10
+ ...cellHeaderPaths.colHeaderPaths || [],
11
+ ...cellHeaderPaths.rowHeaderPaths || []
12
+ ];
13
+ return headerPaths.some((path)=>path?.role === 'sub-total' || path?.role === 'grand-total');
14
+ };
5
15
  const pivotTableBodyCell = (spec, context)=>{
6
16
  const { advancedVSeed } = context;
7
17
  const { cellStyle, config, chartType } = advancedVSeed;
@@ -70,6 +80,7 @@ const pivotTableBodyCell = (spec, context)=>{
70
80
  cellStyle.barMarkWidth = themeConfig?.barMarkWidth;
71
81
  cellStyle.barPadding = themeConfig?.barPadding;
72
82
  cellStyle.barRightToLeft = themeConfig?.barRightToLeft;
83
+ cellStyle.showBar = !isPivotTotalCell(datum);
73
84
  }
74
85
  return {
75
86
  ...result,
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline/spec/table/pipes/cellStyle/pivot.js","sources":["webpack://@visactor/vseed/./src/pipeline/spec/table/pipes/cellStyle/pivot.ts"],"sourcesContent":["import type { IIndicator, PivotTableConstructorOptions } from '@visactor/vtable'\nimport { array } from '@visactor/vutils'\nimport { isString } from 'remeda'\nimport { matchesFieldSelector, selector, selectorWithDynamicFilter } from 'src/dataSelector/selector'\nimport type { BodyCellStyle, Datum, PivotTableSpecPipe, TableConfig } from 'src/types'\nimport type { FieldSelector } from 'src/types/dataSelector'\nimport { getCellOriginalDataByDatum, pickBodyCellStyle, applyColorScale, getColumnMinMax } from './common'\nimport type { IProgressbarColumnIndicator } from '@visactor/vtable/es/ts-types/pivot-table/indicator/progress-indicator'\n\nexport const pivotTableBodyCell: PivotTableSpecPipe = (spec, context) => {\n const { advancedVSeed } = context\n const { cellStyle, config, chartType } = advancedVSeed\n const bodyCellStyle = cellStyle?.bodyCellStyle\n const themeConfig = config?.[chartType] as TableConfig\n\n if (!bodyCellStyle) {\n return spec as PivotTableConstructorOptions\n }\n const bodyCellStyleList = array(bodyCellStyle) as BodyCellStyle[]\n const indicators = (spec as PivotTableConstructorOptions).indicators || []\n const selectedPos: { col: number; row: number }[] = []\n const hasDynamicFilter = bodyCellStyleList.some((style) => !!style.dynamicFilter)\n const allData = advancedVSeed.dataset || []\n\n const newIndicators = indicators.map((ind) => {\n const newInd = isString(ind)\n ? ({\n indicatorKey: ind,\n } as IIndicator)\n : ind\n\n const { indicatorKey } = newInd\n\n // 前置处理:检查是否需要 progressBar 或 backgroundColorScale\n const progressBarStyle = bodyCellStyleList\n .filter(\n (s) => s.enableProgressBar && s?.selector && matchesFieldSelector(indicatorKey, s.selector as FieldSelector),\n )\n .pop()\n const backgroundColorScale = bodyCellStyleList.find(\n (s) =>\n s.enableBackgroundColorScale && s?.selector && matchesFieldSelector(indicatorKey, s.selector as FieldSelector),\n )\n let columnMin: number\n let columnMax: number\n\n if (progressBarStyle || backgroundColorScale) {\n const { min, max } = getColumnMinMax(allData, indicatorKey)\n columnMin = min\n columnMax = max\n if (progressBarStyle) {\n newInd.cellType = 'progressbar'\n ;(newInd as IProgressbarColumnIndicator).barType = 'negative'\n ;(newInd as IProgressbarColumnIndicator).min = progressBarStyle.barMin ?? columnMin\n ;(newInd as IProgressbarColumnIndicator).max = progressBarStyle.barMax ?? columnMax\n }\n }\n\n newInd.style = (datum: any) => {\n const { dataValue, cellHeaderPaths } = datum\n const headerPaths = [...cellHeaderPaths.colHeaderPaths, ...cellHeaderPaths.rowHeaderPaths]\n\n const originalDatum: Datum = {\n [indicatorKey]: dataValue,\n }\n\n headerPaths.forEach((path: any) => {\n if (path.dimensionKey) {\n originalDatum[path.dimensionKey] = path.value\n }\n })\n\n const currentCellData = getCellOriginalDataByDatum(datum, hasDynamicFilter, originalDatum)\n\n const mergedStyle = bodyCellStyleList.reduce<Record<string, any>>((result, style) => {\n const shouldApply = style.dynamicFilter\n ? selectorWithDynamicFilter(currentCellData || originalDatum, style.dynamicFilter, style.selector)\n : selector(originalDatum, style.selector)\n if (shouldApply) {\n if (selectedPos.length && selectedPos[0].col === datum?.col && selectedPos[0].row === datum?.row) {\n selectedPos.length = 0\n }\n selectedPos.push({\n col: datum?.col,\n row: datum?.row,\n })\n\n const cellStyle = pickBodyCellStyle(style)\n\n // 应用 backgroundColorScale\n if (style.enableBackgroundColorScale) {\n const scaledColor = applyColorScale(dataValue, {\n minValue: columnMin,\n maxValue: columnMax,\n ...themeConfig.backgroundColorScale,\n ...style.backgroundColorScale,\n } as any)\n if (scaledColor) {\n cellStyle.bgColor = scaledColor\n }\n }\n\n // 如果开启了数据条样式\n if (newInd.cellType === 'progressbar') {\n cellStyle.barHeight = themeConfig?.barHeight\n cellStyle.barMarkInBar = themeConfig?.barMarkInBar\n cellStyle.barMarkWidth = themeConfig?.barMarkWidth\n cellStyle.barPadding = themeConfig?.barPadding\n cellStyle.barRightToLeft = themeConfig?.barRightToLeft\n }\n\n return {\n ...result,\n ...cellStyle,\n }\n }\n\n return result\n }, {})\n\n return mergedStyle\n }\n return newInd\n })\n return {\n ...spec,\n runningConfig: {\n ...((spec as any)?.runningConfig || {}),\n selectedPos,\n },\n indicators: newIndicators,\n } as PivotTableConstructorOptions\n}\n"],"names":["pivotTableBodyCell","spec","context","advancedVSeed","cellStyle","config","chartType","bodyCellStyle","themeConfig","bodyCellStyleList","array","indicators","selectedPos","hasDynamicFilter","style","allData","newIndicators","ind","newInd","isString","indicatorKey","progressBarStyle","s","matchesFieldSelector","backgroundColorScale","columnMin","columnMax","min","max","getColumnMinMax","datum","dataValue","cellHeaderPaths","headerPaths","originalDatum","path","currentCellData","getCellOriginalDataByDatum","mergedStyle","result","shouldApply","selectorWithDynamicFilter","selector","pickBodyCellStyle","scaledColor","applyColorScale"],"mappings":"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"}
1
+ {"version":3,"file":"pipeline/spec/table/pipes/cellStyle/pivot.js","sources":["webpack://@visactor/vseed/./src/pipeline/spec/table/pipes/cellStyle/pivot.ts"],"sourcesContent":["import type { IIndicator, PivotTableConstructorOptions } from '@visactor/vtable'\nimport { array } from '@visactor/vutils'\nimport { isString } from 'remeda'\nimport { matchesFieldSelector, selector, selectorWithDynamicFilter } from 'src/dataSelector/selector'\nimport type { BodyCellStyle, Datum, PivotTableSpecPipe, TableConfig } from 'src/types'\nimport type { FieldSelector } from 'src/types/dataSelector'\nimport { getCellOriginalDataByDatum, pickBodyCellStyle, applyColorScale, getColumnMinMax } from './common'\nimport type { IProgressbarColumnIndicator } from '@visactor/vtable/es/ts-types/pivot-table/indicator/progress-indicator'\n\nconst isPivotTotalCell = (styleArg: any): boolean => {\n const cellHeaderPaths = styleArg?.cellHeaderPaths\n if (!cellHeaderPaths) {\n return false\n }\n\n if (cellHeaderPaths.role === 'sub-total' || cellHeaderPaths.role === 'grand-total') {\n return true\n }\n\n const headerPaths = [...(cellHeaderPaths.colHeaderPaths || []), ...(cellHeaderPaths.rowHeaderPaths || [])]\n return headerPaths.some((path: any) => path?.role === 'sub-total' || path?.role === 'grand-total')\n}\n\nexport const pivotTableBodyCell: PivotTableSpecPipe = (spec, context) => {\n const { advancedVSeed } = context\n const { cellStyle, config, chartType } = advancedVSeed\n const bodyCellStyle = cellStyle?.bodyCellStyle\n const themeConfig = config?.[chartType] as TableConfig\n\n if (!bodyCellStyle) {\n return spec as PivotTableConstructorOptions\n }\n const bodyCellStyleList = array(bodyCellStyle) as BodyCellStyle[]\n const indicators = (spec as PivotTableConstructorOptions).indicators || []\n const selectedPos: { col: number; row: number }[] = []\n const hasDynamicFilter = bodyCellStyleList.some((style) => !!style.dynamicFilter)\n const allData = advancedVSeed.dataset || []\n\n const newIndicators = indicators.map((ind) => {\n const newInd = isString(ind)\n ? ({\n indicatorKey: ind,\n } as IIndicator)\n : ind\n\n const { indicatorKey } = newInd\n\n // 前置处理:检查是否需要 progressBar 或 backgroundColorScale\n const progressBarStyle = bodyCellStyleList\n .filter(\n (s) => s.enableProgressBar && s?.selector && matchesFieldSelector(indicatorKey, s.selector as FieldSelector),\n )\n .pop()\n const backgroundColorScale = bodyCellStyleList.find(\n (s) =>\n s.enableBackgroundColorScale && s?.selector && matchesFieldSelector(indicatorKey, s.selector as FieldSelector),\n )\n let columnMin: number\n let columnMax: number\n\n if (progressBarStyle || backgroundColorScale) {\n const { min, max } = getColumnMinMax(allData, indicatorKey)\n columnMin = min\n columnMax = max\n if (progressBarStyle) {\n newInd.cellType = 'progressbar'\n ;(newInd as IProgressbarColumnIndicator).barType = 'negative'\n ;(newInd as IProgressbarColumnIndicator).min = progressBarStyle.barMin ?? columnMin\n ;(newInd as IProgressbarColumnIndicator).max = progressBarStyle.barMax ?? columnMax\n }\n }\n\n newInd.style = (datum: any) => {\n const { dataValue, cellHeaderPaths } = datum\n const headerPaths = [...cellHeaderPaths.colHeaderPaths, ...cellHeaderPaths.rowHeaderPaths]\n\n const originalDatum: Datum = {\n [indicatorKey]: dataValue,\n }\n\n headerPaths.forEach((path: any) => {\n if (path.dimensionKey) {\n originalDatum[path.dimensionKey] = path.value\n }\n })\n\n const currentCellData = getCellOriginalDataByDatum(datum, hasDynamicFilter, originalDatum)\n\n const mergedStyle = bodyCellStyleList.reduce<Record<string, any>>((result, style) => {\n const shouldApply = style.dynamicFilter\n ? selectorWithDynamicFilter(currentCellData || originalDatum, style.dynamicFilter, style.selector)\n : selector(originalDatum, style.selector)\n if (shouldApply) {\n if (selectedPos.length && selectedPos[0].col === datum?.col && selectedPos[0].row === datum?.row) {\n selectedPos.length = 0\n }\n selectedPos.push({\n col: datum?.col,\n row: datum?.row,\n })\n\n const cellStyle = pickBodyCellStyle(style)\n\n // 应用 backgroundColorScale\n if (style.enableBackgroundColorScale) {\n const scaledColor = applyColorScale(dataValue, {\n minValue: columnMin,\n maxValue: columnMax,\n ...themeConfig.backgroundColorScale,\n ...style.backgroundColorScale,\n } as any)\n if (scaledColor) {\n cellStyle.bgColor = scaledColor\n }\n }\n\n // 如果开启了数据条样式\n if (newInd.cellType === 'progressbar') {\n cellStyle.barHeight = themeConfig?.barHeight\n cellStyle.barMarkInBar = themeConfig?.barMarkInBar\n cellStyle.barMarkWidth = themeConfig?.barMarkWidth\n cellStyle.barPadding = themeConfig?.barPadding\n cellStyle.barRightToLeft = themeConfig?.barRightToLeft\n cellStyle.showBar = !isPivotTotalCell(datum)\n }\n\n return {\n ...result,\n ...cellStyle,\n }\n }\n\n return result\n }, {})\n\n return mergedStyle\n }\n return newInd\n })\n return {\n ...spec,\n runningConfig: {\n ...((spec as any)?.runningConfig || {}),\n selectedPos,\n },\n indicators: newIndicators,\n } as PivotTableConstructorOptions\n}\n"],"names":["isPivotTotalCell","styleArg","cellHeaderPaths","headerPaths","path","pivotTableBodyCell","spec","context","advancedVSeed","cellStyle","config","chartType","bodyCellStyle","themeConfig","bodyCellStyleList","array","indicators","selectedPos","hasDynamicFilter","style","allData","newIndicators","ind","newInd","isString","indicatorKey","progressBarStyle","s","matchesFieldSelector","backgroundColorScale","columnMin","columnMax","min","max","getColumnMinMax","datum","dataValue","originalDatum","currentCellData","getCellOriginalDataByDatum","mergedStyle","result","shouldApply","selectorWithDynamicFilter","selector","pickBodyCellStyle","scaledColor","applyColorScale"],"mappings":"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"}
@@ -4,8 +4,10 @@ import { isFieldSelector, matchesFieldSelector, selector, selectorWithDynamicFil
4
4
  import { applyColorScale, getCellOriginalDataByDatum, getColumnMinMax, pickBodyCellStyle } from "./common.js";
5
5
  import { preorderTraverse } from "../../../../utils/tree/traverse.js";
6
6
  const tableBodyCell = (spec, context)=>{
7
- const { advancedVSeed } = context;
7
+ const { advancedVSeed, vseed } = context;
8
+ const { totals } = vseed || {};
8
9
  const { cellStyle, config, chartType } = advancedVSeed;
10
+ const totalAggregation = 'string' == typeof totals ? totals : void 0;
9
11
  const bodyCellStyle = cellStyle?.bodyCellStyle;
10
12
  const themeConfig = config?.[chartType];
11
13
  if (!bodyCellStyle) return spec;
@@ -32,14 +34,14 @@ const tableBodyCell = (spec, context)=>{
32
34
  let columnMin;
33
35
  let columnMax;
34
36
  if (progressBarStyle || backgroundColorScale) {
35
- const { min, max } = getColumnMinMax(allData, field);
37
+ const { min, max } = getColumnMinMax(allData, field, totalAggregation);
36
38
  columnMin = min;
37
39
  columnMax = max;
38
40
  if (progressBarStyle) {
39
41
  col.cellType = 'progressbar';
40
42
  col.barType = 'negative';
41
43
  col.min = progressBarStyle.barMin ?? columnMin;
42
- col.max = progressBarStyle.barMin ?? columnMax;
44
+ col.max = progressBarStyle.barMax ?? columnMax;
43
45
  }
44
46
  }
45
47
  col.style = (datum)=>{
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline/spec/table/pipes/cellStyle/table.js","sources":["webpack://@visactor/vseed/./src/pipeline/spec/table/pipes/cellStyle/table.ts"],"sourcesContent":["import type { ListTableConstructorOptions, ColumnDefine, ProgressbarColumnDefine } from '@visactor/vtable'\nimport { array } from '@visactor/vutils'\nimport { isNullish, isNumber, isPlainObject, isString } from 'remeda'\nimport { isFieldSelector, matchesFieldSelector, selector, selectorWithDynamicFilter } from 'src/dataSelector/selector'\nimport type { BodyCellStyle, ListTableSpecPipe, TableConfig } from 'src/types'\nimport type { FieldSelector, MeasureSelector } from 'src/types/dataSelector'\nimport { getCellOriginalDataByDatum, pickBodyCellStyle, applyColorScale, getColumnMinMax } from './common'\nimport { preorderTraverse } from 'src/pipeline/utils/tree/traverse'\n\nexport const tableBodyCell: ListTableSpecPipe = (spec, context) => {\n const { advancedVSeed } = context\n const { cellStyle, config, chartType } = advancedVSeed\n const bodyCellStyle = cellStyle?.bodyCellStyle\n const themeConfig = config?.[chartType] as TableConfig\n\n if (!bodyCellStyle) {\n return spec as ListTableConstructorOptions\n }\n\n const bodyCellStyleList = array(bodyCellStyle) as BodyCellStyle[]\n const columns = (spec as ListTableConstructorOptions).columns || []\n const selectedPos: { col: number; row: number }[] = []\n const allData = advancedVSeed.dataset || []\n\n const setStyleOfColumn = (col: ColumnDefine) => {\n const field = col.field as string\n\n // 过滤出匹配当前列的样式配置\n const matchedStyles = bodyCellStyleList.filter((style) => {\n // 检查 dynamicFilter\n if (style?.dynamicFilter) {\n return style.dynamicFilter?.result?.success === true || !!style.dynamicFilter?.fallback\n }\n\n // 检查 selector\n if (isNullish(style.selector)) {\n return true\n }\n\n const selectors = array(style.selector) as any[]\n return selectors.some((sel) => {\n // 1. FieldSelector(字段选择器)\n if (isFieldSelector(sel)) {\n return matchesFieldSelector(field, sel)\n }\n\n // 2. MeasureSelector/DimensionSelector(条件选择器)\n if (isPlainObject(sel)) {\n return isNullish(sel.field) || (sel as MeasureSelector).field === field\n }\n\n // 3. ValueSelector(值选择器)\n return isNumber(sel) || isString(sel)\n })\n })\n\n if (!matchedStyles.length) {\n return false\n }\n\n const hasDynamicFilter = matchedStyles.some((style) => !!style.dynamicFilter)\n\n // 前置处理:检查是否需要 progressBar\n const progressBarStyle = matchedStyles\n .filter((s) => s.enableProgressBar && s?.selector && matchesFieldSelector(field, s.selector as FieldSelector))\n .pop()\n const backgroundColorScale = matchedStyles.find(\n (s) => s.enableBackgroundColorScale && s?.selector && matchesFieldSelector(field, s.selector as FieldSelector),\n )\n let columnMin: number\n let columnMax: number\n if (progressBarStyle || backgroundColorScale) {\n const { min, max } = getColumnMinMax(allData, field)\n columnMin = min\n columnMax = max\n if (progressBarStyle) {\n col.cellType = 'progressbar'\n ;(col as ProgressbarColumnDefine).barType = 'negative'\n ;(col as ProgressbarColumnDefine).min = progressBarStyle.barMin ?? columnMin\n ;(col as ProgressbarColumnDefine).max = progressBarStyle.barMin ?? columnMax\n }\n }\n\n // 统一的 col.style 回调\n col.style = (datum: any) => {\n const originalDatum = {\n [field]: datum.dataValue,\n }\n const currentCellData = getCellOriginalDataByDatum(datum, hasDynamicFilter, originalDatum)\n\n const mergedStyle = matchedStyles.reduce<Record<string, any>>((result, style) => {\n const shouldApply = style.dynamicFilter\n ? selectorWithDynamicFilter(currentCellData || originalDatum, style.dynamicFilter, style.selector)\n : selector(originalDatum, style.selector)\n\n if (shouldApply) {\n if (selectedPos.length && selectedPos[0].col === datum?.col && selectedPos[0].row === datum?.row) {\n // 说明重复进入了,清空历史\n selectedPos.length = 0\n }\n selectedPos.push({\n col: datum?.col,\n row: datum?.row,\n })\n\n let cellStyle = pickBodyCellStyle(style)\n\n // 应用 backgroundColorScale\n if (style.enableBackgroundColorScale) {\n const scaledColor = applyColorScale(datum.dataValue, {\n minValue: columnMin,\n maxValue: columnMax,\n ...themeConfig.backgroundColorScale,\n ...style?.backgroundColorScale,\n } as any)\n if (scaledColor) {\n cellStyle.bgColor = scaledColor\n }\n }\n // 如果开启了数据条样式\n if (col.cellType === 'progressbar') {\n cellStyle = {\n ...cellStyle,\n barHeight: themeConfig?.barHeight,\n barMarkInBar: themeConfig?.barMarkInBar,\n barMarkWidth: themeConfig?.barMarkWidth,\n barPadding: themeConfig?.barPadding,\n barRightToLeft: themeConfig?.barRightToLeft,\n barAxisColor: themeConfig?.barAxisColor,\n }\n }\n\n return {\n ...result,\n ...cellStyle,\n }\n }\n\n return result\n }, {})\n\n return mergedStyle\n }\n\n return false\n }\n\n preorderTraverse<ColumnDefine, 'columns'>(columns, setStyleOfColumn, 'columns')\n ;(spec as any).runningConfig = {\n ...((spec as any).runningConfig || {}),\n selectedPos,\n }\n\n return spec as ListTableConstructorOptions\n}\n"],"names":["tableBodyCell","spec","context","advancedVSeed","cellStyle","config","chartType","bodyCellStyle","themeConfig","bodyCellStyleList","array","columns","selectedPos","allData","setStyleOfColumn","col","field","matchedStyles","style","isNullish","selectors","sel","isFieldSelector","matchesFieldSelector","isPlainObject","isNumber","isString","hasDynamicFilter","progressBarStyle","s","backgroundColorScale","columnMin","columnMax","min","max","getColumnMinMax","datum","originalDatum","currentCellData","getCellOriginalDataByDatum","mergedStyle","result","shouldApply","selectorWithDynamicFilter","selector","pickBodyCellStyle","scaledColor","applyColorScale","preorderTraverse"],"mappings":"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"}
1
+ {"version":3,"file":"pipeline/spec/table/pipes/cellStyle/table.js","sources":["webpack://@visactor/vseed/./src/pipeline/spec/table/pipes/cellStyle/table.ts"],"sourcesContent":["import type { ListTableConstructorOptions, ColumnDefine, ProgressbarColumnDefine } from '@visactor/vtable'\nimport { array } from '@visactor/vutils'\nimport { isNullish, isNumber, isPlainObject, isString } from 'remeda'\nimport { isFieldSelector, matchesFieldSelector, selector, selectorWithDynamicFilter } from 'src/dataSelector/selector'\nimport type { BodyCellStyle, ListTableSpecPipe, Table, TableConfig } from 'src/types'\nimport type { FieldSelector, MeasureSelector } from 'src/types/dataSelector'\nimport { getCellOriginalDataByDatum, pickBodyCellStyle, applyColorScale, getColumnMinMax } from './common'\nimport { preorderTraverse } from 'src/pipeline/utils/tree/traverse'\n\nexport const tableBodyCell: ListTableSpecPipe = (spec, context) => {\n const { advancedVSeed, vseed } = context\n const { totals } = (vseed || {}) as Table\n const { cellStyle, config, chartType } = advancedVSeed\n const totalAggregation = typeof totals === 'string' ? totals : undefined\n const bodyCellStyle = cellStyle?.bodyCellStyle\n const themeConfig = config?.[chartType] as TableConfig\n\n if (!bodyCellStyle) {\n return spec as ListTableConstructorOptions\n }\n\n const bodyCellStyleList = array(bodyCellStyle) as BodyCellStyle[]\n const columns = (spec as ListTableConstructorOptions).columns || []\n const selectedPos: { col: number; row: number }[] = []\n const allData = advancedVSeed.dataset || []\n\n const setStyleOfColumn = (col: ColumnDefine) => {\n const field = col.field as string\n\n // 过滤出匹配当前列的样式配置\n const matchedStyles = bodyCellStyleList.filter((style) => {\n // 检查 dynamicFilter\n if (style?.dynamicFilter) {\n return style.dynamicFilter?.result?.success === true || !!style.dynamicFilter?.fallback\n }\n\n // 检查 selector\n if (isNullish(style.selector)) {\n return true\n }\n\n const selectors = array(style.selector) as any[]\n return selectors.some((sel) => {\n // 1. FieldSelector(字段选择器)\n if (isFieldSelector(sel)) {\n return matchesFieldSelector(field, sel)\n }\n\n // 2. MeasureSelector/DimensionSelector(条件选择器)\n if (isPlainObject(sel)) {\n return isNullish(sel.field) || (sel as MeasureSelector).field === field\n }\n\n // 3. ValueSelector(值选择器)\n return isNumber(sel) || isString(sel)\n })\n })\n\n if (!matchedStyles.length) {\n return false\n }\n\n const hasDynamicFilter = matchedStyles.some((style) => !!style.dynamicFilter)\n\n // 前置处理:检查是否需要 progressBar\n const progressBarStyle = matchedStyles\n .filter((s) => s.enableProgressBar && s?.selector && matchesFieldSelector(field, s.selector as FieldSelector))\n .pop()\n const backgroundColorScale = matchedStyles.find(\n (s) => s.enableBackgroundColorScale && s?.selector && matchesFieldSelector(field, s.selector as FieldSelector),\n )\n let columnMin: number\n let columnMax: number\n if (progressBarStyle || backgroundColorScale) {\n const { min, max } = getColumnMinMax(allData, field, totalAggregation)\n columnMin = min\n columnMax = max\n if (progressBarStyle) {\n col.cellType = 'progressbar'\n ;(col as ProgressbarColumnDefine).barType = 'negative'\n ;(col as ProgressbarColumnDefine).min = progressBarStyle.barMin ?? columnMin\n ;(col as ProgressbarColumnDefine).max = progressBarStyle.barMax ?? columnMax\n }\n }\n\n // 统一的 col.style 回调\n col.style = (datum: any) => {\n const originalDatum = {\n [field]: datum.dataValue,\n }\n const currentCellData = getCellOriginalDataByDatum(datum, hasDynamicFilter, originalDatum)\n\n const mergedStyle = matchedStyles.reduce<Record<string, any>>((result, style) => {\n const shouldApply = style.dynamicFilter\n ? selectorWithDynamicFilter(currentCellData || originalDatum, style.dynamicFilter, style.selector)\n : selector(originalDatum, style.selector)\n\n if (shouldApply) {\n if (selectedPos.length && selectedPos[0].col === datum?.col && selectedPos[0].row === datum?.row) {\n // 说明重复进入了,清空历史\n selectedPos.length = 0\n }\n selectedPos.push({\n col: datum?.col,\n row: datum?.row,\n })\n\n let cellStyle = pickBodyCellStyle(style)\n\n // 应用 backgroundColorScale\n if (style.enableBackgroundColorScale) {\n const scaledColor = applyColorScale(datum.dataValue, {\n minValue: columnMin,\n maxValue: columnMax,\n ...themeConfig.backgroundColorScale,\n ...style?.backgroundColorScale,\n } as any)\n if (scaledColor) {\n cellStyle.bgColor = scaledColor\n }\n }\n // 如果开启了数据条样式\n if (col.cellType === 'progressbar') {\n cellStyle = {\n ...cellStyle,\n barHeight: themeConfig?.barHeight,\n barMarkInBar: themeConfig?.barMarkInBar,\n barMarkWidth: themeConfig?.barMarkWidth,\n barPadding: themeConfig?.barPadding,\n barRightToLeft: themeConfig?.barRightToLeft,\n barAxisColor: themeConfig?.barAxisColor,\n }\n }\n\n return {\n ...result,\n ...cellStyle,\n }\n }\n\n return result\n }, {})\n\n return mergedStyle\n }\n\n return false\n }\n\n preorderTraverse<ColumnDefine, 'columns'>(columns, setStyleOfColumn, 'columns')\n ;(spec as any).runningConfig = {\n ...((spec as any).runningConfig || {}),\n selectedPos,\n }\n\n return spec as ListTableConstructorOptions\n}\n"],"names":["tableBodyCell","spec","context","advancedVSeed","vseed","totals","cellStyle","config","chartType","totalAggregation","undefined","bodyCellStyle","themeConfig","bodyCellStyleList","array","columns","selectedPos","allData","setStyleOfColumn","col","field","matchedStyles","style","isNullish","selectors","sel","isFieldSelector","matchesFieldSelector","isPlainObject","isNumber","isString","hasDynamicFilter","progressBarStyle","s","backgroundColorScale","columnMin","columnMax","min","max","getColumnMinMax","datum","originalDatum","currentCellData","getCellOriginalDataByDatum","mergedStyle","result","shouldApply","selectorWithDynamicFilter","selector","pickBodyCellStyle","scaledColor","applyColorScale","preorderTraverse"],"mappings":"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"}
package/dist/umd/index.js CHANGED
@@ -4358,19 +4358,46 @@ self.R = R;
4358
4358
  if (key in bodyCellStyle) acc[tableStyleMap[key]] = bodyCellStyle[key];
4359
4359
  return acc;
4360
4360
  }, {});
4361
- const getColumnMinMax = (allData, field)=>{
4361
+ const getColumnMinMax = (allData, field, totalAggregation)=>{
4362
4362
  let min = 1 / 0;
4363
4363
  let max = -1 / 0;
4364
+ let sum = 0;
4365
+ let count = 0;
4366
+ const hasTotal = !!totalAggregation;
4367
+ const aggregationType = 'string' == typeof totalAggregation ? totalAggregation : 'sum';
4364
4368
  for (const datum of allData){
4365
4369
  const value = Number(datum[field]);
4366
4370
  if (!Number.isNaN(value)) {
4367
4371
  min = Math.min(min, value);
4368
4372
  max = Math.max(max, value);
4373
+ sum += value;
4374
+ count += 1;
4369
4375
  }
4370
4376
  }
4377
+ const baseMin = min === 1 / 0 ? 0 : min;
4378
+ const baseMax = max === -1 / 0 ? 0 : max;
4379
+ if (!hasTotal) return {
4380
+ min: baseMin,
4381
+ max: baseMax
4382
+ };
4383
+ const total = (()=>{
4384
+ switch(aggregationType){
4385
+ case 'avg':
4386
+ return count ? sum / count : 0;
4387
+ case 'max':
4388
+ return baseMax;
4389
+ case 'min':
4390
+ return baseMin;
4391
+ case 'count':
4392
+ return count;
4393
+ case 'sum':
4394
+ default:
4395
+ return sum;
4396
+ }
4397
+ })();
4371
4398
  return {
4372
- min: min === 1 / 0 ? 0 : min,
4373
- max: max === -1 / 0 ? 0 : max
4399
+ min: Math.min(baseMin, total),
4400
+ max: Math.max(baseMax, total)
4374
4401
  };
4375
4402
  };
4376
4403
  const applyColorScale = (value, scale)=>{
@@ -4392,8 +4419,10 @@ self.R = R;
4392
4419
  } : null;
4393
4420
  };
4394
4421
  const tableBodyCell = (spec, context)=>{
4395
- const { advancedVSeed } = context;
4422
+ const { advancedVSeed, vseed } = context;
4423
+ const { totals } = vseed || {};
4396
4424
  const { cellStyle, config, chartType } = advancedVSeed;
4425
+ const totalAggregation = 'string' == typeof totals ? totals : void 0;
4397
4426
  const bodyCellStyle = cellStyle?.bodyCellStyle;
4398
4427
  const themeConfig = config?.[chartType];
4399
4428
  if (!bodyCellStyle) return spec;
@@ -4420,14 +4449,14 @@ self.R = R;
4420
4449
  let columnMin;
4421
4450
  let columnMax;
4422
4451
  if (progressBarStyle || backgroundColorScale) {
4423
- const { min, max } = getColumnMinMax(allData, field);
4452
+ const { min, max } = getColumnMinMax(allData, field, totalAggregation);
4424
4453
  columnMin = min;
4425
4454
  columnMax = max;
4426
4455
  if (progressBarStyle) {
4427
4456
  col.cellType = 'progressbar';
4428
4457
  col.barType = 'negative';
4429
4458
  col.min = progressBarStyle.barMin ?? columnMin;
4430
- col.max = progressBarStyle.barMin ?? columnMax;
4459
+ col.max = progressBarStyle.barMax ?? columnMax;
4431
4460
  }
4432
4461
  }
4433
4462
  col.style = (datum)=>{
@@ -4800,6 +4829,16 @@ self.R = R;
4800
4829
  };
4801
4830
  return result;
4802
4831
  };
4832
+ const isPivotTotalCell = (styleArg)=>{
4833
+ const cellHeaderPaths = styleArg?.cellHeaderPaths;
4834
+ if (!cellHeaderPaths) return false;
4835
+ if ('sub-total' === cellHeaderPaths.role || 'grand-total' === cellHeaderPaths.role) return true;
4836
+ const headerPaths = [
4837
+ ...cellHeaderPaths.colHeaderPaths || [],
4838
+ ...cellHeaderPaths.rowHeaderPaths || []
4839
+ ];
4840
+ return headerPaths.some((path)=>path?.role === 'sub-total' || path?.role === 'grand-total');
4841
+ };
4803
4842
  const pivotTableBodyCell = (spec, context)=>{
4804
4843
  const { advancedVSeed } = context;
4805
4844
  const { cellStyle, config, chartType } = advancedVSeed;
@@ -4868,6 +4907,7 @@ self.R = R;
4868
4907
  cellStyle.barMarkWidth = themeConfig?.barMarkWidth;
4869
4908
  cellStyle.barPadding = themeConfig?.barPadding;
4870
4909
  cellStyle.barRightToLeft = themeConfig?.barRightToLeft;
4910
+ cellStyle.showBar = !isPivotTotalCell(datum);
4871
4911
  }
4872
4912
  return {
4873
4913
  ...result,
@@ -8859,6 +8899,37 @@ self.R = R;
8859
8899
  result.animation = true;
8860
8900
  return result;
8861
8901
  };
8902
+ const reverseStackCornerRadius = (cornerRadius)=>{
8903
+ if (!Array.isArray(cornerRadius)) return cornerRadius;
8904
+ const [topLeft = 0, topRight = 0, bottomRight = 0, bottomLeft = 0] = cornerRadius;
8905
+ return [
8906
+ bottomRight,
8907
+ bottomLeft,
8908
+ topLeft,
8909
+ topRight
8910
+ ];
8911
+ };
8912
+ const mergeStackCornerRadius = (cornerRadius)=>{
8913
+ if (!Array.isArray(cornerRadius)) return cornerRadius;
8914
+ const [topLeft = 0, topRight = 0, bottomRight = 0, bottomLeft = 0] = cornerRadius;
8915
+ return [
8916
+ Math.max(topLeft, bottomRight),
8917
+ Math.max(topRight, bottomLeft),
8918
+ Math.max(bottomRight, topLeft),
8919
+ Math.max(bottomLeft, topRight)
8920
+ ];
8921
+ };
8922
+ const getStackRangeCornerRadius = (cornerRadius, datum)=>{
8923
+ const stackStart = datum?.['__VCHART_STACK_START'];
8924
+ const stackEnd = datum?.['__VCHART_STACK_END'];
8925
+ if ('number' != typeof stackStart || 'number' != typeof stackEnd) return;
8926
+ const hasPositivePart = stackStart > 0 || stackEnd > 0;
8927
+ const hasNegativePart = stackStart < 0 || stackEnd < 0;
8928
+ if (hasPositivePart && hasNegativePart) return mergeStackCornerRadius(cornerRadius);
8929
+ if (hasPositivePart) return cornerRadius;
8930
+ if (hasNegativePart) return reverseStackCornerRadius(cornerRadius);
8931
+ return 0;
8932
+ };
8862
8933
  const stackCornerRadius_stackCornerRadius = (spec, context)=>{
8863
8934
  const { advancedVSeed, vseed } = context;
8864
8935
  const { chartType } = vseed;
@@ -8867,7 +8938,11 @@ self.R = R;
8867
8938
  return {
8868
8939
  ...spec,
8869
8940
  stackCornerRadius: (_, datum)=>{
8870
- if (datum && datum[datum[FoldMeasureId]] > 0) return stackCornerRadius;
8941
+ const stackRangeCornerRadius = getStackRangeCornerRadius(stackCornerRadius, datum);
8942
+ if (void 0 !== stackRangeCornerRadius) return stackRangeCornerRadius;
8943
+ const value = datum?.[datum?.[FoldMeasureId]];
8944
+ if (value > 0) return stackCornerRadius;
8945
+ if (value < 0) return reverseStackCornerRadius(stackCornerRadius);
8871
8946
  return 0;
8872
8947
  }
8873
8948
  };