/* 图表配置设置 */
import Highcharts from 'highcharts';
import { defaultOpts, seasonOptions,getTerminal,browser } from '@/utils/defaultOptions';
// 散点x轴
const scatterXAxis = {
tickPosition: 'inside',
lineColor: '#bfbfbf',
tickColor: '#bfbfbf',
tickLength:5,
ordinal: false,
type: 'linear'
}
// y轴静态配置
const basicYAxis = {
tickLength: 5,
lineWidth: 1,
lineColor: '#bfbfbf',
tickColor: '#bfbfbf',
// offset: 0,
visible: true,
gridLineWidth: 0,
tickPosition: 'inside',
endOnTick: false,
startOnTick: false,
showLastLabel: true,
tickPixelInterval: 50,
}
export default {
data() {
return {
bgList:[
{image_url:require('@/assets/img/ppt_m/bg3.jpg')},
{image_url:require('@/assets/img/ppt_m/bg4.jpg')},
{image_url:require('@/assets/img/ppt_m/bg5.jpg')},
// {image_url:'https://hzstatic.hzinsights.com/ppt/bg3.jpg'},
// {image_url:'https://hzstatic.hzinsights.com/ppt/bg4.jpg'},
// {image_url:'https://hzstatic.hzinsights.com/ppt/bg5.jpg'},
],//首页背景
//领先频度对应英文
leadUnitEnMap: {
'年': 'Y',
'季': 'Q',
'月': 'M',
'周': 'W',
'天': 'D',
},
/* 奇怪柱形图 */
barDateList: [],//柱形图的绘图数据
barXIdData: [],//柱形图的x轴
barEdbData: [],//柱形图的表格数据 只用于取值
chartLimit: {},
/* 商品价格曲线 */
commodityChartData: [],
commodityXData: [],
commodityEdbList: [],
/* 时间截面散点图 */
sectionScatterData: {},
relevanceChartData:null,//相关性图表
relevanceUnitEnMap:{
'年': 'Year',
'季': 'Season',
'月': 'Month',
'周': 'Week',
'天': 'Day',
},
/* 统计频率图 */
statisticFrequencyData: {}
}
},
methods: {
/* 设置options 曲线图 季节图*/
setOptions() {
// ChartType: 1曲线图 2季节图 3面积 4柱状 5散点 6组合 季节图中公历和农历数据结构不同
const chartSetMap = {
1: this.setDefaultChart,
2: this.setSeasonChart,
3: this.setStackOrCombinChart,
4: this.setStackOrCombinChart,
5: this.setScatterChart,
6: this.setStackOrCombinChart
};
chartSetMap[this.chartInfo.ChartType]&&chartSetMap[this.chartInfo.ChartType]()
},
/* 曲线 */
setDefaultChart() {
//拼接标题 数据列
let data = [],
ydata = [];
let rightTwoIndex = this.dataList.findIndex((item) => item.IsAxis ===2);
// const chartData = _.cloneDeep(this.dataList);
let chartData = this.dataList.some(_ =>_.IsAxis===2) ? this.changeEdbOrder(this.dataList) : _.cloneDeep(this.dataList);
chartData.forEach((item, index) => {
//轴位置值相同的下标
let sameSideIndex = chartData.findIndex(i => i.IsAxis === item.IsAxis);
//y轴
let yItem = {
...basicYAxis,
title: {
text: item.Unit,
textCh:item.Unit,//中文单位
textEn:item.Unit?item.UnitEn:'',//英文单位,但如果无中文单位则不显示
// text: null,
align: 'high',
rotation: 0,
y: -15,
x: (item.IsAxis===0 && rightTwoIndex>-1) ? -chartData[rightTwoIndex].Unit.length*12 : 0,
textAlign: item.IsAxis===1 ? 'left' : 'right',
reserveSpace: false
},
labels: {
formatter: function (ctx) {
let val = ctx.value;
return val;
},
align: 'center',
x: [0,2].includes(item.IsAxis) ? 5 : -5,
style: {
fontSize: '10px',
},
},
opposite: [0,2].includes(item.IsAxis),
reversed: item.IsOrder,
min: Number(item.MinData),
max: Number(item.MaxData),
tickWidth: 1,
visible: sameSideIndex === index
};
// //拼接标题 判断相同指标名称拼接来源
let dynamic_title = item.EdbName;
let dynamic_arr = chartData.filter(
(item) => dynamic_title === item.EdbName
);
// 拼接配置 IsAxis左轴1 右轴0 IsOrder正序false 逆序true EdbInfoType是否是领先指标
let dynamic_tag = this.concatDynamicTag(item);
let dynamic_tag_en = this.concatDynamicTag(item,'en');
//预测指标配置
let predict_params = item.EdbInfoCategoryType === 1 ? this.getPredictParams(item) : {};
//中英文名称
const nameCh = dynamic_arr.length > 1
? `${item.EdbName}(${item.SourceName})${dynamic_tag}`
: `${item.EdbName}${dynamic_tag}`
const nameEn = item.EdbNameEn?`${item.EdbNameEn}${dynamic_tag_en}`:''
//数据列
let obj = {
data: [],
type: 'spline',
yAxis: sameSideIndex,
name:nameCh,
nameCh:nameCh,
nameEn:nameEn,
color: item.ChartColor,
lineWidth: Number(item.ChartWidth),
...predict_params
};
item.DataList = item.DataList || [];
for (let i of item.DataList) {
obj.data.push([i.DataTimestamp, i.Value]);
}
data.push(obj);
ydata.push(yItem);
});
// 范围为1年内 x轴显示为月/日 否则默认年/月
this.xTimeDiffer();
this.options = {
series: data,
yAxis: ydata
};
//滚动相关性独立tooltip
if(this.chartInfo.Source === 4) {
const { LeadValue,LeadUnit } = this.relevanceChartData.CorrelationChartInfo;
let relevanceUnitEnMap = this.relevanceUnitEnMap;
this.options.tooltip = {
formatter: function() {
let str = `${Highcharts.dateFormat('%Y/%m/%d',this.x)}
相关性系数:${this.y.toFixed(4)}
领先${LeadValue+LeadUnit}
` return str }, formatterCh: function() { let str = `${Highcharts.dateFormat('%Y/%m/%d',this.x)}相关性系数:${this.y.toFixed(4)}
领先${LeadValue+LeadUnit}
` return str }, formatterEn: function() { let str = `${Highcharts.dateFormat('%Y/%m/%d',this.x)}Correlation coefficient:${this.y.toFixed(4)}
lead${LeadValue+relevanceUnitEnMap[LeadUnit]}
` return str } } } }, /* 堆叠柱 堆叠面积 组合图 */ setStackOrCombinChart() { const chartTypeMap = { 3: 'areaspline', 4: 'column', 6: '' }; let chartStyle = chartTypeMap[this.chartInfo.ChartType]; //拼接标题 数据列 let data = [], ydata = []; let chartData = this.dataList.some(_ =>_.IsAxis===2) ? this.changeEdbOrder(this.dataList) : _.cloneDeep(this.dataList); chartData.forEach((item, index) => { //轴位置值相同的下标 let sameSideIndex = chartData.findIndex(i => i.IsAxis === item.IsAxis); //堆叠图的yAxis必须一致 数据列所对应的y轴 let serie_yIndex = index; if([3,4].includes(this.chartInfo.ChartType)) { // 类型为堆叠图时公用第一个指标y轴 serie_yIndex = 0; } else if(this.chartInfo.ChartType ===6 && ['areaspline','column'].includes(item.ChartStyle)) { // 组合图找第一个堆叠柱状或面积的作为公用 serie_yIndex = chartData.findIndex(i => i.ChartStyle === item.ChartStyle); } //数据对应的y轴是公用轴则配置也共享 item.IsAxis = serie_yIndex === index ? item.IsAxis : chartData[serie_yIndex].IsAxis; item.IsOrder = serie_yIndex === index ? item.IsOrder : chartData[serie_yIndex].IsOrder; let rightTwoIndex = [3,4].includes(this.chartInfo.ChartType) ? -1 : this.dataList.findIndex((item) => item.IsAxis===2); //y轴 let yItem = { ...basicYAxis, title: { //text: sameSideIndex !== index ? '' : `${item.Unit}`, text:item.Unit, textCh:item.Unit,//中文单位 textEn:item.Unit?item.UnitEn:'',//英文单位,但如果无中文单位则不显示 // text: null, align: 'high', rotation: 0, y: -15, x: (item.IsAxis===0 && rightTwoIndex>-1) ? -chartData[rightTwoIndex].Unit.length*12 : 0, textAlign: item.IsAxis===1 ? 'left' : 'right', reserveSpace: false }, labels: { formatter: function (ctx) { let val = ctx.value; return sameSideIndex !== index ? '' : val; }, align: 'center', x: [0,2].includes(item.IsAxis) ? 5 : -5, style: { fontSize: '10px', }, }, opposite: [0,2].includes(item.IsAxis), reversed: item.IsOrder, min: Number(chartData[sameSideIndex].MinData), max: Number(chartData[sameSideIndex].MaxData), tickWidth: sameSideIndex !== index ? 0 : 1, visible: serie_yIndex === index && sameSideIndex ===index }; // //拼接标题 判断相同指标名称拼接来源 let dynamic_title = item.EdbName; let dynamic_arr = chartData.filter( (item) => dynamic_title === item.EdbName ); // 拼接配置 IsAxis左轴1 右轴0 IsOrder正序false 逆序true EdbInfoType是否是领先指标 let dynamic_tag = this.concatDynamicTag(item); let dynamic_tag_en = this.concatDynamicTag(item,'en'); //预测指标配置 let predict_params = item.EdbInfoCategoryType === 1 ? this.getPredictParams(item,chartStyle) : {}; //中英文名称 const nameCh = dynamic_arr.length > 1 ? `${item.EdbName}(${item.SourceName})${dynamic_tag}` : `${item.EdbName}${dynamic_tag}` const nameEn = item.EdbNameEn?`${item.EdbNameEn}${dynamic_tag_en}`:'' //数据列 let obj = { data: [], type: chartStyle || item.ChartStyle, yAxis: serie_yIndex, name:nameCh, nameCh:nameCh, nameEn:nameEn, color: item.ChartColor, lineWidth: (this.chartInfo.ChartType === 6 && item.ChartStyle === 'spline') ? Number(item.ChartWidth) : 0, fillColor: (this.chartInfo.ChartType === 3 || (this.chartInfo.ChartType === 6 && item.ChartStyle === 'areaspline')) ? item.ChartColor : undefined, borderWidth: 1, borderColor: item.ChartColor, zIndex: (this.chartInfo.ChartType === 6 && item.ChartStyle === 'spline') ? 1 : 0, //防止组合图曲线被遮住 ...predict_params }; item.DataList = item.DataList || []; for (let i of item.DataList) { obj.data.push([i.DataTimestamp, i.Value]); } data.push(obj); ydata.push(yItem); }); // 范围为1年内 x轴显示为月/日 否则默认年/月 this.xTimeDiffer() this.options = { series: data, yAxis: ydata }; }, /* 季节图配置 */ setSeasonChart() { /* 季节性图的图表配置 */ const chartData = this.dataList[0]; let seasonYdata = [], seasonData = [], chart = { spacing: [5, 8, 2, 8], }; /* 公历数据处理 处理数据列 y轴 */ if (this.chartInfo.Calendar === '公历') for (let j of chartData.DataList) { //预测指标配置 let predict_params = chartData.EdbInfoCategoryType === 1 ? this.getSeasonPredictParams(j.CuttingDataTimestamp) : {}; let serie_item = { data: [], type: chartData.ChartStyle, yAxis: 0, name: j.Year, ...predict_params }; const data_array = _.cloneDeep(j.DataList); data_array && data_array.forEach((item) => { serie_item.data.push([item.DataTimestamp, item.Value]); }); const index = chartData.DataList.findIndex( (item) => item.Year === j.Year ); const s_yItem = { title: { text: `${chartData.Unit}`, textCh:chartData.Unit, textEn:chartData.Unit?chartData.UnitEn:'', // text: null, align: 'high', rotation: 0, y: -15, offset: -(12 * chartData.Unit.length), }, labels: { formatter: function (ctx) { let val = ctx.value; return index !== 0 ? '' : val; }, align: 'center', style: { fontSize: '10px', }, x: -5, }, max: Number(chartData.MaxData), min: Number(chartData.MinData), ...seasonOptions.yAxis, }; seasonData.push(serie_item); seasonYdata.push(s_yItem); } /* 农历数据处理 */ let filterArr = this.chartInfo.Calendar === '农历' ? chartData.DataList.List.filter((item, index) => index > 0) : []; if (this.chartInfo.Calendar === '农历') for (let j of filterArr) { //预测指标配置 let predict_params = chartData.EdbInfoCategoryType === 1 ? this.getSeasonPredictParams(j.CuttingDataTimestamp) : {}; let serie_item = { data: [], type: chartData.ChartStyle, yAxis: 0, name: j.Year, ...predict_params }; const data_array = _.cloneDeep(j.Items); data_array && data_array.forEach((item) => { serie_item.data.push([item.DataTimestamp, item.Value]); }); const index = filterArr.findIndex((item) => item.Year === j.Year); const s_yItem = { title: { text: `${chartData.Unit}`, textCh:chartData.Unit, textEn:chartData.Unit?chartData.UnitEn:'', // text: null, align: 'high', rotation: 0, y: -15, offset: -(12 * chartData.Unit.length), }, labels: { formatter: function (ctx) { let val = ctx.value; return index !== 0 ? '' : val; }, align: 'center', style: { fontSize: '10px', }, x: -5, }, max: Number(chartData.MaxData), min: Number(chartData.MinData), ...seasonOptions.yAxis, }; seasonData.push(serie_item); seasonYdata.push(s_yItem); } // 季节图x轴显示月/日 周度指标额外处理时间轴显示 const xAxis = { ...defaultOpts.xAxis, labels: { formatter: function (ctx) { return Highcharts.dateFormat('%m/%d', ctx.value); }, style: { fontSize: '10px', }, }, }; // 季节图提示框显示 月/日 defaultOpts.tooltip = { split: false, shared: true, dateTimeLabelFormats: { // 时间格式化字符 day: '%m/%d', week: '%m/%d', month: '%m/%d', year: '%m/%d', }, xDateFormat: '%m/%d', valueDecimals: 2, }; //农历默认选中一年数据并隐藏按钮 公历显示全部数据 let rangeSelector = this.chartInfo.Calendar === '农历' ? { enabled: true, selected: 0, inputStyle: { display: 'none', }, labelStyle: { display: 'none', }, buttonTheme: { style: { display: 'none', }, }, buttons: [ { type: 'month', count: 12, text: '12月', }, { type: 'month', count: 15, text: '15月', }, { type: 'all', text: '全部', }, ], } : { enabled: false, }; this.options = { colors: this.chartInfo.Calendar === '公历' ? seasonOptions.colors.slice(-chartData.DataList.length) : seasonOptions.colors.slice(-filterArr.length), series: seasonData, yAxis: seasonYdata, xAxis, rangeSelector }; }, /* 散点图设置 只允许2指标画图第一个指标值为x轴 第二个指标为y轴 */ setScatterChart() { const chartData = _.cloneDeep(this.dataList); // 取2个指标中日期相同的数据 let real_data = []; let tmpData_date = {};//用来取点对应的日期 let data1 = _.cloneDeep(chartData)[0].DataList || []; let data2 = _.cloneDeep(chartData)[1].DataList || []; data1.forEach(_item => { data2.forEach(_item2 => { if(_item.DataTimestamp === _item2.DataTimestamp) { _item.DataTime = _item.DataTime.replace(/-/g,'/'); //日期 let itemIndex =_item.Value + "_" +_item2.Value if(tmpData_date[itemIndex]) { tmpData_date[itemIndex].push(_item.DataTime) } else { tmpData_date[itemIndex] = [_item.DataTime] } //值 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() }相关性系数:${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 } } this.options = { isRelevanceChart: Source===3, title: { text:'' }, series: seriesData, yAxis: [yAxis] , xAxis:xAxis, tooltip } }, /* 截面散点图获取详情赋值 */ initSectionScatterData({ DataResp }) { this.chartLimit = { min: Number(DataResp.YMinValue), max: Number(DataResp.YMaxValue), x_min: Number(DataResp.XMinValue), x_max: Number(DataResp.XMaxValue) } this.sectionScatterData = DataResp; this.setSectionScatterChart(); }, /* 截面散点图设置 sectionScatterData */ setSectionScatterChart() { const { DataList,XName,XNameEn,XUnitName,XUnitNameEn,YName,YNameEn,YUnitName,YUnitNameEn } = this.sectionScatterData; const { min,max,x_min,x_max } = this.chartLimit; //y轴 let yAxis = { ...basicYAxis, title: { text: YName, textCh:YName,// 中文 textEn:YNameEn, style:{}, styleEn:{cursor:'pointer'}, align: 'middle', }, opposite: false, reversed: false, min: Number(min), max: Number(max), tickWidth: 1, } //x轴 let xAxis = { ...scatterXAxis, title: { text: XName, textCh:XName,// 中文 textEn:XNameEn, style:{}, styleEn:{cursor:'pointer'}, align: 'middle', }, min: Number(x_min), max: Number(x_max), } //数据列 let series = []; DataList.forEach(item => { //数据列 let series_item = { data: [], type: 'scatter', name: item.Name, nameCh: item.Name, nameEn: item.NameEn, color: item.Color, lineWidth: 0, chartType: 'linear', zIndex:1 } item.EdbInfoList.forEach(_ => { series_item.data.push({ x: _.XValue, y: _.YValue, dataLabels: { enabled: _.IsShow, allowOverlap: true, align: 'left', format: _.Name, formatCh: _.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: '#666', x: 20, y: 30, zIndex: 9, allowOverlap: true, formatter: function(){ let tag = ''; item.ShowRSquare && item.ShowFitEquation ? tag =`${item.TrendLine}