{"version":3,"file":"util.js","sourceRoot":"","sources":["../../../src/plots/scatter/util.ts"],"names":[],"mappings":"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","sourcesContent":["import { View } from '@antv/g2';\nimport { get, isArray, isNumber } from '@antv/util';\nimport {\n regressionExp,\n regressionLinear,\n regressionLoess,\n regressionLog,\n regressionPoly,\n regressionPow,\n regressionQuad,\n} from 'd3-regression';\nimport { getSplinePath } from '../../utils';\nimport { ScatterOptions } from './types';\n\nconst REGRESSION_MAP = {\n exp: regressionExp,\n linear: regressionLinear,\n loess: regressionLoess,\n log: regressionLog,\n poly: regressionPoly,\n pow: regressionPow,\n quad: regressionQuad,\n};\n\ntype RenderOptions = {\n view: View;\n options: ScatterOptions;\n};\n\ntype D3RegressionResult = {\n a?: number;\n b?: number;\n c?: number;\n coefficients?: number[];\n rSquared?: number;\n};\n\n/**\n * 获取四象限默认配置\n * @param {number} xBaseline\n * @param {number} yBaseline\n */\nexport function getQuadrantDefaultConfig(xBaseline: number, yBaseline: number) {\n // 文本便宜距离\n const textOffset = 10;\n // 四象限默认样式\n const defaultConfig: { [key: string]: any } = {\n regionStyle: [\n {\n position: {\n start: [xBaseline, 'max'],\n end: ['max', yBaseline],\n },\n style: {\n fill: '#d8d0c0',\n opacity: 0.4,\n },\n },\n {\n position: {\n start: ['min', 'max'],\n end: [xBaseline, yBaseline],\n },\n style: {\n fill: '#a3dda1',\n opacity: 0.4,\n },\n },\n {\n position: {\n start: ['min', yBaseline],\n end: [xBaseline, 'min'],\n },\n style: {\n fill: '#d8d0c0',\n opacity: 0.4,\n },\n },\n {\n position: {\n start: [xBaseline, yBaseline],\n end: ['max', 'min'],\n },\n style: {\n fill: '#a3dda1',\n opacity: 0.4,\n },\n },\n ],\n lineStyle: {\n stroke: '#9ba29a',\n lineWidth: 1,\n },\n labelStyle: [\n {\n position: ['max', yBaseline],\n offsetX: -textOffset,\n offsetY: -textOffset,\n style: {\n textAlign: 'right',\n textBaseline: 'bottom',\n fontSize: 14,\n fill: '#ccc',\n },\n },\n {\n position: ['min', yBaseline],\n offsetX: textOffset,\n offsetY: -textOffset,\n style: {\n textAlign: 'left',\n textBaseline: 'bottom',\n fontSize: 14,\n fill: '#ccc',\n },\n },\n {\n position: ['min', yBaseline],\n offsetX: textOffset,\n offsetY: textOffset,\n style: {\n textAlign: 'left',\n textBaseline: 'top',\n fontSize: 14,\n fill: '#ccc',\n },\n },\n {\n position: ['max', yBaseline],\n offsetX: -textOffset,\n offsetY: textOffset,\n style: {\n textAlign: 'right',\n textBaseline: 'top',\n fontSize: 14,\n fill: '#ccc',\n },\n },\n ],\n };\n return defaultConfig;\n}\n\nconst splinePath = (data: number[][], config: RenderOptions) => {\n const {\n view,\n options: { xField, yField },\n } = config;\n const xScaleView = view.getScaleByField(xField);\n const yScaleView = view.getScaleByField(yField);\n const pathData = data.map((d: [number, number]) =>\n view.getCoordinate().convert({ x: xScaleView.scale(d[0]), y: yScaleView.scale(d[1]) })\n );\n return getSplinePath(pathData, false);\n};\n\nexport const getPath = (config: RenderOptions) => {\n const { options } = config;\n const { xField, yField, data, regressionLine } = options;\n const { type = 'linear', algorithm, equation: customEquation } = regressionLine;\n let pathData: Array<[number, number]>;\n let equation = null;\n if (algorithm) {\n pathData = isArray(algorithm) ? algorithm : algorithm(data);\n equation = customEquation;\n } else {\n const reg = REGRESSION_MAP[type]()\n .x((d) => d[xField])\n .y((d) => d[yField]);\n pathData = reg(data);\n equation = getRegressionEquation(type, pathData as D3RegressionResult);\n }\n return [splinePath(pathData, config), equation];\n};\n\n/**\n * 调整散点图 meta: { min, max } ① data.length === 1 ② 所有数据 y 值相等 ③ 所有数据 x 值相等\n * @param options\n * @returns\n */\nexport const getMeta = (\n options: Pick\n): ScatterOptions['meta'] => {\n const { meta = {}, xField, yField, data } = options;\n const xFieldValue = data[0][xField];\n const yFieldValue = data[0][yField];\n const xIsPositiveNumber = xFieldValue > 0;\n const yIsPositiveNumber = yFieldValue > 0;\n\n /**\n * 获得对应字段的 min max scale 配置\n */\n function getMetaMinMax(field: string, axis: 'x' | 'y') {\n const fieldMeta = get(meta, [field]);\n\n function getCustomValue(type: 'min' | 'max') {\n return get(fieldMeta, type);\n }\n\n const range = {};\n\n if (axis === 'x') {\n if (isNumber(xFieldValue)) {\n if (!isNumber(getCustomValue('min'))) {\n range['min'] = xIsPositiveNumber ? 0 : xFieldValue * 2;\n }\n\n if (!isNumber(getCustomValue('max'))) {\n range['max'] = xIsPositiveNumber ? xFieldValue * 2 : 0;\n }\n }\n\n return range;\n }\n\n if (isNumber(yFieldValue)) {\n if (!isNumber(getCustomValue('min'))) {\n range['min'] = yIsPositiveNumber ? 0 : yFieldValue * 2;\n }\n\n if (!isNumber(getCustomValue('max'))) {\n range['max'] = yIsPositiveNumber ? yFieldValue * 2 : 0;\n }\n }\n\n return range;\n }\n\n return {\n ...meta,\n [xField]: {\n ...meta[xField],\n ...getMetaMinMax(xField, 'x'),\n },\n [yField]: {\n ...meta[yField],\n ...getMetaMinMax(yField, 'y'),\n },\n };\n};\n\n/**\n * 获取回归函数表达式\n * @param {string} type - 回归函数类型\n * @param {D3RegressionResult} res - 回归计算结果集\n * @return {string}\n */\nexport function getRegressionEquation(type: string, res: D3RegressionResult) {\n const roundByPrecision = (n, p = 4) => Math.round(n * Math.pow(10, p)) / Math.pow(10, p);\n const safeFormat = (value) => (Number.isFinite(value) ? roundByPrecision(value) : '?');\n\n switch (type) {\n case 'linear':\n // y = ax + b\n return `y = ${safeFormat(res.a)}x + ${safeFormat(res.b)}, R^2 = ${safeFormat(res.rSquared)}`;\n case 'exp':\n // y = ae^(bx)\n return `y = ${safeFormat(res.a)}e^(${safeFormat(res.b)}x), R^2 = ${safeFormat(res.rSquared)}`;\n case 'log':\n // y = a · ln(x) + b\n return `y = ${safeFormat(res.a)}ln(x) + ${safeFormat(res.b)}, R^2 = ${safeFormat(res.rSquared)}`;\n case 'quad':\n // y = ax^2 + bx + c\n return `y = ${safeFormat(res.a)}x^2 + ${safeFormat(res.b)}x + ${safeFormat(res.c)}, R^2 = ${safeFormat(\n res.rSquared\n )}`;\n case 'poly':\n // y = anx^n + ... + a1x + a0\n // eslint-disable-next-line no-case-declarations\n let temp = `y = ${safeFormat(res.coefficients?.[0])} + ${safeFormat(res.coefficients?.[1])}x + ${safeFormat(\n res.coefficients?.[2]\n )}x^2`;\n for (let i = 3; i < res.coefficients.length; ++i) {\n temp += ` + ${safeFormat(res.coefficients[i])}x^${i}`;\n }\n return `${temp}, R^2 = ${safeFormat(res.rSquared)}`;\n case 'pow':\n // y = ax^b\n return `y = ${safeFormat(res.a)}x^${safeFormat(res.b)}, R^2 = ${safeFormat(res.rSquared)}`;\n }\n return null;\n}\n"]}