// 图渲染逻辑模块 import {onMounted,ref,nextTick,reactive} from 'vue' import {chartDefaultOpts,scatterXAxis,basicYAxis,basicXAxis,leadUnitEnMap,relevanceUnitEnMap,seasonOptions} from './config' import Highcharts from 'highcharts/highstock'; import HighchartsFormat from 'highcharts'; import HighchartsMore from 'highcharts/highcharts-more'; import HightchartsExport from 'highcharts/modules/exporting'; import Boost from 'highcharts/modules/boost' import HighchartszhCN from './highcahrts-zh_CN.js' import moment from 'moment' import _ from 'lodash'; HighchartszhCN(Highcharts) HightchartsExport(Highcharts) HighchartsMore(Highcharts) Boost(Highcharts) /** * 渲染图方法 * @param data 图详情数据 * @param renderId 图表在dom中的id * @param lang 图表显示为中文/英文 默认 zh中文 en英文 * @param changeLangIsCheck 切换中英文时 是否要校验 * @param showChartTitle 是否显示图表标题 默认true */ let ChartIns=null//图表实例 let chartData=ref(null)//图的所有数据 let LangType=ref('zh')//当前图表显示的语言版本 let RenderDomId=ref('')//图表渲染的domid let options=ref(null)//渲染图的数据 const axisLimitState = reactive({//极值数据 leftIndex:-1,//左侧上下限对应下标 rightIndex: -1, //右侧上下限对应下标 rightTwoIndex: -1,//右2上下限对应下标 hasLeftAxis:false, hasRightAxis:false, hasRightTwoAxis:false, hasXAxis:false, leftMin:0, leftMax:0, rightMin:0, rightMax:0, rightTwoMin:0, rightTwoMax:0, xMin:0, xMax:0, }) //仅ETA图库内图表需要使用自定义上下限 let useSelfLimit = false let isUseSelfLimit = ref(false) const screen = ref(document.body.clientWidth < 1200 ? 'phone' : 'pc'); // webcomponent的EtaChart.ce.vue文件用到了这里的逻辑 // 有修改了 chartRender,setLimitData 这俩方法的,需要重新编辑下webcomponent(npm run build.lib),然后替换掉report项目的对应文件eta_comp.js export function useChartRender(){ return { options, axisLimitState, chartRender, setLimitData, isUseSelfLimit } } /**备注一下 越多越乱 * @params * Source 1 ; chartType只在source:1用到 1曲线 2季节 3面积 4堆积柱 5散点 6组合 7柱形 10截面散点 11雷达图 * 2 商品价格 * 3 相关性 * 4 滚动相关性 * 5 商品利润 * 6 拟合方程 * 7 统计特征/标准差 * 8 统计特征/百分位 * 9 统计特征/频率 * 10 跨品种分析 */ export function chartRender({data,renderId,lang='zh',changeLangIsCheck,showChartTitle=true,shouldUseSelfLimit=false}){ // 初始化掉极值数据 axisLimitState.leftIndex=-1 axisLimitState.rightIndex=-1 axisLimitState.rightTwoIndex=-1 axisLimitState.hasLeftAxis=false axisLimitState.hasRightAxis=false axisLimitState.hasRightTwoAxis=false axisLimitState.hasXAxis=false //使用自定义上下限时,不需要初始化极值 if(!isUseSelfLimit.value){ axisLimitState.leftMin=0 axisLimitState.leftMax=0 axisLimitState.rightMin=0 axisLimitState.rightMax=0 axisLimitState.rightTwoMin=0 axisLimitState.rightTwoMax=0 axisLimitState.xMin=0 axisLimitState.xMax=0 } let chartOpt={} LangType.value=lang RenderDomId.value=renderId chartData.value=data /* useSelfLimit = ['/myETA/chartdetail','/chartETA/chartdetail'].includes(window.location.pathname) */ useSelfLimit = shouldUseSelfLimit if([1,11].includes(data.ChartInfo.Source)){ const chartSetMap = { 1: setSplineOpt, 2: setSeasonOpt, 3: setStackOrCombinChart, 4: setStackOrCombinChart, 5: setScatterOptions, 6: setStackOrCombinChart, 7: initBarData, 10: setSectionScatterChart, 11: setRadarChart }; chartOpt=chartSetMap[data.ChartInfo.ChartType](data) }else if([2,5].includes(data.ChartInfo.Source)){//商品价格曲线 chartOpt=initCommodityData(data); }else if([3].includes(data.ChartInfo.Source)){//相关性 滚动相关性 chartOpt=initRelevanceChart(data); }else if([4,6,7,8].includes(data.ChartInfo.Source)){//滚动相关性 拟合方程 标准差 百分比 chartOpt=setSplineOpt(data); }else if([9].includes(data.ChartInfo.Source)){//统计频率 chartOpt=setStatisticFrequency(data); }else if(data.ChartInfo.Source===10) { /* 历史数据chartInfo里上下限全是空 兼容下历史数据不崩 */ axisLimitState.hasLeftAxis=true axisLimitState.leftMin=data.ChartInfo.LeftMin?Number(data.ChartInfo.LeftMin):Number(data.DataResp.YMinValue) axisLimitState.leftMax=data.ChartInfo.LeftMax?Number(data.ChartInfo.LeftMax):Number(data.DataResp.YMaxValue) axisLimitState.hasXAxis=true axisLimitState.xMin= data.ChartInfo.XMin?Number(data.ChartInfo.XMin):Number(data.DataResp.XMinValue) axisLimitState.xMax=data.ChartInfo.XMax?Number(data.ChartInfo.XMax):Number(data.DataResp.XMaxValue), chartOpt = setCrossVarietyChart(data) } /* eta1.4.1增加了主题色 仍然以defaultOpts为最底层配置 外层配置在这里统一设置了如legend chart背景色 x轴y轴系列等样式还是需要在具体的options中单独设置 */ let themeOptions = setThemeOptions(); options.value={...chartDefaultOpts,...themeOptions, ...chartOpt} // 设置图标题 setChartTitle(showChartTitle) // 设置语言 setChartLang(changeLangIsCheck) //stock不支持线形图只支持时间图 某些用chart let is_linear = chartOpt.series ? chartOpt.series.some(_ => _.chartType === 'linear') : false ; is_linear ?ChartIns=Highcharts.chart(RenderDomId.value,options.value) : ChartIns=Highcharts.stockChart(RenderDomId.value,options.value); return ChartIns } //主题色一些外层公用配置 目前只有绘图区和legend和colors function setThemeOptions() { if(!chartData.value.ChartInfo.ChartThemeStyle) return {} let chartTheme = JSON.parse(chartData.value.ChartInfo.ChartThemeStyle) return { legend: { ...chartDefaultOpts.legend, ...chartTheme.legendOptions }, chart: { ...chartDefaultOpts.chart, ...chartTheme.drawOption }, colors: chartTheme.colorsOptions } } /* 处理轴的标识线结构 在指定轴位置上拼接标识线 0:右轴 1:左轴 2:右2轴 x轴固定3 axisType表示x轴类型 处理时间轴的值 datetime/null */ function setAxisPlotLines(axis,axisType) { const { MarkersLines,ChartType } = chartData.value.ChartInfo; const { EdbInfoList } = chartData.value; if(!MarkersLines) return [] let markerLines = JSON.parse(MarkersLines); let arr = markerLines.filter(_ => _.isShow&&_.axis===axis) let plotLines = arr.map(_ => { //是否是x时间轴 let isXDateAxis = axis===3&&axisType==='datetime'; let markerValue; if(isXDateAxis) { //季节图x轴额外拼个年份 let nowYear = ChartType===2 ? new Date(EdbInfoList[0].DataList[1].DataList [0].DataTimestamp).getFullYear() : ''; markerValue = ChartType===2 ? new Date(`${nowYear}-${_.value}`).getTime() : new Date(_.value).getTime() }else { markerValue = Number(_.value) } return { value: markerValue, dashStyle: _.dashStyle, width: Number(_.lineWidth), color: _.color, label: { text: _.text||'', verticalAlign: _.textPosition, style: { color: _.textColor, fontSize: _.textFontSize } } } }) return plotLines } /* 处理标识区拼接 axisType表示x轴类型处理时间轴的值 datetime/null */ function setAxisPlotAreas(axis,axisType) { const { MarkersAreas,ChartType } = chartData.value.ChartInfo; const { EdbInfoList } = chartData.value; if(!MarkersAreas) return [] let markerAreas = JSON.parse(MarkersAreas); let arr = markerAreas.filter(_ => _.isShow&&_.axis===axis) let plotBands = arr.map(_ => { //是否是x时间轴 let isXDateAxis = axis===3&&axisType==='datetime'; let fromMarkerValue,toMarkerValue; if(isXDateAxis) { //季节图x轴额外拼个年份 let nowYear = ChartType===2 ? new Date(EdbInfoList[0].DataList[1].DataList [0].DataTimestamp).getFullYear() : ''; fromMarkerValue = ChartType===2 ? new Date(`${nowYear}-${_.fromValue}`).getTime() : new Date(_.fromValue).getTime() toMarkerValue = ChartType===2 ? new Date(`${nowYear}-${_.toValue}`).getTime() : new Date(_.toValue).getTime() }else { fromMarkerValue = Number(_.fromValue); toMarkerValue = Number(_.toValue); } //默认label有些偏移 重新归正下 let positionMapValue = { 'top': 12, 'middle': 0, 'bottom': -10 } return { from: fromMarkerValue, to: toMarkerValue, color: _.color, label: { text: _.text||'', verticalAlign: _.textPosition, y: positionMapValue[_.textPosition], style: { color: _.textColor, fontSize: _.textFontSize } } } }) return plotBands } /* 预测配置 分区 */ function getPredictParams ({LatestDate,PredictChartColor}) { return { zoneAxis: 'x', zones: [{ value: new Date(LatestDate).getTime()+1 }, { dashStyle: 'ShortDot', color: PredictChartColor }] } } /* 季节图预测数据 年份=分割点年份做分割 年份>分割点年份全为预测 */ function getSeasonPredictParams (timestamp){ return timestamp ? { zoneAxis: 'x', zones: [{ value: new Date(timestamp).getTime()+1 }, { dashStyle: 'ShortDot', }] } : {} } // 查询范围为1年内 x轴显示为月/日 否则默认年/月 function xTimeDiffer(minTime,maxTime,dateType){ //年限差 let year_differ=moment(maxTime).diff(moment(minTime),'years',true) // console.log('年限差',year_differ) if ([5, 6].includes(dateType) && year_differ <= 1) { return true } else { return false } } /* 拼接动态的指标名称小标签 */ function concatDynamicTag(item,lang){ const { IsAxis,IsOrder,EdbInfoType,LeadValue,LeadUnit } = item; // IsAxis左轴1 右轴0 2右2轴 //IsOrder正序false 逆序true //IsOrder正序false 逆序true //IsOrder正序false 逆序true //EdbInfoType是否是领先指标 const axisLabelMap =lang=='zh'? { 0: '右轴', 2: '右2轴' }:{ 0: 'RHS', 2: '2-RHS' } const orderLabelMap =lang=='zh'? { 1: '逆序' }:{ 1: 'REV' } const edbInfoMap =lang=='zh'? { 0: '领先' }:{ 0: 'Lead' } //英文领先单位转换 const leadUnit = lang==='zh' ? LeadUnit : leadUnitEnMap[LeadUnit]; let axis_tag = axisLabelMap[IsAxis] || ''; //逆序拼接 let order_tag = orderLabelMap[Number(IsOrder)] ? `${axis_tag ? ',': ''}${orderLabelMap[Number(IsOrder)]}` : '' //领先拼接 let edb_tag = edbInfoMap[EdbInfoType] ? `${(axis_tag||order_tag) ? ',' : '' }${edbInfoMap[EdbInfoType]}${LeadValue}${leadUnit}` : ''; let dynamic_tag = (axis_tag || order_tag || edb_tag) ? `(${axis_tag}${order_tag}${edb_tag})` : ''; return dynamic_tag } /* 拼接数据列动态name */ function setDyncmicSerieName (item,dynamic_arr,lang='zh') { let temName ='' /* if(lang=='zh'){ temName= dynamic_arr.length > 1 ? `${item.EdbName}(${item.SourceName})${concatDynamicTag(item,'zh')}` : `${item.EdbName}${concatDynamicTag(item,'zh')}` }else{ temName=item.EdbNameEn?`${item.EdbNameEn}${concatDynamicTag(item,'en')}`:'' } */ const temNameEn = item.EdbNameEn?`${item.EdbNameEn}${concatDynamicTag(item,'en')}`:'' const temNameZh = dynamic_arr.length > 1 ? `${item.EdbAliasName||item.EdbName}(${item.SourceName})${concatDynamicTag(item,'zh')}` : `${item.EdbAliasName||item.EdbName}${concatDynamicTag(item,'zh')}` temName = lang=='zh'?temNameZh:temNameEn?temNameEn:temNameZh if(temName.length>20){ let temArr=[] for(let i=0;i') } return temName } /* 指标顺序调整 IsAxis: 0右轴 1左轴 2右2*/ function changeEdbOrder (data){ // 左轴指标 let left_edbs = data.filter(_ => _.IsAxis===1); //右轴指标 let right_edbs = data.filter(_ => !_.IsAxis); // 右2轴指标 let right_two_edbs = data.filter(_ => _.IsAxis === 2); // 按 左 右 右2顺序排列 return [left_edbs,right_edbs,right_two_edbs].flat(Infinity); } //检查图表英文配置是否完整 function checkChartEnData(){ let result = true //图表名称:this.chartInfo.ChartNameEn if(!chartData.value.ChartInfo.ChartNameEn){ result = false } //指标名称:this.dataList[].EdbNameEn //指标单位:this.dataList[].UnitEn chartData.value.EdbInfoList.forEach(item=>{ if(!item.EdbNameEn){ result = false } if(chartData.value.ChartInfo.ChartType!==10&&item.Unit&&!item.UnitEn){ result = false } }) return result } // 设置图表显示的语言 function setChartLang(changeLangIsCheck){ if(changeLangIsCheck&&!checkChartEnData()) return const {ChartType,Source} = chartData.value.ChartInfo if(Source==1){ // 散点图 if(ChartType == 5){ options.value.yAxis.title.text = LangType.value == 'zh' ? options.value.yAxis.title.textZh : options.value.yAxis.title.textEn; // options.value.yAxis.title.style = LangType.value == 'zh' ? {} : options.value.yAxis.title.styleEn; options.value.xAxis.title.text = LangType.value == 'zh' ? options.value.xAxis.title.textZh : options.value.xAxis.title.textEn // options.value.xAxis.title.style = LangType.value == 'zh' ? {} : options.value.xAxis.title.styleEn; options.value.series.forEach(item => { item.name = LangType.value == 'zh' ? item.nameZh : item.nameEn; }); options.value.tooltip.formatter = LangType.value == 'zh' ? options.value.tooltip.formatterZh : options.value.tooltip.formatterEn; }else{ // 单位 options.value.yAxis.forEach(item => { item.title.text = LangType.value == 'zh' ? item.title.textZh : item.title.textEn; // item.title.style = LangType.value == 'zh' ? {} : (item.title.styleEn || {}) }); // 图例 名称 if(ChartType != 2){ // 季节图 不更改图例名称 options.value.series.forEach(item => { item.name = LangType.value == 'zh' ? item.nameZh : (item.nameEn!='无英文名称'?item.nameEn:`${item.nameEn}`) }); } //截面散点 x轴标题 if(ChartType === 10){ options.value.xAxis.title.text = LangType.value == 'zh' ? options.value.xAxis.title.textZh : options.value.xAxis.title.textEn; // options.value.xAxis.title.style = LangType.value == 'zh' ? {} : options.value.xAxis.title.styleEn; options.value.tooltip.formatter = LangType.value == 'zh' ? options.value.tooltip.formatterCh : options.value.tooltip.formatterEn; options.value.series.forEach(item => { if(!item.linkedTo) { item.data.forEach(point => { point.dataLabels.format = LangType.value == 'zh' ? point.dataLabels.formatZh : (point.dataLabels.formatEn||'无英文标签'); point.dataLabels.color = (LangType.value==='en' && !point.dataLabels.formatEn) ? '#999' : '#333' }) } }); } //柱形图额外设置x轴中英文 if([7,11].includes(ChartType)){ //x轴 options.value.xAxis.categories = chartData.value.XEdbIdValue.map(_ => LangType.value == 'zh' ? chartData.value.EdbInfoList.find(edb => edb.EdbInfoId===_).EdbAliasName || chartData.value.EdbInfoList.find(edb => edb.EdbInfoId===_).EdbName : chartData.value.EdbInfoList.find(edb => edb.EdbInfoId===_).EdbNameEn) } } } if([2,3,4].includes(Source)){ options.value.yAxis.forEach(item => { item.title.text = LangType.value == 'zh' ? item.title.textZh: item.title.textEn||item.title.textZh }); //图例 options.value.series.forEach(item => { item.name = LangType.value == 'en' ?(item.nameEn||item.nameZh) : item.nameZh }); //tooltip options.value.tooltip.formatter = LangType.value == 'en'?options.value.tooltip.formatterEn:options.value.tooltip.formatterZh //x轴 if(Source==2){ options.value.xAxis.categories = commodityXData.value.map(_ => { LangType.value == 'en'?_.NameEn:_.Name }); } if([3].includes(Source)){ options.value.xAxis.title.text=LangType.value == 'en'?(options.value.xAxis.title.textEn||options.value.xAxis.title.textZh):options.value.xAxis.title.textZh } } } // 设置图标题 function setChartTitle(showChartTitle){ if(showChartTitle){ const ChartInfo=chartData.value.ChartInfo options.value.title.textZh=ChartInfo.ChartName options.value.title.textEn=ChartInfo.ChartNameEn options.value.title.text=LangType.value == 'zh' ?options.value.title.textZh:options.value.title.textEn||options.value.title.textZh }else{ options.value.title.text='' } } //统计频率图 function setStatisticFrequency(e){ axisLimitState.leftIndex=-1 axisLimitState.rightIndex=-1 axisLimitState.rightTwoIndex=-1 /* 主题样式*/ const chartTheme = e.ChartInfo.ChartThemeStyle ? JSON.parse(e.ChartInfo.ChartThemeStyle) : null; const { DataList,LeftMaxValue,LeftMinValue,RightMaxValue,RightMinValue } = e.DataResp; const xAxis = { ...scatterXAxis, tickWidth: 1, labels: { style: { ...chartTheme&&chartTheme.xAxisOptions.style } } } //y和系列 let yAxis = [],series = []; DataList.forEach((item,index) => { let y_item = { ...basicYAxis, title: { text: item.Unit, textCh:item.Unit,// 中文 textEn:item.UnitEn||item.Unit, align: 'high', rotation: 0, y: -15, reserveSpace: false, style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, }, labels: { style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, }, opposite: item.IsAxis===1?false:true, min: index===0? Number(LeftMinValue):Number(RightMinValue), max: index===0? Number(LeftMaxValue):Number(RightMaxValue), tickWidth: 1, } //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模 const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index let series_item = { data: item.Value.map(_ =>[_.X,_.Y]), dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid', type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || 'spline', yAxis: index, name: item.Name, nameZh: item.Name, nameEn: item.NameEn||item.Name, color: item.Color, lineWidth: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth)||3, chartType: 'linear', zIndex:1 } series.push(series_item); yAxis.push(y_item) }) let tooltip = { formatter: function() { let xList = DataList[0].Value.map(_ =>_.X); let step = xList[1]-xList[0]; let data_interval = `[${this.x},${this.x+step}]`; let str=`${ data_interval }`; this.points.forEach(item => { str += `
\u25CF${item.series.name}: ${item.y}%
` }) return str }, shared: true } return { title: { text:'' }, tooltip, series, yAxis, xAxis } } //曲线图 function setSplineOpt(e){ //其他Source也会用到曲线图,这里需要兼容 const isETASource = e.ChartInfo.Source===1 const data=[4,6,7,8].includes(e.ChartInfo.Source)?[e.DataResp]:e.EdbInfoList let series=[] let yAxis=[] let xAxis = {} let temYLeftArr=[] let temYRightArr=[] let temYRightTwoArr = [] let temYLeftIndex=data.findIndex((item) => item.IsAxis===1) let temYRightIndex=data.findIndex((item) => !item.IsAxis) let temYRightTwoIndex = data.findIndex((item) => item.IsAxis===2) axisLimitState.leftIndex=temYLeftIndex axisLimitState.rightIndex=temYRightIndex axisLimitState.rightTwoIndex=temYRightTwoIndex /* 主题样式*/ const chartTheme = e.ChartInfo.ChartThemeStyle ? JSON.parse(e.ChartInfo.ChartThemeStyle) : null; let minAndMaxTimeTemArr=[]//存放所有指标的最大最小时间 //有右二轴时排个序 按照左 右 右2的顺序 let newData = data.some(_ =>_.IsAxis===2) ? changeEdbOrder(data) : data; newData.forEach((item,index)=>{ //轴位置值相同的下标 let sameSideIndex = newData.findIndex(i => i.IsAxis === item.IsAxis); let dynamic_title = item.EdbName; let dynamic_arr = newData.filter( (item) => dynamic_title === item.EdbName ); //处理数据列name let temName= setDyncmicSerieName(item,dynamic_arr,'zh') let temNameEN=setDyncmicSerieName(item,dynamic_arr,'en') //预测指标配置 let predict_params = item.EdbInfoCategoryType === 1 ? getPredictParams(item) : {}; //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模 const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index let seriesItemObj={ data:[], dataGrouping:{ enabled:false }, type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || 'spline', dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid', yAxis:index, name:temName, nameZh:temName, nameEn:temNameEN, color: item.ChartColor, lineWidth: Number(item.ChartWidth)||(chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth)||1, visible:true, LatestDate:item.LatestDate, LatestValue:item.LatestValue, marker:chartTheme && chartTheme.lineOptionList[lineIndex].dataMark && chartTheme.lineOptionList[lineIndex].dataMark!='none'?{ enabled:true, symbol: chartTheme.lineOptionList[lineIndex].markType || 'circle', fillColor:chartTheme.lineOptionList[lineIndex].markColor, radius: chartTheme.lineOptionList[lineIndex].markSize }:{}, ...predict_params } item.DataList = item.DataList || []; for (let i of item.DataList) { seriesItemObj.data.push([i.DataTimestamp, i.Value]); } series.push(seriesItemObj) // 设置y轴 if(item.IsAxis){ temYLeftArr.push(item) }else{ temYRightArr.push(item) } //获取上下限 console.log('useSelfLimit',useSelfLimit) let minLimit = 0,maxLimit = 0 if(!useSelfLimit||!isETASource){ minLimit = item.MinData maxLimit = item.MaxData } if(useSelfLimit&&isETASource){ const limitMap = { 0:['rightMin','rightMax'], 1:['leftMin','leftMax'], 2:['rightTwoMin','rightTwoMax'] } if(limitMap[item.IsAxis]){ minLimit = axisLimitState[`${limitMap[item.IsAxis][0]}`]||0 maxLimit = axisLimitState[`${limitMap[item.IsAxis][1]}`]||0 } } const textZh = item.ConvertUnit||item.Unit const textEn = item.ConvertEnUnit||item.UnitEn||item.ConvertUnit||item.Unit let yItem={ ...basicYAxis, IsAxis:item.IsAxis, labels: { formatter: function (ctx) { return sameSideIndex !== index ? '' : ctx.value; }, align: 'center', x: [0,2].includes(item.IsAxis) ? 5 : -5, style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, }, tickWidth: sameSideIndex !== index ? 0 : 1, title: { text: sameSideIndex !== index ? '' : `${textZh}`, textZh:textZh,//中文单位 textEn:textZh?textEn:'',//英文单位,但如果无中文单位则不显示 align: 'high', rotation: 0, y: -15, x: (item.IsAxis===0 && temYRightTwoIndex>-1) ? -newData[temYRightTwoIndex].Unit.length*12 : 0, textAlign: item.IsAxis===1 ? 'left' : 'right', reserveSpace: false, style:{ ...chartTheme&&chartTheme.yAxisOptions.style } }, opposite: [0,2].includes(item.IsAxis), reversed: item.IsOrder, min: Number(minLimit), max: Number(maxLimit), visible: sameSideIndex === index, chartEdbInfo:item,//指标数据用于在保存时读取指标数据 plotBands: setAxisPlotAreas(item.IsAxis), plotLines: setAxisPlotLines(item.IsAxis) } yAxis.push(yItem) if(item.DataList.length>0){ minAndMaxTimeTemArr.push(item.DataList[0].DataTimestamp) minAndMaxTimeTemArr.push(item.DataList[item.DataList.length-1].DataTimestamp) } }) // 设置x轴 // 找出所有指标的最大和最小时间 分成6段 let minTime=Math.min.apply(null,minAndMaxTimeTemArr) let maxTime=Math.max.apply(null,minAndMaxTimeTemArr) const isLessThanOneYear = xTimeDiffer(minTime,maxTime,e.ChartInfo.DateType) xAxis={ ...basicXAxis, labels: { formatter: function (ctx) { return isLessThanOneYear ? HighchartsFormat.dateFormat('%m/%d', ctx.value) : HighchartsFormat.dateFormat('%y/%m', ctx.value); }, style: { ...chartTheme&&chartTheme.xAxisOptions.style } }, tickInterval:screen.value === 'phone'?((maxTime-minTime)/6)/(24*3600*1000)>30?(maxTime-minTime)/6:24*3600*1000*30:undefined, plotBands: setAxisPlotAreas(3,'datetime'), plotLines: setAxisPlotLines(3,'datetime') } yAxis.forEach(item=>{ if(item.IsAxis===1){//左轴 axisLimitState.hasLeftAxis=true if(!useSelfLimit||!isETASource){ axisLimitState.leftMin=data[temYLeftIndex].MinData axisLimitState.leftMax=data[temYLeftIndex].MaxData item.min=data[temYLeftIndex].MinData item.max=data[temYLeftIndex].MaxData } }else if (item.IsAxis===2){ // 右2轴 axisLimitState.hasRightTwoAxis=true if(!useSelfLimit||!isETASource){ axisLimitState.rightTwoMin=data[temYRightTwoIndex].MinData axisLimitState.rightTwoMax=data[temYRightTwoIndex].MaxData item.min=data[temYRightTwoIndex].MinData item.max=data[temYRightTwoIndex].MaxData } }else{ axisLimitState.hasRightAxis=true if(!useSelfLimit||!isETASource){ axisLimitState.rightMin=data[temYRightIndex].MinData axisLimitState.rightMax=data[temYRightIndex].MaxData item.min=data[temYRightIndex].MinData item.max=data[temYRightIndex].MaxData } } }) return { series, xAxis:[xAxis], yAxis, rangeSelector:{ enabled: false} } } //季节图 function setSeasonOpt(e){ axisLimitState.leftIndex=0 const {RightAxis:SeasonRightConfig={}} = e.DataResp||{} axisLimitState.rightIndex=SeasonRightConfig.IsShow?1:-1 axisLimitState.rightTwoIndex=-1 /* 主题样式*/ const chartTheme = e.ChartInfo.ChartThemeStyle ? JSON.parse(e.ChartInfo.ChartThemeStyle) : null; let chartData={} const data=e.EdbInfoList[0] const calendarType=e.ChartInfo.Calendar||'公历' const colorsArr=chartTheme&&chartTheme.colorsOptions.reverse(); let series=[],yAxis=[] //农历默认选中一年数据并隐藏按钮 公历显示全部数据 // 农历数据需要去除第一项 农历和公历处理逻辑一样 const chartDataHandle=calendarType === '农历'? data.DataList.filter((item, index) => index > 0): data.DataList // 跟颜色对应 chartTheme && (chartTheme.lineOptionList=chartTheme.lineOptionList.reverse().slice(-chartDataHandle.length)) let maxDateRange=0 // if(calendarType==='公历'){ //常规左轴 chartDataHandle.forEach((item,index)=>{ //预测指标配置 let predict_params = data.EdbInfoCategoryType === 1 ? getSeasonPredictParams(item.CuttingDataTimestamp) : {}; //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模 const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index let seriesItem={ data:[], dataGrouping:{ enabled:false }, type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || data.ChartStyle, dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid', yAxis:0, name:item.ChartLegend, lineWidth: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth) || 1, // color:colorsArr.slice(-chartDataHandle.length)[lineIndex], //与PC端的配置不同步,导致两边 十条之后的线条颜色不对应 visible:true, marker:chartTheme && chartTheme.lineOptionList[lineIndex].dataMark && chartTheme.lineOptionList[lineIndex].dataMark!='none'?{ enabled:true, symbol: chartTheme.lineOptionList[lineIndex].markType || 'circle', fillColor:chartTheme.lineOptionList[lineIndex].markColor, radius: chartTheme.lineOptionList[lineIndex].markSize }:{}, ...predict_params } item.DataList=item.DataList||[] let dateRange = item.DataList[item.DataList.length-1].DataTimestamp - item.DataList[0].DataTimestamp // 时间范围 maxDateRange=Math.max(maxDateRange,dateRange) for(let i of item.DataList){ seriesItem.data.push([i.DataTimestamp, i.Value]) } series.push(seriesItem) }) chartData.colors = colorsArr.slice(-chartDataHandle.length) //同期上下限/均线/标准差 const {MaxMinLimits={},SamePeriodAverage={},SamePeriodStandardDeviation={}} = e.DataResp||{} if(MaxMinLimits.IsShow&&MaxMinLimits.List&&MaxMinLimits.List.length){ let serieItem = { type:'arearange',//上下限是一个范围 data:[], name:MaxMinLimits.Legend||'同期上下限', color:MaxMinLimits.Color||'#075EEE' , fillOpacity:parseRgbaColor(MaxMinLimits.Color||'')>0.75?0.75:parseRgbaColor(MaxMinLimits.Color||'') //透明度最高0.75 } MaxMinLimits.List.forEach(item=>{ serieItem.data.push([item.DataTimestamp,item.MinValue,item.MaxValue]) }) series.push(serieItem) } if(SamePeriodAverage.IsShow&&SamePeriodAverage.List){ let serieItem = { type:'line', data:[], lineWidth:SamePeriodAverage.LineWidth, dashStyle:SamePeriodAverage.LineType, name:SamePeriodAverage.Legend||'同期均值', color:SamePeriodAverage.Color||'#075EEE' } SamePeriodAverage.List.forEach(item=>{ serieItem.data.push([item.DataTimestamp,item.Value]) }) series.push(serieItem) } if(SamePeriodStandardDeviation.IsShow&&SamePeriodStandardDeviation.List){ let serieItem = { type:'arearange',//标准差也是一个范围 data:[], name:SamePeriodStandardDeviation.Legend||'同期标准差', color:SamePeriodStandardDeviation.Color||'#075EEE', fillOpacity:parseRgbaColor(SamePeriodStandardDeviation.Color||'')>0.75?0.75:parseRgbaColor(SamePeriodStandardDeviation.Color||'') } SamePeriodStandardDeviation.List.forEach(item=>{ serieItem.data.push([item.DataTimestamp,item.MinValue,item.MaxValue]) }) series.push(serieItem) } //右轴 if(SeasonRightConfig.IsShow){ //右轴的设置 let serieConfig = SeasonRightConfig.Style==='column'?{ //柱形 type:'column', color:SeasonRightConfig.ChartColor }:{ //标记点 type:'spline', lineWidth:SeasonRightConfig.LineWidth, dashStyle:SeasonRightConfig.LineStyle, color:SeasonRightConfig.IsConnected?SeasonRightConfig.LineColor:'rgba(255, 255, 255, 0)',//没有连线颜色设置为透明 marker:{ enabled:true, symbol:SeasonRightConfig.Shape, fillColor:SeasonRightConfig.ChartColor, radius:SeasonRightConfig.Size }, } let serieItem = { ...serieConfig, name:SeasonRightConfig.Legend||'', data:[], yAxis:1, } const DataList = (SeasonRightConfig.IndicatorType===1?SeasonRightConfig.EdbInfoList[0].DataList:e.EdbInfoList[1]?.DataList)||[] DataList.forEach(item=>{ serieItem.data.push([item.DataTimestamp,item.Value]) }) series.push(serieItem) } //获取上下限 let minLimit = 0,maxLimit = 0,rightMin = 0,rightMax = 0 //非ETA图库不使用自定义上下限 非ETA图库的季节性图也不能设置右轴 if(!useSelfLimit){ minLimit = data.MinData maxLimit = data.MaxData }else{ minLimit = axisLimitState.leftMin||0 maxLimit = axisLimitState.leftMax||0 //右轴上下限设置 if(axisLimitState.rightIndex!==-1){ rightMin = axisLimitState.rightMin||0 rightMax = axisLimitState.rightMax||0 } } const textZh = data.ConvertUnit||data.Unit const textEn = data.ConvertEnUnit||data.UnitEn||data.ConvertUnit||data.Unit yAxis=[{ IsAxis:data.IsAxis, labels: { align: 'center', y:5, style: { ...chartTheme&&chartTheme.yAxisOptions.style } }, title: { text: `${textZh}`, textZh:textZh, // 中文 // 中文不存在,无论英文有无都显示空 textEn:textZh?textEn||'英文单位':'', // 英文 align: 'high', rotation: 0, y: -5, x: 0, textAlign: 'left', reserveSpace: false, style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, }, max: Number(maxLimit), min: Number(minLimit), plotBands: setAxisPlotAreas(1), plotLines: setAxisPlotLines(1), lineWidth: 1, lineColor: '#bfbfbf', tickColor: '#bfbfbf', offset: 0, opposite: false, reversed: false, visible: true, gridLineWidth: 0, tickWidth: 1, tickLength:5, tickPosition: 'inside', endOnTick: false, startOnTick: false, showLastLabel: true, //显示最后刻度值 tickPixelInterval: 50, // chartEdbInfo:item//指标数据 }] //如果有右轴,yAxis加上右轴 if(SeasonRightConfig.IsShow){ const rightEdb = (SeasonRightConfig.IndicatorType===1?SeasonRightConfig.EdbInfoList[0]:e.EdbInfoList[1])||{Unit:''} //左轴同比:text为空或% 右轴指标:取指标单位 if(SeasonRightConfig.IndicatorType===1){ rightEdb.Unit = SeasonRightConfig.NumFormat===1?'%':'' }else{ rightEdb.Unit = e.EdbInfoList[1]&&(e.EdbInfoList[1].ConvertUnit||e.EdbInfoList[1].Unit)||'' } yAxis.push({ ...seasonOptions.yAxis, opposite: true,//右轴 labels: { align: 'center', y:5, style: { ...chartTheme&&chartTheme.yAxisOptions.style } }, title: { text: rightEdb.Unit||'', style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, align: 'high', rotation: 0, y: -5, x: 0, textAlign: 'right', reserveSpace: false, }, max: Number(rightMax), min: Number(rightMin), }) } chartData.series=series chartData.yAxis=yAxis // chartData.rangeSelector=rangeSelector // 设置坐标轴极值 axisLimitState.hasLeftAxis=true if(!useSelfLimit){ axisLimitState.leftMin=Number(data.MinData) axisLimitState.leftMax=Number(data.MaxData) } // 季节图x轴显示月/日 let xAxis={ tickPosition: 'inside', lineColor: '#bfbfbf', tickColor: '#bfbfbf', tickLength:5, type: 'datetime', ordinal: false, dateTimeLabelFormats: { day: '%y/%m', week: '%y/%m', month: '%y/%m', year: '%y/%m', }, labels: { formatter: (ctx)=> { return HighchartsFormat.dateFormat('%m/%d', ctx.value) }, style: { ...chartTheme&&chartTheme.xAxisOptions.style } }, tickInterval:screen.value === 'phone'?maxDateRange/6:undefined,//季节图 plotBands: setAxisPlotAreas(3,'datetime'), plotLines: setAxisPlotLines(3,'datetime') } chartData.xAxis=[xAxis] // 季节图提示框显示 月/日 chartData.tooltip={ split: false, shared: true, dateTimeLabelFormats: { // 时间格式化字符 day: '%m/%d', week: '%m/%d', month: '%m/%d', year: '%m/%d', }, xDateFormat: '%m/%d', } return { ...chartData, // title: { // enabled: true, // text:e.ChartInfo.ChartName // }, // legend:{ // enabled:true, // verticalAlign: 'top', // y:-10, // x:(10 * data.Unit.length)/2 // } } } //堆叠图/组合图设置 //本来和曲线图逻辑基本一致兼容下即可 为了以后便于维护和阅读还是拆开写吧 function setStackOrCombinChart(e){ const data=e.EdbInfoList //图表类型 const chartTypeMap = { 3: 'areaspline', 4: 'column', 6: '' }; let chartStyle = chartTypeMap[e.ChartInfo.ChartType]; /* 主题样式*/ const chartTheme = e.ChartInfo.ChartThemeStyle ? JSON.parse(e.ChartInfo.ChartThemeStyle) : null; let series=[] let yAxis=[] let xAxis = {} let temYLeftArr=[] let temYRightArr=[] let temYRightTwoArr = [] let temYLeftIndex,temYRightIndex,temYRightTwoIndex; let minAndMaxTimeTemArr=[]//存放所有指标的最大最小时间 //有右二轴时排个序 按照左 右 右2的顺序 let newData = data.some(_ =>_.IsAxis===2) ? changeEdbOrder(data) : data; newData.forEach((item,index)=>{ //轴位置值相同的下标 let sameSideIndex = newData.findIndex(i => i.IsAxis === item.IsAxis); //堆叠图的yAxis必须一致 数据列所对应的y轴 let serie_yIndex = index; if([3,4].includes(e.ChartInfo.ChartType)) { // 类型为堆叠图时公用第一个指标y轴 serie_yIndex = 0; } else if(e.ChartInfo.ChartType ===6 && ['areaspline','column'].includes(item.ChartStyle)) { // 组合图找第一个堆叠柱状或面积的作为公用 serie_yIndex = newData.findIndex(i => i.ChartStyle === item.ChartStyle); } //数据对应的y轴是公用轴则配置也共享 item.IsAxis = serie_yIndex === index ? item.IsAxis : newData[serie_yIndex].IsAxis; item.IsOrder = serie_yIndex === index ? item.IsOrder : newData[serie_yIndex].IsOrder; temYLeftIndex = [3,4].includes(e.ChartInfo.ChartType) ? (newData[serie_yIndex].IsAxis ? serie_yIndex : -1) : data.findIndex((item) => item.IsAxis===1); temYRightIndex = [3,4].includes(e.ChartInfo.ChartType) ? (newData[serie_yIndex].IsAxis ? -1 : serie_yIndex) : data.findIndex((item) => !item.IsAxis); temYRightTwoIndex = [3,4].includes(e.ChartInfo.ChartType) ? -1 : data.findIndex((item) => item.IsAxis===2); axisLimitState.leftIndex=temYLeftIndex axisLimitState.rightIndex=temYRightIndex axisLimitState.rightTwoIndex=temYRightTwoIndex let dynamic_title = item.EdbName; let dynamic_arr = newData.filter( (item) => dynamic_title === item.EdbName ); //处理数据列name let temName= setDyncmicSerieName(item,dynamic_arr,'zh') let temNameEN=setDyncmicSerieName(item,dynamic_arr,'en') //预测指标配置 let predict_params = item.EdbInfoCategoryType === 1 ? getPredictParams(item) : {}; //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模 const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index let seriesItemObj={ data:[], dataGrouping:{ enabled:false }, type: chartStyle || item.ChartStyle, yAxis:serie_yIndex, name:temName, nameZh:temName, nameEn:temNameEN, color: item.ChartColor, lineWidth: Number(item.ChartWidth)||(chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth) || 1, fillColor: (e.ChartInfo.ChartType === 3 || (e.ChartInfo.ChartType === 6 && item.ChartStyle === 'areaspline')) ? item.ChartColor : undefined, visible:true, LatestDate:item.LatestDate, LatestValue:item.LatestValue, ...predict_params } item.DataList = item.DataList || []; for (let i of item.DataList) { seriesItemObj.data.push([i.DataTimestamp, i.Value]); } series.push(seriesItemObj) //获取上下限 let minLimit = 0,maxLimit = 0 //非ETA图库不使用自定义上下限 if(!useSelfLimit){ minLimit = newData[sameSideIndex].MinData maxLimit = newData[sameSideIndex].MaxData }else{ const limitMap = { 0:['rightMin','rightMax'], 1:['leftMin','leftMax'], 2:['rightTwoMin','rightTwoMax'] } if(limitMap[item.IsAxis]){ minLimit = axisLimitState[`${limitMap[item.IsAxis][0]}`]||0 maxLimit = axisLimitState[`${limitMap[item.IsAxis][1]}`]||0 } } // 设置y轴 if(item.IsAxis){ temYLeftArr.push(item) }else{ temYRightArr.push(item) } const textZh = item.ConvertUnit||item.Unit const textEn = item.ConvertEnUnit||item.UnitEn||item.ConvertUnit||item.Unit let yItem={ ...basicYAxis, IsAxis:item.IsAxis, labels: { formatter: function (ctx) { return sameSideIndex !== index ? '' : ctx.value; }, align: 'center', x: [0,2].includes(item.IsAxis) ? 5 : -5, style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, }, title: { // text: sameSideIndex !== index ? '' : `${item.Unit}`, text: textZh, textZh:textZh, // 中文 // 中文不存在,无论英文有无都显示空 textEn:textZh?textEn||'英文单位':'', // 英文 align: 'high', rotation: 0, y: -15, x: (item.IsAxis===0 && temYRightTwoIndex>-1) ? -newData[temYRightTwoIndex].Unit.length*12 : 0, textAlign: item.IsAxis===1 ? 'left' : 'right', reserveSpace: false, style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, }, opposite: [0,2].includes(item.IsAxis), reversed: item.IsOrder, min: Number(minLimit), max: Number(maxLimit), tickWidth: sameSideIndex !== index ? 0 : 1, visible: serie_yIndex === index && sameSideIndex ===index, plotBands: setAxisPlotAreas(item.IsAxis), plotLines: setAxisPlotLines(item.IsAxis), chartEdbInfo:item//指标数据用于在保存时读取指标数据 } yAxis.push(yItem) if(item.DataList.length>0){ minAndMaxTimeTemArr.push(item.DataList[0].DataTimestamp) minAndMaxTimeTemArr.push(item.DataList[item.DataList.length-1].DataTimestamp) } }) // 设置x轴 // 找出所有指标的最大和最小时间 分成6段 let minTime=Math.min.apply(null,minAndMaxTimeTemArr) let maxTime=Math.max.apply(null,minAndMaxTimeTemArr) const isLessThanOneYear = xTimeDiffer(minTime,maxTime,e.ChartInfo.DateType) xAxis={ ...basicXAxis, labels: { formatter: function (ctx) { return isLessThanOneYear ? HighchartsFormat.dateFormat('%m/%d', ctx.value) : HighchartsFormat.dateFormat('%y/%m', ctx.value); }, style: { ...chartTheme&&chartTheme.xAxisOptions.style } }, tickInterval:screen.value === 'phone'?((maxTime-minTime)/6)/(24*3600*1000)>30?(maxTime-minTime)/6:24*3600*1000*30:undefined, plotBands: setAxisPlotAreas(3,'datetime'), plotLines: setAxisPlotLines(3,'datetime') } yAxis.forEach(item=>{ if(item.IsAxis === 1){//左轴 axisLimitState.hasLeftAxis=true if(!useSelfLimit){ axisLimitState.leftMin=data[temYLeftIndex].MinData axisLimitState.leftMax=data[temYLeftIndex].MaxData item.min=data[temYLeftIndex].MinData item.max=data[temYLeftIndex].MaxData } }else if (item.IsAxis===2){ // 右2轴 axisLimitState.hasRightTwoAxis=true if(!useSelfLimit){ axisLimitState.rightTwoMin=data[temYRightTwoIndex].MinData axisLimitState.rightTwoMax=data[temYRightTwoIndex].MaxData item.min=data[temYRightTwoIndex].MinData item.max=data[temYRightTwoIndex].MaxData } }else{ axisLimitState.hasRightAxis=true if(!useSelfLimit){ axisLimitState.rightMin=data[temYRightIndex].MinData axisLimitState.rightMax=data[temYRightIndex].MaxData item.min=data[temYRightIndex].MinData item.max=data[temYRightIndex].MaxData } } }) return { series, xAxis:xAxis, yAxis, rangeSelector:{ enabled: false} } } /* 散点图 第一个指标值为x轴 第二个指标为y轴*/ function setScatterOptions(data){ axisLimitState.leftIndex=1 axisLimitState.rightIndex=-1 axisLimitState.rightTwoIndex=-1 const dataList=data.EdbInfoList const { ChartInfo } = data; /* 主题样式*/ const chartTheme = ChartInfo.ChartThemeStyle ? JSON.parse(ChartInfo.ChartThemeStyle) : null; //上下限设置的是y轴,也就是第二个指标的值,改回来 axisLimitState.hasLeftAxis=true /* axisLimitState.leftMin=Number(dataList[1].MinData) axisLimitState.leftMax=Number(dataList[1].MaxData) axisLimitData.leftMin=Number(dataList[1].MinData) axisLimitData.leftMax=Number(dataList[1].MaxData) */ // 取2个指标中日期相同的数据 const real_data = []; let tmpData_date = {};//用来取点对应的日期 let data1 = _.cloneDeep(dataList)[0].DataList || []; let data2 = _.cloneDeep(dataList)[1].DataList || []; data1.forEach((_item) => { data2.forEach((_item2) => { if(_item.DataTimestamp === _item2.DataTimestamp) { //日期 let itemIndex =_item.Value + "_" +_item2.Value if(tmpData_date[itemIndex]) { tmpData_date[itemIndex].push( moment(_item.DataTimestamp).format('YYYY/MM/DD')) } else { tmpData_date[itemIndex] = [moment(_item.DataTimestamp).format('YYYY/MM/DD')] } //值 real_data.push({ x: _item.Value, y: _item2.Value }) } }) }) real_data.sort((x,y) => x-y); //悬浮窗 拼接日期 原始指标名称 let tooltip = { formatter: function() { return `${ tmpData_date[this.x+'_'+this.y].length > 4 ? tmpData_date[this.x+'_'+this.y].slice(0,4).join()+'...' : tmpData_date[this.x+'_'+this.y].join() }
${dataList[0].EdbName}: ${this.x}
${dataList[1].EdbName}: ${this.y} ` }, // 中文 formatterCh: function() { return `${ tmpData_date[this.x+'_'+this.y].length > 4 ? tmpData_date[this.x+'_'+this.y].slice(0,4).join()+'...' : tmpData_date[this.x+'_'+this.y].join() }
${dataList[0].EdbName}: ${this.x}
${dataList[1].EdbName}: ${this.y} ` }, // 英文 formatterEn: function() { let str1 = `${dataList[0].EdbNameEn}` let str2 = `${dataList[1].EdbNameEn}` return `${ tmpData_date[this.x+'_'+this.y].length > 4 ? tmpData_date[this.x+'_'+this.y].slice(0,4).join()+'...' : tmpData_date[this.x+'_'+this.y].join() }
${str1}: ${this.x}
${str2}: ${this.y} ` } } const { IsOrder,ChartColor } = dataList[0]; //获取上下限 let minLimit = 0,maxLimit = 0 if(!useSelfLimit){ minLimit = data.ChartInfo.LeftMin||0; maxLimit = data.ChartInfo.LeftMax||0; }else{ minLimit = axisLimitState.leftMin||0 maxLimit = axisLimitState.leftMax||0 } console.log('check limit',minLimit,maxLimit) const textYZh = dataList[1].ConvertUnit||dataList[1].Unit const textYEn = dataList[1].ConvertEnUnit||dataList[1].UnitEn||dataList[1].ConvertUnit||dataList[1].Unit //y轴 let yAxis = { title: { text: `${textYZh}`, textZh:textYZh, textEn:textYZh?textYEn:'', align: 'high', rotation: 0, y: -15, x:0, textAlign: 'left', reserveSpace: false, style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, }, labels: { formatter: function (ctx) { return ctx.value; }, align: 'center', style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, }, opposite: false, reversed: IsOrder, min: Number(minLimit), max: Number(maxLimit), tickWidth: 1, tickLength: 5, lineWidth: 1, lineColor: '#bfbfbf', tickColor: '#bfbfbf', offset: 0, visible: true, gridLineWidth: 0, tickPosition: 'inside', endOnTick: false, startOnTick: false, showLastLabel: true, tickPixelInterval: 50, plotBands: setAxisPlotAreas(1), plotLines: setAxisPlotLines(1) } //数据列 let series = { data: [], type: 'scatter', name: `${ChartInfo.ChartName}${IsOrder ? '(逆序)' : ''}`, nameZh:`${ChartInfo.ChartName}${IsOrder ? '(逆序)' : ''}`, nameEn:ChartInfo.ChartNameEn?`${ChartInfo.ChartNameEn}${IsOrder ? '(reverse)' : ''}`:'', color: ChartColor, visible:true, chartType: 'linear', marker: { radius: (chartTheme&&chartTheme.lineOptionList[0].radius)||5, }, } real_data.forEach(_ => { series.data.push([_.x,_.y]) }) const textXZh = dataList[0].ConvertUnit||dataList[0].Unit const textXEn = dataList[0].ConvertEnUnit||dataList[0].UnitEn||dataList[0].ConvertUnit||dataList[0].Unit return { title: { text:'' }, series: [ series ], yAxis, xAxis: { ...scatterXAxis, title: { text: `${textXZh}`, textZh:textXZh, textEn:textXZh?textXEn:'', align: 'high', rotation: 0, x: 0, offset: 20, style: { ...chartTheme&&chartTheme.xAxisOptions.style }, }, labels: { style: { ...chartTheme&&chartTheme.xAxisOptions.style } }, }, tooltip } } /* 奇怪柱形图 */ const barDateList = ref([]);//柱形图的绘图数据 const barXData = ref([]);//柱形图的x轴 const barEdbData = ref([]);//柱形图的表格数据 只用于取值 let axisLimitData={} /* 奇怪柱状图 和其他逻辑无公用点 依赖数据为单独的数据 x轴为指标名称的柱形图 以日期作为series */ function setBarChart (e){ let seriesData = []; const data = _.cloneDeep(barDateList.value); /* 主题样式*/ const chartTheme = e.ChartInfo.ChartThemeStyle ? JSON.parse(e.ChartInfo.ChartThemeStyle) : null; //x轴 let xAxis = { ...scatterXAxis, categories: barXData.value, tickWidth: 1, labels: { style: { ...chartTheme&&chartTheme.xAxisOptions.style } } } const { leftMin,leftMax } = axisLimitState; const textZh = e.ChartInfo?.Unit const textEn = e.ChartInfo?.UnitEn||e.ChartInfo?.Unit // console.log(leftMin,leftMax) //y轴 let yAxis = { ...basicYAxis, title: { text: textZh, textZh: textZh, textEn: textEn, align: 'high', rotation: 0, y: -12, x:0, textAlign: 'left', reserveSpace: false, style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, }, labels: { formatter: function (ctx) { let val = ctx.value; return val; }, align: 'center', style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, }, min: Number(leftMin), max: Number(leftMax), opposite: false, tickWidth: 1, plotBands: setAxisPlotAreas(1), plotLines: setAxisPlotLines(1) } //数据列 data.forEach(item => { let serie_item = { data: item.Value, type: 'column', yAxis: 0, name: item.Name || item.Date, nameZh: item.Name || item.Date, nameEn: item.Date, color: item.Color, chartType: 'linear', visible:true, }; seriesData.push(serie_item) }) return { title: { text:'' }, plotOptions: { column:{ stacking: null, }, }, series: seriesData, yAxis: [ yAxis ], xAxis } } /* 获取图表详情后赋值柱状图数据 */ function initBarData(data){ const { XEdbIdValue,YDataList,EdbInfoList,ChartInfo } = data; let xData = XEdbIdValue.map(_ => EdbInfoList.find(edb => edb.EdbInfoId===_).EdbAliasName) // console.log(xData) axisLimitState.leftIndex=-1 axisLimitState.rightIndex=-1 axisLimitState.rightTwoIndex=-1 barDateList.value = YDataList; barXData.value = xData; barEdbData.value = EdbInfoList; axisLimitState.hasLeftAxis=true axisLimitState.leftMin=Number(ChartInfo.LeftMin) axisLimitState.leftMax=Number(ChartInfo.LeftMax) return setBarChart(data); } /* 商品价格曲线设置 绘图逻辑同奇怪柱形图*/ const commodityChartData = ref([]);//商品价格图的绘图数据 const commodityXData = ref([]);//商品价格图的x轴 const commodityEdbList = ref([]);//商品价格图的表格数据 只用于取值 /* 商品价格曲线设置 绘图逻辑同奇怪柱形图*/ const setCommodityChart = (leftMin,leftMax) => { axisLimitState.leftIndex=-1 axisLimitState.rightIndex=-1 axisLimitState.rightTwoIndex=-1 /* 主题样式*/ const chartTheme = chartData.value.ChartInfo.ChartThemeStyle ? JSON.parse(chartData.value.ChartInfo.ChartThemeStyle) : null; let seriesData = []; const data = _.cloneDeep(commodityChartData.value); console.log(data); //x轴 let xAxis = { ...scatterXAxis, categories: commodityXData.value.map(_ => _.Name), tickWidth: 1, labels: { style: { ...chartTheme&&chartTheme.xAxisOptions.style } } } //y轴 let yAxis = { ...basicYAxis, title: { text: commodityEdbList.value[0].Unit, textZh: commodityEdbList.value[0].Unit, textEn: commodityEdbList.value[0].Unit?(commodityEdbList.value[0].UnitEn||'英文单位'):'', align: 'high', rotation: 0, y: -15, textAlign: 'left', reserveSpace: false, style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, }, labels: { formatter: function (ctx) { let val = ctx.value; return val; }, align: 'center', style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, }, min: Number(leftMin), max: Number(leftMax), opposite: false, tickWidth: 1, } //数据列 data.forEach((item,index) => { //处理首或/尾全是无效数据的以null填充 let filterData = filterInvalidData(item) //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模 const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index let serie_item = { data: filterData, type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || 'spline', dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid', yAxis: 0, name: item.Name, nameZh: item.Name, nameEn: item.NameEn, color: item.Color, chartType: 'linear', lineWidth: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth) || 3, visible: true, marker: { enabled: false } }; seriesData.push(serie_item) }) //tooltip let tooltip = { formatter: function() { const ctx = this; let str = ''; ctx.points.forEach(item => { let obj_item = data.find(_ => _.Name === item.series.name); let index = commodityXData.value.findIndex(_ => _.Name === ctx.x); // 合约显示 const haveContract=obj_item.XEdbInfoIdList[index] if(haveContract){ // 利润曲线指标名 let edb_name = chartData.value.ChartInfo.Source === 5 ? (index === 0 ? obj_item.NameList[index] : `${chartData.value.DataResp.ProfitName}(${obj_item.NameList[index]})`) : commodityEdbList.value.find(_ => _.EdbInfoId === obj_item.XEdbInfoIdList[index]).EdbName; str+=`${ edb_name }` if(!obj_item.NoDataEdbList.includes(obj_item.XEdbInfoIdList[index])) { str += `
\u25CF${obj_item.Date}: ${item.y}
` }else { str += `
\u25CF${obj_item.Date}: 无
` } } }) return str||'无合约' }, formatterCh: function() { let str = ''; this.points.forEach(item => { let obj_item = data.find(_ => _.Name === item.series.name); let index = commodityXData.value.findIndex(_ => _.Name === this.x); str+=`${ commodityEdbList.value.find(_ => _.EdbInfoId === obj_item.XEdbInfoIdList[index]).EdbName }` if(!obj_item.NoDataEdbList.includes(obj_item.XEdbInfoIdList[index])) { str += `
\u25CF${obj_item.Date}: ${item.y}
` }else { str += `
\u25CF${obj_item.Date}: 无
` } }) return str }, formatterEn: function() { let str = ''; this.points.forEach(item => { let obj_item = data.find(_ => _.NameEn === item.series.name); let index = commodityXData.value.findIndex(_ => _.NameEn === this.x); str+=`${ commodityEdbList.value.find(_ => _.EdbInfoId === obj_item.XEdbInfoIdList[index]).EdbNameEn }` if(!obj_item.NoDataEdbList.includes(obj_item.XEdbInfoIdList[index])) { str += `
\u25CF${obj_item.Date}: ${item.y}
` }else { str += `
\u25CF${obj_item.Date}: 无
` } }) return str }, shared: true } // console.log(seriesData); return { title: { text:'' }, series: seriesData, yAxis: [ yAxis ], xAxis, tooltip } }; /* 处理无效数据为null */ function filterInvalidData(item){ let validateArr = item.XEdbInfoIdList.filter(_ =>!item.NoDataEdbList.includes(_)); let first_index = item.XEdbInfoIdList.findIndex(_ => _ === validateArr[0]); let last_index = item.XEdbInfoIdList.findIndex(_ => _ === validateArr[validateArr.length-1]); // console.log('first_index',first_index) // console.log('last_index',last_index) let arr = item.Value.map((item,index) => { if(index < first_index || index > last_index) { return null }else { return item } }) return arr; } function initCommodityData(data){ const { XDataList,YDataList,EdbInfoList,ChartInfo,DataResp } = data; commodityEdbList.value = EdbInfoList; commodityChartData.value = ChartInfo.Source===5?DataResp.YDataList:YDataList commodityXData.value = ChartInfo.Source===5?DataResp.XDataList:XDataList axisLimitState.hasLeftAxis=true axisLimitState.leftMin=Number(ChartInfo.LeftMin) axisLimitState.leftMax=Number(ChartInfo.LeftMax) return setCommodityChart(ChartInfo.LeftMin,ChartInfo.LeftMax); } //相关性图表 function initRelevanceChart(data){ /* 主题样式*/ const chartTheme = data.ChartInfo.ChartThemeStyle ? JSON.parse(data.ChartInfo.ChartThemeStyle) : null; axisLimitState.leftIndex=-1 axisLimitState.rightIndex=-1 axisLimitState.rightTwoIndex=-1 // 处理X轴 let xAxis={ categories: data.ChartInfo.Source===3?data.XEdbIdValue:data.DataResp.XDateTimeValue, tickWidth: 1, title: { text: data.ChartInfo.Source===3 ?`期数(${data.CorrelationChartInfo.LeadUnit})` : null, textZh:data.ChartInfo.Source===3 ? `期数(${data.CorrelationChartInfo.LeadUnit})`:null, textEn:data.ChartInfo.Source===3 ? `stage(${relevanceUnitEnMap[data.CorrelationChartInfo.LeadUnit]})`:null, align: 'high', rotation: 0, x: 0, y:10, offset: 20, style: { ...chartTheme&&chartTheme.xAxisOptions.style } }, labels: { style: { ...chartTheme&&chartTheme.xAxisOptions.style } }, tickInterval: 1, offset:0, tickmarkPlacement:'on' } // 处理Y轴 let yAxis={ ...basicYAxis, title: { text: '相关性系数', textZh: '相关性系数', textEn: 'Correlation coefficient', align: 'high', rotation: 0, y: -15, textAlign: 'left', reserveSpace: false, style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, }, labels: { formatter: function (ctx) { let val = ctx.value; return val; }, align: 'center', style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, }, opposite: false, tickWidth: 1, } //处理series let seriesData=[] data.YDataList.forEach((item,index)=>{ //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模 const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index let serie_item = { data: item.Value, type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || 'spline', dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid', yAxis: 0, name: item.Name||data.ChartInfo.ChartName, nameZh: item.Name||data.ChartInfo.ChartName, nameEn: item.NameEn||data.ChartInfo.ChartNameEn, color: item.Color, chartType: 'linear', lineWidth: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth) || 3, visible:true, marker: { enabled: false } }; seriesData.push(serie_item) }) const { LeadValue,LeadUnit } = data.CorrelationChartInfo; const { Source } = data.ChartInfo; let tooltip = { formatter: function() { let str = `

相关性系数:${this.y.toFixed(4)}


领先${ Source===3 ?this.x+'期' : LeadValue+LeadUnit}

` return str }, formatterCh: function() { let str = `

相关性系数:${this.y.toFixed(4)}


领先${ Source===3 ?this.x+'期' : LeadValue+LeadUnit}

` return str }, formatterEn: function() { let str = `

Correlation coefficient:${this.y.toFixed(4)}


lead${ Source===3 ? this.x+'stage' : LeadValue+relevanceUnitEnMap[LeadUnit]}

` return str } } nextTick(()=>{ // if(data.ChartInfo.Source===3){ // const hEl=document.getElementById(RenderDomId.value) // // console.log(hEl.offsetHeight); // xAxis.offset=-(hEl.offsetHeight-98)/2 // } options.value = { isRelevanceChart:data.ChartInfo.Source===3, title: { text:'' }, series: seriesData, yAxis: [yAxis] , xAxis:xAxis, tooltip } ChartIns.update(options.value,true) }) return { isRelevanceChart:true, title: { text:'' }, series: seriesData, yAxis: [yAxis] , xAxis:xAxis, tooltip } } /* 截面散点图设置 sectionScatterData */ function setSectionScatterChart({DataResp,ChartInfo}) { axisLimitState.leftIndex=-1 axisLimitState.rightIndex=-1 axisLimitState.rightTwoIndex=-1 /* 主题样式*/ const chartTheme = ChartInfo.ChartThemeStyle ? JSON.parse(ChartInfo.ChartThemeStyle) : null; const { DataList,XName,XNameEn,XUnitName,XUnitNameEn,YName,YNameEn,YUnitName,YUnitNameEn } = DataResp; const leftMin=Number(DataResp.YMinValue) const leftMax=Number(DataResp.YMaxValue) const xMin=Number(DataResp.XMinValue) const xMax=Number(DataResp.XMaxValue) axisLimitState.hasLeftAxis=true axisLimitState.hasXAxis=true axisLimitState.leftMin=leftMin axisLimitState.leftMax=leftMax axisLimitState.xMin=xMin axisLimitState.xMax=xMax //y轴 let yAxis = { ...basicYAxis, title: { text: YName, textZh:YName,// 中文 textEn:YNameEn|| '', style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, align: 'middle', }, labels: { style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, }, opposite: false, reversed: false, min: Number(leftMin), max: Number(leftMax), tickWidth: 1, plotBands: setAxisPlotAreas(1), plotLines: setAxisPlotLines(1) } //x轴 let xAxis = { ...scatterXAxis, title: { text: XName, textZh:XName,// 中文 textEn:XNameEn || '', style: { ...chartTheme&&chartTheme.xAxisOptions.style }, align: 'middle', }, labels: { style:{ ...chartTheme&&chartTheme.xAxisOptions.style }, }, min: Number(xMin), max: Number(xMax), plotBands: setAxisPlotAreas(3), plotLines: setAxisPlotLines(3) } //数据列 let series = []; DataList.forEach((item,index) => { //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模 const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index //数据列 let series_item = { data: [], type: 'scatter', name: item.Name, nameZh: item.Name, nameEn: item.NameEn, color: item.Color, lineWidth: 0, chartType: 'linear', zIndex:1, visible: true, marker: { radius: (chartTheme&&chartTheme.lineOptionList[lineIndex].radius)||5, }, } item.EdbInfoList.forEach(_ => { series_item.data.push({ x: _.XValue, y: _.YValue, dataLabels: { enabled: _.IsShow, allowOverlap: true, align: 'left', format: _.Name, formatZh: _.Name, formatEn: _.NameEn } }) }) series.push(series_item); //趋势线 if(item.ShowTrendLine) { let trend_data = item.TrendLimitData.map((_,_index) => ( _index === item.TrendLimitData.length-1 ? { x: _.X, y: _.Y, dataLabels: { enabled: item.ShowRSquare || item.ShowFitEquation, align: 'left', color: item.Color, x: 20, y: 30, zIndex: 9, allowOverlap: true, formatter: function(){ let tag = ''; item.ShowRSquare && item.ShowFitEquation ? tag =`${item.TrendLine}
R²=${item.RSquare}` : item.ShowRSquare && !item.ShowFitEquation ? tag =`R²=${item.RSquare}` : item.ShowFitEquation && !item.ShowRSquare ? tag =`${item.TrendLine}` : '' return tag } } } : { x: _.X, y: _.Y, } )) let trend_item = { data: trend_data, type: 'spline', linkedTo: ':previous', color: item.Color, lineWidth: 1, chartType: 'linear', enableMouseTracking: false, dashStyle:'Dash', zIndex: 2, visible: true, marker: { enabled: false } } series.push(trend_item) } }) let tooltip = { formatter: function() { let series_obj = DataList.find(_ => _.Name === this.series.name); let ponit_obj = series_obj.EdbInfoList.find(_ => _.XValue ===this.x && _.YValue===this.y); let str=`${ ponit_obj.Name }`; str += `
\u25CF${ponit_obj.XName}: ${this.x} ${ponit_obj.XDate}
`; str += `\u25CF${ponit_obj.YName}: ${this.y} (${ponit_obj.YDate})`; return str }, formatterCh: function() { let series_obj = DataList.find(_ => _.Name === this.series.name); let ponit_obj = series_obj.EdbInfoList.find(_ => _.XValue ===this.x && _.YValue===this.y); let str=`${ ponit_obj.Name }`; str += `
\u25CF${ponit_obj.XName}: ${this.x} ${ponit_obj.XDate}
`; str += `\u25CF${ponit_obj.YName}: ${this.y} (${ponit_obj.YDate})`; return str }, formatterEn: function() { let series_obj = DataList.find(_ => _.NameEn === this.series.name); let ponit_obj = series_obj.EdbInfoList.find(_ => _.XValue ===this.x && _.YValue===this.y); let str=`${ ponit_obj.NameEn }`; str += `
\u25CF${ponit_obj.XNameEn}: ${this.x} ${ponit_obj.XDate}
`; str += `\u25CF${ponit_obj.YNameEn}: ${this.y} ${ponit_obj.YDate}`; return str } } return { title: { text:'' }, series, yAxis: [yAxis], xAxis, tooltip } } /* 跨品种分析 */ function setCrossVarietyChart({DataResp,EdbInfoList,ChartInfo}) { axisLimitState.leftIndex=-1 axisLimitState.rightIndex=-1 axisLimitState.rightTwoIndex=-1 /* 主题样式*/ const chartTheme = ChartInfo.ChartThemeStyle ? JSON.parse(ChartInfo.ChartThemeStyle) : null; const { DataList,XName,YName,XNameEn,YNameEn,XMaxValue,XMinValue,YMaxValue,YMinValue } = DataResp; const {leftMin,leftMax,xMin,xMax} = axisLimitState; //y轴 let yAxis = { ...basicYAxis, title: { text: YName, textCh:YName,// 中文 textEn:YNameEn||YName, align: 'middle', style: { ...chartTheme&&chartTheme.xAxisOptions.style } }, labels: { style: { ...chartTheme&&chartTheme.xAxisOptions.style } }, opposite: false, reversed: false, min: Number(leftMin), max: Number(leftMax), tickWidth: 1, } // x轴 let xAxis = { ...scatterXAxis, title: { text: XName, textCh:XName,// 中文 textEn:XNameEn || XName, align: 'middle', style: { ...chartTheme&&chartTheme.xAxisOptions.style } }, labels: { style: { ...chartTheme&&chartTheme.xAxisOptions.style } }, min: Number(xMin), max: Number(xMax), } //数据列 let series = []; const tagMap = { //标签对应文字 1: '最新', 3: 'Fix' } DataList.forEach(item => { //数据列 let series_item = { data: [], type: 'scatter', name: item.Name, nameZh: item.Name, nameEn: item.NameEn||item.Name, color: item.Color, lineWidth: 0, chartType: 'linear', zIndex:1 } item.CoordinatePointData.forEach(_ => { series_item.data.push({ x: _.X, y: _.Y, dataLabels: { enabled: _.ShowTips===1, allowOverlap: true, align: 'left', format: tagMap[_.DateType] || `-${_.DaysAgo}D`, } }) }) series.push(series_item); }) let tooltip = { formatter: function() { let series_obj = DataList.find(_ => _.Name === this.series.name); let ponit_obj = series_obj.CoordinatePointData.find(_ => _.X ===this.x && _.Y===this.y); let xEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.XEdbInfoId); let yEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.YEdbInfoId); let str=`${ this.series.name }`; str += `
\u25CF${xEdbInfo.EdbName}: ${this.x} ${ponit_obj.XDate}
`; str += `\u25CF${yEdbInfo.EdbName}: ${this.y} ${ponit_obj.YDate}`; return str }, formatterCh: function() { let series_obj = DataList.find(_ => _.Name === this.series.name); let ponit_obj = series_obj.CoordinatePointData.find(_ => _.X ===this.x && _.Y===this.y); let xEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.XEdbInfoId); let yEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.YEdbInfoId); let str=`${ this.series.name }`; str += `
\u25CF${xEdbInfo.EdbName}: ${this.x} ${ponit_obj.XDate}
`; str += `\u25CF${yEdbInfo.EdbName}: ${this.y} ${ponit_obj.YDate}`; return str }, formatterEn: function() { let series_obj = DataList.find(_ => _.NameEn === this.series.name); let ponit_obj = series_obj.CoordinatePointData.find(_ => _.X ===this.x && _.Y===this.y); let xEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.XEdbInfoId); let yEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.YEdbInfoId); let str=`${ this.series.name }`; str += `
\u25CF${xEdbInfo.EdbNameEn}: ${this.x} ${ponit_obj.XDate}
`; str += `\u25CF${yEdbInfo.EdbNameEn}: ${this.y} ${ponit_obj.YDate}`; return str } } return { title: { text:'' }, series, yAxis: [yAxis], xAxis, tooltip } } /* 雷达图 */ function setRadarChart({DataResp,EdbInfoList,ChartInfo}) { axisLimitState.leftIndex=-1 axisLimitState.rightIndex=-1 axisLimitState.rightTwoIndex=-1 const { YDataList,XEdbIdValue } = DataResp; let XDataList = EdbInfoList.filter(_ => XEdbIdValue.includes(_.EdbInfoId)); axisLimitState.hasLeftAxis=true axisLimitState.leftMin=Number(ChartInfo.LeftMin) axisLimitState.leftMax=Number(ChartInfo.LeftMax) /* 主题样式*/ const chartTheme = ChartInfo.ChartThemeStyle ? JSON.parse(ChartInfo.ChartThemeStyle) : null; //x轴 let xAxis = { lineWidth: 0, tickLength: 0, tickmarkPlacement: 'on', categories:XDataList.map(_ => _.EdbAliasName||_.EdbName), labels: { allowOverlap: true, autoRotationLimit: 40, style: { ...chartTheme&&chartTheme.xAxisOptions.style } } } //y轴 let yAxis = [{ gridLineInterpolation: 'polygon', gridLineWidth: 1, lineWidth: 0, endOnTick: false, startOnTick: false, showLastLabel: true, // tickAmount:4, title: { text: ChartInfo.Unit, textCh: ChartInfo.Unit, textEn: ChartInfo.UnitEn, align: 'high', rotation: 0, y: 5, x:10, textAlign: 'left', reserveSpace: false, style:{ ...chartTheme&&chartTheme.yAxisOptions.style }, }, labels: { allowOverlap: true, style:{ ...chartTheme&&chartTheme.yAxisOptions.style } }, min: Number(ChartInfo.LeftMin), max: Number(ChartInfo.LeftMax), }] //系列 let series = []; YDataList.forEach((item,index) => { //图表可配置的线条数就10条,第11条用第1条的配置,索引取下模 const lineIndex = chartTheme ? index%chartTheme.lineOptionList.length : index let serie_item = { name: item.Name || item.Date, nameZh: item.Name || item.Date, nameEn: item.Date, data: item.Value, pointPlacement: 'on', type: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineType) || 'line', dashStyle: (chartTheme&&chartTheme.lineOptionList[lineIndex].dashStyle)||'Solid', yAxis: 0, color: item.Color, lineWidth: (chartTheme&&chartTheme.lineOptionList[lineIndex].lineWidth) || 1, chartType: 'linear' }; series.push(serie_item) }) return { chart: { ...chartDefaultOpts.chart, ...chartTheme?.drawOption, spacing: [2,10,2,10], polar:true, }, title: { text:'' }, pane: { size: '85%' }, series, yAxis, xAxis } } //获取RGBA的透明度 function parseRgbaColor(color='rgba(51, 51, 51, 1)'){ const arr = color.match(/(\d(\.\d+)?)+/g) || ['','','',1]; return parseFloat(arr[3]||1) } /* ----自定义上下限相关--- */ /* 计算y轴上下限 */ function calcYAxislimit(tableData=[],ChartInfo,DataResp={}){ //散点图单独处理 if(ChartInfo.ChartType===5){ if(tableData[1]){ axisLimitState.leftMin = tableData[1].MinData axisLimitState.leftMax = tableData[1].MaxData } return } //分组 const leftData = tableData.filter(i => i.IsAxis === 1).map(i => [Number(i.MinData), Number(i.MaxData)]) const rightData = tableData.filter(i => !i.IsAxis).map(i => [Number(i.MinData), Number(i.MaxData)]) const rightTwoData = tableData.filter(i => i.IsAxis === 2).map(i => [Number(i.MinData), Number(i.MaxData)]) //计算最大最小值 if (leftData.length) { const { Max, Min } = calcLimit(leftData.flat()) axisLimitState.leftMin = Min axisLimitState.leftMax = Max } if (rightData.length) { const { Max, Min } = calcLimit(rightData.flat()) axisLimitState.rightMin = Min axisLimitState.rightMax = Max } if (rightTwoData.length) { const { Max, Min } = calcLimit(rightTwoData.flat()) axisLimitState.rightTwoMin = Min axisLimitState.rightTwoMax = Max } //季节性图-右轴单独处理 if(ChartInfo.ChartType===2){ if(DataResp.RightAxis&&DataResp.RightAxis.IsAdd&&DataResp.RightAxis.IsShow){ if(DataResp.RightAxis.IndicatorType===1){ axisLimitState.rightMin = DataResp.RightAxis.EdbInfoList[0].MinData||0 axisLimitState.rightMax = DataResp.RightAxis.EdbInfoList[0].MaxData||0 }else{ axisLimitState.rightMin = tableData[1].MinData||0 axisLimitState.rightMax = tableData[1].MaxData||0 } } } } function calcLimit(arr) { return { Max: Math.max(...arr), Min: Math.min(...arr) } } //图表详情-设置图表上下限 function setLimitData({EdbInfoList,ChartInfo,DataResp}){ const { //左右轴极值字段 LeftMin=0,LeftMax=0, RightMin=0,RightMax=0, Right2Min=0,Right2Max=0, MinMaxSave } = ChartInfo if(MinMaxSave){ axisLimitState.leftMin = Number(LeftMin) axisLimitState.leftMax = Number(LeftMax) axisLimitState.rightMin = Number(RightMin) axisLimitState.rightMax = Number(RightMax) axisLimitState.rightTwoMin = Number(Right2Min) axisLimitState.rightTwoMax = Number(Right2Max) //若用户修改过,则检测轴的上下限是否为空,若为空,则需要计算对应轴的上下限 checkLimit(EdbInfoList,ChartInfo) console.log('check',axisLimitState.leftMin,axisLimitState.leftMax) }else{ calcYAxislimit(EdbInfoList,ChartInfo,DataResp?DataResp:{}) } } function checkLimit(tableData=[],ChartInfo){ //散点图单独处理 if(ChartInfo.ChartType===5){ if(tableData[1]){ if(Number(axisLimitState.leftMin)===0&&Number(axisLimitState.leftMax)===0){ axisLimitState.leftMin = tableData[1].MinData axisLimitState.leftMax = tableData[1].MaxData } } return } //若轴的上下限均为0,则不管用户有没有修改过,都重新赋值 if(Number(axisLimitState.leftMin)===0&&Number(axisLimitState.leftMax)===0){ const leftData = tableData.filter(i=>i.IsAxis===1).map(i=>[Number(i.MinData),Number(i.MaxData)]) if(leftData.length){ const {Max,Min} = calcLimit(leftData.flat()) axisLimitState.leftMin = Min axisLimitState.leftMax = Max } } if(Number(axisLimitState.rightMin)===0&&Number(axisLimitState.rightMax)===0){ const rightData = tableData.filter(i => !i.IsAxis).map(i=>[Number(i.MinData),Number(i.MaxData)]) if(rightData.length){ const {Max,Min} = calcLimit(rightData.flat()) axisLimitState.rightMin = Min axisLimitState.rightMax = Max } } if(Number(axisLimitState.rightTwoMin)===0&&Number(axisLimitState.rightTwoMax)===0){ const rightTwoData = tableData.filter(i=>i.IsAxis===2).map(i=>[Number(i.MinData),Number(i.MaxData)]) if(rightTwoData.length){ const {Max,Min} = calcLimit(rightTwoData.flat()) axisLimitState.rightTwoMin = Min axisLimitState.rightTwoMax = Max } } } /*-------------------- */