import _ from 'lodash'; import moment from 'moment'; import { isArray } from './types'; /** * 转换echarts线性渐变方向 成 css渐变角度 css线性渐变方向为从上往下时为0deg。(0: 上 -> 下)。 * 根据echarts渐变方向计算出角度,以水平方向为基准顺时针旋转的角度。(0: 左 -> 右) 所以需要多旋转90度,转为css角度。 * * @param {any} x1 Echarts.graphic.LinearGradient.x * @param {any} y1 Echarts.graphic.LinearGradient.y * @param {any} x2 Echarts.graphic.LinearGradient.x2 * @param {any} y2 Echarts.graphic.LinearGradient.y2 * @returns Deg角度 */ const toCssAngle = (x1, y1, x2, y2) => { const deltaX = x2 - x1; const deltaY = y2 - y1; return Math.atan2(deltaY, deltaX) * (180 / Math.PI) + 90; }; /** * 获取系列真实值 * * @param {Object} param Formatter 单个数据集 * @returns 系列真实值 */ const valueAccessor = (param) => { // 数据可能通过series配置,也可能通过dataset配置。 const { value, encode, dimensionNames } = param; if (isArray(value)) { return value[encode.y[0]]; } else if (_.isObject(value)) { return value[dimensionNames[encode.y[0]]]; } else { return value; } }; /** * 获取系列单位 * * @param {Object} option 图表配置项 * @param {Object} param Formatter 单个数据集 * @returns 系列单位 */ const unitAccessor = (option, param) => { const { yAxis, series } = option; const { seriesIndex } = param; // 规范 yAxis 和 series 都为数组, 方便通过下标访问 const axisArr = isArray(yAxis) ? yAxis : !!yAxis ? [yAxis] : []; const serieArr = isArray(series) ? series : !!series ? [series] : []; const serie = serieArr[seriesIndex]; // 构造单位 let unit = ''; if (serie && serie.showUnit !== false) { unit = serie.unit !== null && serie.unit !== undefined ? serie.unit : _.get(axisArr, [_.get(serie, 'yAxisIndex', 0), 'name'], ''); // 根据serie去yAxis配置找name属性当做单位 } return unit; }; /** * 获取可渐变背景颜色值 * * @param {Object} param Formatter 单个数据集 * @returns 系列背景颜色 */ const bgcolorAccessor = (param) => { if (!param || !param.color) return null; const { color } = param; if (color.type === 'linear') { const { x, y, x2, y2, colorStops } = color; const angle = toCssAngle(x, y, x2, y2); const hint = colorStops.map((item) => { return `${item.color} ${item.offset * 100}%`; }); return `linear-gradient(${angle}deg, ${hint.join(',')})`; } else if (color.type === 'radial') { const { x, y, r, colorStops } = color; const hint = colorStops.map((item) => { return `${item.color} ${item.offset * 100}%`; }); return `radial-gradient(circle farthest-side at ${x} ${y}, ${hint.join(',')})`; } else { return color; } }; /** * 获取文字颜色值 * * @param {Object} param Formatter 单个数据集 * @returns 系列文字颜色 */ const colorAccessor = (param) => { if (!param || !param.color) return null; const { color } = param; if (color.type === 'linear' || color.type === 'radial') { const { colorStops } = color; return colorStops[0].color; } else { return color; } }; // const xlabelAccessor = (option, param) => { // const { xAxis, series } = option; // const { name, seriesIndex, axisValueLabel } = param; // const axisArr = isArray(xAxis) ? xAxis : !!xAxis ? [xAxis] : []; // const serieArr = isArray(series) ? series : !!series ? [series] : []; // const serie = serieArr[seriesIndex]; // const type = _.get(axisArr, [_.get(serie, 'xAxisIndex', 0), 'type'], 'category'); // // const formatter = _.get(axisArr, [_.get(serie, 'xAxisIndex', 0), 'axisLabel', 'formatter'], '{yyyy}-{MM}-{dd}'); // if (type === 'time') { // return axisValueLabel // } else { // return name; // } // }; /** * Tooltip头部样式内容 * * @param {Object} param Formatter 单个数据集 * @returns */ const headTemplate = (option, param) => { if (!param) return ''; const { name, axisValueLabel, axisType, axisValue } = param; const { tooltip } = option; const { timeFormat = 'YYYY-MM-DD HH:mm:ss' } = tooltip ?? {}; const text = axisType === 'xAxis.time' ? moment(axisValue).format(timeFormat) : name || axisValueLabel; return `<div style="border-bottom: 1px solid #F0F0F0; color: #808080; margin-bottom: 5px; padding-bottom: 5px;">${text}</div>`; }; /** * Tooltip每个系列样式内容 * * @param {Object} option 图表配置项 * @param {Object} param Formatter 单个数据集 * @returns */ const seriesTemplate = (option, param) => { if (!param) return ''; const value = valueAccessor(param); const unit = unitAccessor(option, param); const bgcolor = bgcolorAccessor(param); const color = colorAccessor(param); if (value === void 0 || value === null) return ''; return ` <div> <span style="display:inline-block;margin: 0 7px 2px 0;border-radius:5px;width:5px;height:5px;background:${bgcolor}"></span> <span>${param.seriesName}</span><span style="display:inline-block;">:</span><span style="color:${color};margin-left:10px">${value}</span> <span>${unit}</span> </div> `; }; // 默认tooltip配置 export const buildDefaultTooltip = (option) => { const cfg = { show: true, padding: [5, 10], trigger: 'axis', // 一般柱状图/曲线图都用axis,饼图/散点图等无类目的用item triggerOn: 'mousemove|click', renderMode: 'html', confine: true, // *是否限制在图表区域内 appendToBody: false, // *不挂到body标签下,挂载到图表容器节点 formatter: (params) => { let tooltipHeader = '', tooltipContent = ''; if (isArray(params)) { tooltipHeader = headTemplate(option, params[0]); params.forEach((param) => { tooltipContent += seriesTemplate(option, param); }); } else { tooltipHeader = headTemplate(option, params); tooltipContent += seriesTemplate(option, params); } return ` <div> ${tooltipHeader} <div>${tooltipContent}</div> </div> `; }, }; return cfg; };