render.js 68 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084
  1. // 图渲染逻辑模块
  2. import {onMounted,ref,nextTick,reactive} from 'vue'
  3. import {chartDefaultOpts,scatterXAxis,basicYAxis,basicXAxis,leadUnitEnMap,relevanceUnitEnMap} from './config'
  4. import Highcharts from 'highcharts/highstock';
  5. import HighchartsFormat from 'highcharts';
  6. import HightchartsExport from 'highcharts/modules/exporting';
  7. import Boost from 'highcharts/modules/boost'
  8. import HighchartszhCN from './highcahrts-zh_CN.js'
  9. import moment from 'moment'
  10. import _ from 'lodash';
  11. HighchartszhCN(Highcharts)
  12. HightchartsExport(Highcharts)
  13. Boost(Highcharts)
  14. /**
  15. * 渲染图方法
  16. * @param data 图详情数据
  17. * @param renderId 图表在dom中的id
  18. * @param lang 图表显示为中文/英文 默认 zh中文 en英文
  19. * @param changeLangIsCheck 切换中英文时 是否要校验
  20. * @param showChartTitle 是否显示图表标题 默认true
  21. */
  22. let ChartIns=null//图表实例
  23. let chartData=ref(null)//图的所有数据
  24. let LangType=ref('zh')//当前图表显示的语言版本
  25. let RenderDomId=ref('')//图表渲染的domid
  26. let options=ref(null)//渲染图的数据
  27. const axisLimitState = reactive({//极值数据
  28. leftIndex:-1,//左侧上下限对应下标
  29. rightIndex: -1, //右侧上下限对应下标
  30. rightTwoIndex: -1,//右2上下限对应下标
  31. hasLeftAxis:false,
  32. hasRightAxis:false,
  33. hasRightTwoAxis:false,
  34. hasXAxis:false,
  35. leftMin:0,
  36. leftMax:0,
  37. rightMin:0,
  38. rightMax:0,
  39. rightTwoMin:0,
  40. rightTwoMax:0,
  41. xMin:0,
  42. xMax:0,
  43. })
  44. export function useChartRender(){
  45. return {
  46. options,
  47. axisLimitState,
  48. chartRender,
  49. }
  50. }
  51. /**备注一下 越多越乱
  52. * @params
  53. * Source 1 ; chartType只在source:1用到 1曲线 2季节 3面积 4堆积柱 5散点 6组合 7柱形 8截面散点
  54. * 2 商品价格
  55. * 3 相关性
  56. * 4 滚动相关性
  57. * 5 商品利润
  58. * 6 拟合方程
  59. * 7 统计特征/标准差
  60. * 8 统计特征/百分位
  61. * 9 统计特征/频率
  62. * 10 跨品种分析
  63. */
  64. export function chartRender({data,renderId,lang='zh',changeLangIsCheck,showChartTitle=true}){
  65. // 初始化掉极值数据
  66. axisLimitState.leftIndex=-1
  67. axisLimitState.rightIndex=-1
  68. axisLimitState.rightTwoIndex=-1
  69. axisLimitState.hasLeftAxis=false
  70. axisLimitState.hasRightAxis=false
  71. axisLimitState.hasRightTwoAxis=false
  72. axisLimitState.hasXAxis=false
  73. axisLimitState.leftMin=0
  74. axisLimitState.leftMax=0
  75. axisLimitState.rightMin=0
  76. axisLimitState.rightMax=0
  77. axisLimitState.rightTwoMin=0
  78. axisLimitState.rightTwoMax=0
  79. axisLimitState.xMin=0
  80. axisLimitState.xMax=0
  81. let chartOpt={}
  82. LangType.value=lang
  83. RenderDomId.value=renderId
  84. chartData.value=data
  85. if(data.ChartInfo.Source===1){
  86. const chartSetMap = {
  87. 1: setSplineOpt,
  88. 2: setSeasonOpt,
  89. 3: setStackOrCombinChart,
  90. 4: setStackOrCombinChart,
  91. 5: setScatterOptions,
  92. 6: setStackOrCombinChart,
  93. 7: initBarData,
  94. 10: setSectionScatterChart
  95. };
  96. chartOpt=chartSetMap[data.ChartInfo.ChartType](data)
  97. }else if([2,5].includes(data.ChartInfo.Source)){//商品价格曲线
  98. chartOpt=initCommodityData(data);
  99. }else if([3].includes(data.ChartInfo.Source)){//相关性 滚动相关性
  100. chartOpt=initRelevanceChart(data);
  101. }else if([4,6,7,8].includes(data.ChartInfo.Source)){//滚动相关性 拟合方程 标准差 百分比
  102. chartOpt=setSplineOpt(data);
  103. }else if([9].includes(data.ChartInfo.Source)){//统计频率
  104. chartOpt=setStatisticFrequency(data);
  105. }else if(data.ChartInfo.Source===10) {
  106. chartOpt = setCrossVarietyChart(data)
  107. }
  108. /*
  109. eta1.4.1增加了主题色
  110. 仍然以defaultOpts为最底层配置 外层配置在这里统一设置了如legend chart背景色
  111. x轴y轴系列等样式还是需要在具体的options中单独设置
  112. */
  113. let themeOptions = setThemeOptions();
  114. options.value={...chartDefaultOpts,...themeOptions, ...chartOpt}
  115. // 设置图标题
  116. setChartTitle(showChartTitle)
  117. // 设置语言
  118. setChartLang(changeLangIsCheck)
  119. //stock不支持线形图只支持时间图 某些用chart
  120. let is_linear = chartOpt.series
  121. ? chartOpt.series.some(_ => _.chartType === 'linear')
  122. : false ;
  123. is_linear ?ChartIns=Highcharts.chart(RenderDomId.value,options.value) : ChartIns=Highcharts.stockChart(RenderDomId.value,options.value);
  124. return ChartIns
  125. }
  126. //主题色一些外层公用配置 目前只有绘图区和legend和colors
  127. function setThemeOptions() {
  128. if(!chartData.value.ChartInfo.ChartThemeStyle) return {}
  129. let chartTheme = JSON.parse(chartData.value.ChartInfo.ChartThemeStyle)
  130. return {
  131. legend: {
  132. ...chartDefaultOpts.legend,
  133. ...chartTheme.legendOptions
  134. },
  135. chart: {
  136. ...chartDefaultOpts.chart,
  137. ...chartTheme.drawOption
  138. },
  139. colors: chartTheme.colorsOptions
  140. }
  141. }
  142. /* 处理轴的标识线结构 在指定轴位置上拼接标识线
  143. 0:右轴 1:左轴 2:右2轴 x轴固定3
  144. axisType表示x轴类型 处理时间轴的值 datetime/null
  145. */
  146. function setAxisPlotLines(axis,axisType) {
  147. const { MarkersLines,ChartType } = chartData.value.ChartInfo;
  148. if(!MarkersLines) return []
  149. let markerLines = JSON.parse(MarkersLines);
  150. let arr = markerLines.filter(_ => _.isShow&&_.axis===axis)
  151. let plotLines = arr.map(_ => {
  152. //是否是x时间轴
  153. let isXDateAxis = axis===3&&axisType==='datetime';
  154. let markerValue;
  155. if(isXDateAxis) {
  156. //季节图x轴额外拼个年份
  157. let nowYear = new Date().getFullYear();
  158. markerValue = ChartType===2
  159. ? new Date(`${nowYear}-${_.value}`).getTime()
  160. : new Date(_.value).getTime()
  161. }else {
  162. markerValue = Number(_.value)
  163. }
  164. return {
  165. value: markerValue,
  166. dashStyle: _.dashStyle,
  167. width: Number(_.lineWidth),
  168. color: _.color,
  169. label: {
  170. text: _.text||'',
  171. verticalAlign: _.textPosition,
  172. style: {
  173. color: _.textColor,
  174. fontSize: _.textFontSize
  175. }
  176. }
  177. }
  178. })
  179. return plotLines
  180. }
  181. /* 处理标识区拼接 axisType表示x轴类型处理时间轴的值 datetime/null */
  182. function setAxisPlotAreas(axis,axisType) {
  183. const { MarkersAreas,ChartType } = chartData.value.ChartInfo;
  184. if(!MarkersAreas) return []
  185. let markerAreas = JSON.parse(MarkersAreas);
  186. let arr = markerAreas.filter(_ => _.isShow&&_.axis===axis)
  187. let plotBands = arr.map(_ => {
  188. //是否是x时间轴
  189. let isXDateAxis = axis===3&&axisType==='datetime';
  190. let fromMarkerValue,toMarkerValue;
  191. if(isXDateAxis) {
  192. //季节图x轴额外拼个年份
  193. let nowYear = new Date().getFullYear();
  194. fromMarkerValue = ChartType===2
  195. ? new Date(`${nowYear}-${_.fromValue}`).getTime()
  196. : new Date(_.fromValue).getTime()
  197. toMarkerValue = ChartType===2
  198. ? new Date(`${nowYear}-${_.toValue}`).getTime()
  199. : new Date(_.toValue).getTime()
  200. }else {
  201. fromMarkerValue = Number(_.fromValue);
  202. toMarkerValue = Number(_.toValue);
  203. }
  204. //默认label有些偏移 重新归正下
  205. let positionMapValue = {
  206. 'top': 12,
  207. 'middle': 0,
  208. 'bottom': -10
  209. }
  210. return {
  211. from: fromMarkerValue,
  212. to: toMarkerValue,
  213. color: _.color,
  214. label: {
  215. text: _.text||'',
  216. verticalAlign: _.textPosition,
  217. y: positionMapValue[_.textPosition],
  218. style: {
  219. color: _.textColor,
  220. fontSize: _.textFontSize
  221. }
  222. }
  223. }
  224. })
  225. return plotBands
  226. }
  227. /* 预测配置 分区 */
  228. function getPredictParams ({LatestDate,PredictChartColor}) {
  229. return {
  230. zoneAxis: 'x',
  231. zones: [{
  232. value: new Date(LatestDate).getTime()+1
  233. }, {
  234. dashStyle: 'ShortDot',
  235. color: PredictChartColor
  236. }]
  237. }
  238. }
  239. /* 季节图预测数据 年份=分割点年份做分割 年份>分割点年份全为预测 */
  240. function getSeasonPredictParams (timestamp){
  241. return timestamp
  242. ? {
  243. zoneAxis: 'x',
  244. zones: [{
  245. value: new Date(timestamp).getTime()+1
  246. }, {
  247. dashStyle: 'ShortDot',
  248. }]
  249. }
  250. : {}
  251. }
  252. // 查询范围为1年内 x轴显示为月/日 否则默认年/月
  253. function xTimeDiffer(minTime,maxTime){
  254. //年限差
  255. let year_differ=moment(maxTime).diff(moment(minTime),'years',true)
  256. // console.log('年限差',year_differ)
  257. if (year_differ<=1) {
  258. // console.log('true');
  259. return true;
  260. } else {
  261. // console.log('false');
  262. return false;
  263. }
  264. }
  265. /* 拼接动态的指标名称小标签 */
  266. function concatDynamicTag(item,lang){
  267. const { IsAxis,IsOrder,EdbInfoType,LeadValue,LeadUnit } = item;
  268. // IsAxis左轴1 右轴0 2右2轴
  269. //IsOrder正序false 逆序true
  270. //IsOrder正序false 逆序true
  271. //IsOrder正序false 逆序true
  272. //EdbInfoType是否是领先指标
  273. const axisLabelMap =lang=='zh'? {
  274. 0: '右轴',
  275. 2: '右2轴'
  276. }:{
  277. 0: 'RHS',
  278. 2: '2-RHS'
  279. }
  280. const orderLabelMap =lang=='zh'? {
  281. 1: '逆序'
  282. }:{
  283. 1: 'REV'
  284. }
  285. const edbInfoMap =lang=='zh'? {
  286. 0: '领先'
  287. }:{
  288. 0: 'Lead'
  289. }
  290. //英文领先单位转换
  291. const leadUnit = lang==='zh' ? LeadUnit : leadUnitEnMap[LeadUnit];
  292. let axis_tag = axisLabelMap[IsAxis] || '';
  293. //逆序拼接
  294. let order_tag = orderLabelMap[Number(IsOrder)] ? `${axis_tag ? ',': ''}${orderLabelMap[Number(IsOrder)]}` : ''
  295. //领先拼接
  296. let edb_tag = edbInfoMap[EdbInfoType] ? `${(axis_tag||order_tag) ? ',' : '' }${edbInfoMap[EdbInfoType]}${LeadValue}${leadUnit}` : '';
  297. let dynamic_tag = (axis_tag || order_tag || edb_tag) ? `(${axis_tag}${order_tag}${edb_tag})` : '';
  298. return dynamic_tag
  299. }
  300. /* 拼接数据列动态name */
  301. function setDyncmicSerieName (item,dynamic_arr,lang='zh') {
  302. let temName =''
  303. /* if(lang=='zh'){
  304. temName= dynamic_arr.length > 1
  305. ? `${item.EdbName}(${item.SourceName})${concatDynamicTag(item,'zh')}`
  306. : `${item.EdbName}${concatDynamicTag(item,'zh')}`
  307. }else{
  308. temName=item.EdbNameEn?`${item.EdbNameEn}${concatDynamicTag(item,'en')}`:''
  309. } */
  310. const temNameEn = item.EdbNameEn?`${item.EdbNameEn}${concatDynamicTag(item,'en')}`:''
  311. const temNameZh = dynamic_arr.length > 1
  312. ? `${item.EdbAliasName||item.EdbName}(${item.SourceName})${concatDynamicTag(item,'zh')}`
  313. : `${item.EdbAliasName||item.EdbName}${concatDynamicTag(item,'zh')}`
  314. temName = lang=='zh'?temNameZh:temNameEn?temNameEn:temNameZh
  315. if(temName.length>20){
  316. let temArr=[]
  317. for(let i=0;i<temName.length/20;i++){
  318. temArr.push(temName.slice(i*20,i*20+20))
  319. }
  320. temName=temArr.join('<br>')
  321. }
  322. return temName
  323. }
  324. /* 指标顺序调整 IsAxis: 0右轴 1左轴 2右2*/
  325. function changeEdbOrder (data){
  326. // 左轴指标
  327. let left_edbs = data.filter(_ => _.IsAxis===1);
  328. //右轴指标
  329. let right_edbs = data.filter(_ => !_.IsAxis);
  330. // 右2轴指标
  331. let right_two_edbs = data.filter(_ => _.IsAxis === 2);
  332. // 按 左 右 右2顺序排列
  333. return [left_edbs,right_edbs,right_two_edbs].flat(Infinity);
  334. }
  335. //检查图表英文配置是否完整
  336. function checkChartEnData(){
  337. let result = true
  338. //图表名称:this.chartInfo.ChartNameEn
  339. if(!chartData.value.ChartInfo.ChartNameEn){
  340. result = false
  341. }
  342. //指标名称:this.dataList[].EdbNameEn
  343. //指标单位:this.dataList[].UnitEn
  344. chartData.value.EdbInfoList.forEach(item=>{
  345. if(!item.EdbNameEn){
  346. result = false
  347. }
  348. if(chartData.value.ChartInfo.ChartType!==10&&item.Unit&&!item.UnitEn){
  349. result = false
  350. }
  351. })
  352. return result
  353. }
  354. // 设置图表显示的语言
  355. function setChartLang(changeLangIsCheck){
  356. if(changeLangIsCheck&&!checkChartEnData()) return
  357. const {ChartType,Source} = chartData.value.ChartInfo
  358. if(Source==1){
  359. // 散点图
  360. if(ChartType == 5){
  361. options.value.yAxis.title.text = LangType.value == 'zh' ? options.value.yAxis.title.textZh : options.value.yAxis.title.textEn;
  362. options.value.yAxis.title.style = LangType.value == 'zh' ? {} : options.value.yAxis.title.styleEn;
  363. options.value.xAxis.title.text = LangType.value == 'zh' ? options.value.xAxis.title.textZh : options.value.xAxis.title.textEn
  364. options.value.xAxis.title.style = LangType.value == 'zh' ? {} : options.value.xAxis.title.styleEn;
  365. options.value.series.forEach(item => {
  366. item.name = LangType.value == 'zh' ? item.nameZh : item.nameEn;
  367. });
  368. options.value.tooltip.formatter = LangType.value == 'zh' ? options.value.tooltip.formatterZh : options.value.tooltip.formatterEn;
  369. }else{
  370. // 单位
  371. options.value.yAxis.forEach(item => {
  372. item.title.text = LangType.value == 'zh' ? item.title.textZh : item.title.textEn;
  373. item.title.style = LangType.value == 'zh' ? {} : (item.title.styleEn || {})
  374. });
  375. // 图例 名称
  376. if(ChartType != 2){
  377. // 季节图 不更改图例名称
  378. options.value.series.forEach(item => {
  379. item.name = LangType.value == 'zh'
  380. ? item.nameZh
  381. : (item.nameEn!='无英文名称'?item.nameEn:`<span style="color:#999">${item.nameEn}</span>`)
  382. });
  383. }
  384. //截面散点 x轴标题
  385. if(ChartType === 10){
  386. options.value.xAxis.title.text = LangType.value == 'zh' ? options.value.xAxis.title.textZh : options.value.xAxis.title.textEn;
  387. options.value.xAxis.title.style = LangType.value == 'zh' ? {} : options.value.xAxis.title.styleEn;
  388. options.value.tooltip.formatter = LangType.value == 'zh' ? options.value.tooltip.formatterCh : options.value.tooltip.formatterEn;
  389. options.value.series.forEach(item => {
  390. if(!item.linkedTo) {
  391. item.data.forEach(point => {
  392. point.dataLabels.format = LangType.value == 'zh' ? point.dataLabels.formatZh : (point.dataLabels.formatEn||'无英文标签');
  393. point.dataLabels.color = (LangType.value==='en' && !point.dataLabels.formatEn) ? '#999' : '#333'
  394. })
  395. }
  396. });
  397. }
  398. //柱形图额外设置x轴中英文
  399. if(ChartType ===7){
  400. //x轴
  401. options.value.xAxis.categories = chartData.value.XEdbIdValue.map(_ => LangType.value == 'zh'
  402. ? chartData.value.EdbInfoList.find(edb => edb.EdbInfoId===_).EdbAliasName
  403. : chartData.value.EdbInfoList.find(edb => edb.EdbInfoId===_).EdbNameEn)
  404. }
  405. }
  406. }
  407. if([2,3,4].includes(Source)){
  408. options.value.yAxis.forEach(item => {
  409. item.title.text = LangType.value == 'zh' ? item.title.textZh: item.title.textEn
  410. });
  411. //图例
  412. options.value.series.forEach(item => {
  413. item.name = LangType.value == 'en' ?item.nameEn : item.nameZh
  414. });
  415. //tooltip
  416. options.value.tooltip.formatter = LangType.value == 'en'?options.value.tooltip.formatterEn:options.value.tooltip.formatterZh
  417. //x轴
  418. if(Source==2){
  419. options.value.xAxis.categories = commodityXData.value.map(_ => {
  420. LangType.value == 'en'?_.NameEn:_.Name
  421. });
  422. }
  423. if([3].includes(Source)){
  424. options.value.xAxis.title.text=LangType.value == 'en'?options.value.xAxis.title.textEn:options.value.xAxis.title.textZh
  425. }
  426. }
  427. }
  428. // 设置图标题
  429. function setChartTitle(showChartTitle){
  430. if(showChartTitle){
  431. const ChartInfo=chartData.value.ChartInfo
  432. options.value.title.textZh=ChartInfo.ChartName
  433. options.value.title.textEn=ChartInfo.ChartNameEn
  434. options.value.title.text=LangType.value == 'zh' ?options.value.title.textZh:options.value.title.textEn||options.value.title.textZh
  435. }else{
  436. options.value.title.text=''
  437. }
  438. }
  439. //统计频率图
  440. function setStatisticFrequency(e){
  441. axisLimitState.leftIndex=-1
  442. axisLimitState.rightIndex=-1
  443. axisLimitState.rightTwoIndex=-1
  444. /* 主题样式*/
  445. const chartTheme = e.ChartInfo.ChartThemeStyle ? JSON.parse(e.ChartInfo.ChartThemeStyle) : null;
  446. const { DataList,LeftMaxValue,LeftMinValue,RightMaxValue,RightMinValue } = e.DataResp;
  447. const xAxis = {
  448. ...scatterXAxis,
  449. tickWidth: 1,
  450. labels: {
  451. style: {
  452. ...chartTheme&&chartTheme.xAxisOptions.style
  453. }
  454. }
  455. }
  456. //y和系列
  457. let yAxis = [],series = [];
  458. DataList.forEach((item,index) => {
  459. let y_item = {
  460. ...basicYAxis,
  461. title: {
  462. text: item.Unit,
  463. textCh:item.Unit,// 中文
  464. textEn:item.UnitEn||item.Unit,
  465. align: 'high',
  466. rotation: 0,
  467. y: -15,
  468. reserveSpace: false,
  469. style:{
  470. ...chartTheme&&chartTheme.yAxisOptions.style
  471. },
  472. },
  473. labels: {
  474. style:{
  475. ...chartTheme&&chartTheme.yAxisOptions.style
  476. },
  477. },
  478. opposite: item.IsAxis===1?false:true,
  479. min: index===0? Number(LeftMinValue):Number(RightMinValue),
  480. max: index===0? Number(LeftMaxValue):Number(RightMaxValue),
  481. tickWidth: 1,
  482. }
  483. let series_item = {
  484. data: item.Value.map(_ =>[_.X,_.Y]),
  485. dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
  486. type: (chartTheme&&chartTheme.lineOptions.lineType) || 'spline',
  487. yAxis: index,
  488. name: item.Name,
  489. nameCh: item.Name,
  490. nameEn: item.NameEn||item.Name,
  491. color: item.Color,
  492. lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth)||3,
  493. chartType: 'linear',
  494. zIndex:1
  495. }
  496. series.push(series_item);
  497. yAxis.push(y_item)
  498. })
  499. let tooltip = {
  500. formatter: function() {
  501. let xList = DataList[0].Value.map(_ =>_.X);
  502. let step = xList[1]-xList[0];
  503. let data_interval = `[${this.x},${this.x+step}]`;
  504. let str=`<b>${ data_interval }</b>`;
  505. this.points.forEach(item => {
  506. str += `<br><span style="color:${item.color}">\u25CF</span>${item.series.name}: ${item.y}%<br>`
  507. })
  508. return str
  509. },
  510. shared: true
  511. }
  512. return {
  513. title: {
  514. text:''
  515. },
  516. tooltip,
  517. series,
  518. yAxis,
  519. xAxis
  520. }
  521. }
  522. //曲线图
  523. function setSplineOpt(e){
  524. const data=[4,6,7,8].includes(e.ChartInfo.Source)?[e.DataResp]:e.EdbInfoList
  525. let series=[]
  526. let yAxis=[]
  527. let xAxis = {}
  528. let temYLeftArr=[]
  529. let temYRightArr=[]
  530. let temYRightTwoArr = []
  531. let temYLeftIndex=data.findIndex((item) => item.IsAxis===1)
  532. let temYRightIndex=data.findIndex((item) => !item.IsAxis)
  533. let temYRightTwoIndex = data.findIndex((item) => item.IsAxis===2)
  534. axisLimitState.leftIndex=temYLeftIndex
  535. axisLimitState.rightIndex=temYRightIndex
  536. axisLimitState.rightTwoIndex=temYRightTwoIndex
  537. /* 主题样式*/
  538. const chartTheme = e.ChartInfo.ChartThemeStyle ? JSON.parse(e.ChartInfo.ChartThemeStyle) : null;
  539. let minAndMaxTimeTemArr=[]//存放所有指标的最大最小时间
  540. //有右二轴时排个序 按照左 右 右2的顺序
  541. let newData = data.some(_ =>_.IsAxis===2) ? changeEdbOrder(data) : data;
  542. newData.forEach((item,index)=>{
  543. //轴位置值相同的下标
  544. let sameSideIndex = newData.findIndex(i => i.IsAxis === item.IsAxis);
  545. let dynamic_title = item.EdbName;
  546. let dynamic_arr = newData.filter(
  547. (item) => dynamic_title === item.EdbName
  548. );
  549. //处理数据列name
  550. let temName= setDyncmicSerieName(item,dynamic_arr,'zh')
  551. let temNameEN=setDyncmicSerieName(item,dynamic_arr,'en')
  552. //预测指标配置
  553. let predict_params = item.EdbInfoCategoryType === 1 ? getPredictParams(item) : {};
  554. let seriesItemObj={
  555. data:[],
  556. dataGrouping:{
  557. enabled:false
  558. },
  559. type: (chartTheme&&chartTheme.lineOptions.lineType) || 'spline',
  560. dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
  561. yAxis:index,
  562. name:temName,
  563. nameZh:temName,
  564. nameEn:temNameEN,
  565. color: item.ChartColor,
  566. lineWidth: Number(item.ChartWidth),
  567. visible:true,
  568. LatestDate:item.LatestDate,
  569. LatestValue:item.LatestValue,
  570. ...predict_params
  571. }
  572. item.DataList = item.DataList || [];
  573. for (let i of item.DataList) {
  574. seriesItemObj.data.push([i.DataTimestamp, i.Value]);
  575. }
  576. series.push(seriesItemObj)
  577. // 设置y轴
  578. if(item.IsAxis){
  579. temYLeftArr.push(item)
  580. }else{
  581. temYRightArr.push(item)
  582. }
  583. let yItem={
  584. ...basicYAxis,
  585. IsAxis:item.IsAxis,
  586. labels: {
  587. formatter: function (ctx) {
  588. return sameSideIndex !== index ? '' : ctx.value;
  589. },
  590. align: 'center',
  591. x: [0,2].includes(item.IsAxis) ? 5 : -5,
  592. style:{
  593. ...chartTheme&&chartTheme.yAxisOptions.style
  594. },
  595. },
  596. tickWidth: sameSideIndex !== index ? 0 : 1,
  597. title: {
  598. text: sameSideIndex !== index ? '' : `${item.Unit}`,
  599. textZh:item.Unit,//中文单位
  600. textEn:item.Unit?item.UnitEn:'',//英文单位,但如果无中文单位则不显示
  601. align: 'high',
  602. rotation: 0,
  603. y: -15,
  604. x: (item.IsAxis===0 && temYRightTwoIndex>-1) ? -newData[temYRightTwoIndex].Unit.length*12 : 0,
  605. textAlign: item.IsAxis===1 ? 'left' : 'right',
  606. reserveSpace: false,
  607. style:{
  608. ...chartTheme&&chartTheme.yAxisOptions.style
  609. },
  610. },
  611. opposite: [0,2].includes(item.IsAxis),
  612. reversed: item.IsOrder,
  613. min: item.MinData,
  614. max: item.MaxData,
  615. visible: sameSideIndex === index,
  616. chartEdbInfo:item,//指标数据用于在保存时读取指标数据
  617. plotBands: setAxisPlotAreas(item.IsAxis),
  618. plotLines: setAxisPlotLines(item.IsAxis)
  619. }
  620. yAxis.push(yItem)
  621. if(item.DataList.length>0){
  622. minAndMaxTimeTemArr.push(item.DataList[0].DataTimestamp)
  623. minAndMaxTimeTemArr.push(item.DataList[item.DataList.length-1].DataTimestamp)
  624. }
  625. })
  626. // 设置x轴
  627. // 找出所有指标的最大和最小时间 分成6段
  628. let minTime=Math.min.apply(null,minAndMaxTimeTemArr)
  629. let maxTime=Math.max.apply(null,minAndMaxTimeTemArr)
  630. const isLessThanOneYear = xTimeDiffer(minTime,maxTime)
  631. xAxis={
  632. ...basicXAxis,
  633. labels: {
  634. formatter: function (ctx) {
  635. return isLessThanOneYear
  636. ? HighchartsFormat.dateFormat('%m/%d', ctx.value)
  637. : HighchartsFormat.dateFormat('%y/%m', ctx.value);
  638. },
  639. style: {
  640. ...chartTheme&&chartTheme.xAxisOptions.style
  641. }
  642. },
  643. tickInterval:((maxTime-minTime)/6)/(24*3600*1000)>30?(maxTime-minTime)/6:24*3600*1000*30,
  644. plotBands: setAxisPlotAreas(3,'datetime'),
  645. plotLines: setAxisPlotLines(3,'datetime')
  646. }
  647. yAxis.forEach(item=>{
  648. if(item.IsAxis===1){//左轴
  649. axisLimitState.hasLeftAxis=true
  650. axisLimitState.leftMin=data[temYLeftIndex].MinData
  651. axisLimitState.leftMax=data[temYLeftIndex].MaxData
  652. // item.min=getAxisMaxOrMin(temYLeftArr,'min')
  653. // item.max=getAxisMaxOrMin(temYLeftArr,'max')
  654. item.min=data[temYLeftIndex].MinData
  655. item.max=data[temYLeftIndex].MaxData
  656. }else if (item.IsAxis===2){ // 右2轴
  657. axisLimitState.hasRightTwoAxis=true
  658. axisLimitState.rightTwoMin=data[temYRightTwoIndex].MinData
  659. axisLimitState.rightTwoMax=data[temYRightTwoIndex].MaxData
  660. item.min=data[temYRightTwoIndex].MinData
  661. item.max=data[temYRightTwoIndex].MaxData
  662. }else{
  663. axisLimitState.hasRightAxis=true
  664. axisLimitState.rightMin=data[temYRightIndex].MinData
  665. axisLimitState.rightMax=data[temYRightIndex].MaxData
  666. // item.min=getAxisMaxOrMin(temYRightArr,'min')
  667. // item.max=getAxisMaxOrMin(temYRightArr,'max')
  668. item.min=data[temYRightIndex].MinData
  669. item.max=data[temYRightIndex].MaxData
  670. }
  671. })
  672. return {
  673. series,
  674. xAxis:[xAxis],
  675. yAxis,
  676. rangeSelector:{ enabled: false}
  677. }
  678. }
  679. //季节图
  680. function setSeasonOpt(e){
  681. axisLimitState.leftIndex=0
  682. axisLimitState.rightIndex=-1
  683. axisLimitState.rightTwoIndex=-1
  684. /* 主题样式*/
  685. const chartTheme = e.ChartInfo.ChartThemeStyle ? JSON.parse(e.ChartInfo.ChartThemeStyle) : null;
  686. let chartData={}
  687. const data=e.EdbInfoList[0]
  688. const calendarType=e.ChartInfo.Calendar||'公历'
  689. const colorsArr=chartTheme.colorsOptions;
  690. let series=[],yAxis=[]
  691. //农历默认选中一年数据并隐藏按钮 公历显示全部数据
  692. // let rangeSelector={}
  693. // 农历数据需要去除第一项 农历和公历处理逻辑一样
  694. const chartDataHandle=calendarType === '农历'?
  695. data.DataList.filter((item, index) => index > 0):
  696. data.DataList
  697. // if(calendarType==='公历'){
  698. chartDataHandle.forEach((item,index)=>{
  699. //预测指标配置
  700. let predict_params = data.EdbInfoCategoryType === 1 ? getSeasonPredictParams(item.CuttingDataTimestamp) : {};
  701. let seriesItem={
  702. data:[],
  703. dataGrouping:{
  704. enabled:false
  705. },
  706. type: (chartTheme&&chartTheme.lineOptions.lineType) || data.ChartStyle,
  707. dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
  708. yAxis:0,
  709. name:item.ChartLegend,
  710. lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth) || 1,
  711. color:colorsArr.slice(-chartDataHandle.length)[index],
  712. visible:true,
  713. ...predict_params
  714. }
  715. item.DataList=item.DataList||[]
  716. for(let i of item.DataList){
  717. seriesItem.data.push([i.DataTimestamp, i.Value])
  718. }
  719. series.push(seriesItem)
  720. })
  721. yAxis=[{
  722. IsAxis:data.IsAxis,
  723. labels: {
  724. align: 'center',
  725. y:5,
  726. style: {
  727. ...chartTheme&&chartTheme.yAxisOptions.style
  728. }
  729. },
  730. title: {
  731. text: `${data.Unit}`,
  732. textZh:data.Unit, // 中文
  733. // 中文不存在,无论英文有无都显示空
  734. textEn:data.Unit?data.UnitEn?data.UnitEn:'英文单位':'', // 英文
  735. align: 'high',
  736. rotation: 0,
  737. y: -5,
  738. x: 0,
  739. textAlign: 'left',
  740. reserveSpace: false,
  741. style:{
  742. ...chartTheme&&chartTheme.yAxisOptions.style
  743. },
  744. },
  745. max: Number(data.MaxData),
  746. min: Number(data.MinData),
  747. plotBands: setAxisPlotAreas(1),
  748. plotLines: setAxisPlotLines(1),
  749. lineWidth: 1,
  750. lineColor: '#bfbfbf',
  751. tickColor: '#bfbfbf',
  752. offset: 0,
  753. opposite: false,
  754. reversed: false,
  755. visible: true,
  756. gridLineWidth: 0,
  757. tickWidth: 1,
  758. tickLength:5,
  759. tickPosition: 'inside',
  760. endOnTick: false,
  761. startOnTick: false,
  762. showLastLabel: true, //显示最后刻度值
  763. tickPixelInterval: 50,
  764. // chartEdbInfo:item//指标数据
  765. }]
  766. chartData.series=series
  767. chartData.yAxis=yAxis
  768. // chartData.rangeSelector=rangeSelector
  769. // 设置坐标轴极值
  770. axisLimitState.hasLeftAxis=true
  771. axisLimitState.leftMin=Number(data.MinData)
  772. axisLimitState.leftMax=Number(data.MaxData)
  773. // 季节图x轴显示月/日
  774. let xAxis={
  775. tickPosition: 'inside',
  776. lineColor: '#bfbfbf',
  777. tickColor: '#bfbfbf',
  778. tickLength:5,
  779. type: 'datetime',
  780. ordinal: false,
  781. dateTimeLabelFormats: {
  782. day: '%y/%m',
  783. week: '%y/%m',
  784. month: '%y/%m',
  785. year: '%y/%m',
  786. },
  787. labels: {
  788. formatter: (ctx)=> {
  789. return HighchartsFormat.dateFormat('%m/%d', ctx.value)
  790. },
  791. style: {
  792. ...chartTheme&&chartTheme.xAxisOptions.style
  793. }
  794. },
  795. tickInterval:24*3600*1000*60,//季节图
  796. plotBands: setAxisPlotAreas(3,'datetime'),
  797. plotLines: setAxisPlotLines(3,'datetime')
  798. }
  799. chartData.xAxis=[xAxis]
  800. // 季节图提示框显示 月/日
  801. chartData.tooltip={
  802. split: false,
  803. shared: true,
  804. dateTimeLabelFormats: {
  805. // 时间格式化字符
  806. day: '%m/%d',
  807. week: '%m/%d',
  808. month: '%m/%d',
  809. year: '%m/%d',
  810. },
  811. xDateFormat: '%m/%d',
  812. }
  813. return {
  814. ...chartData,
  815. // title: {
  816. // enabled: true,
  817. // text:e.ChartInfo.ChartName
  818. // },
  819. // legend:{
  820. // enabled:true,
  821. // verticalAlign: 'top',
  822. // y:-10,
  823. // x:(10 * data.Unit.length)/2
  824. // }
  825. }
  826. }
  827. //堆叠图/组合图设置
  828. //本来和曲线图逻辑基本一致兼容下即可 为了以后便于维护和阅读还是拆开写吧
  829. function setStackOrCombinChart(e){
  830. const data=e.EdbInfoList
  831. //图表类型
  832. const chartTypeMap = {
  833. 3: 'areaspline',
  834. 4: 'column',
  835. 6: ''
  836. };
  837. let chartStyle = chartTypeMap[e.ChartInfo.ChartType];
  838. /* 主题样式*/
  839. const chartTheme = e.ChartInfo.ChartThemeStyle ? JSON.parse(e.ChartInfo.ChartThemeStyle) : null;
  840. let series=[]
  841. let yAxis=[]
  842. let xAxis = {}
  843. let temYLeftArr=[]
  844. let temYRightArr=[]
  845. let temYRightTwoArr = []
  846. let temYLeftIndex,temYRightIndex,temYRightTwoIndex;
  847. let minAndMaxTimeTemArr=[]//存放所有指标的最大最小时间
  848. //有右二轴时排个序 按照左 右 右2的顺序
  849. let newData = data.some(_ =>_.IsAxis===2) ? changeEdbOrder(data) : data;
  850. newData.forEach((item,index)=>{
  851. //轴位置值相同的下标
  852. let sameSideIndex = newData.findIndex(i => i.IsAxis === item.IsAxis);
  853. //堆叠图的yAxis必须一致 数据列所对应的y轴
  854. let serie_yIndex = index;
  855. if([3,4].includes(e.ChartInfo.ChartType)) {
  856. // 类型为堆叠图时公用第一个指标y轴
  857. serie_yIndex = 0;
  858. } else if(e.ChartInfo.ChartType ===6 && ['areaspline','column'].includes(item.ChartStyle)) {
  859. // 组合图找第一个堆叠柱状或面积的作为公用
  860. serie_yIndex = newData.findIndex(i => i.ChartStyle === item.ChartStyle);
  861. }
  862. //数据对应的y轴是公用轴则配置也共享
  863. item.IsAxis = serie_yIndex === index ? item.IsAxis : newData[serie_yIndex].IsAxis;
  864. item.IsOrder = serie_yIndex === index ? item.IsOrder : newData[serie_yIndex].IsOrder;
  865. temYLeftIndex = [3,4].includes(e.ChartInfo.ChartType)
  866. ? (newData[serie_yIndex].IsAxis ? serie_yIndex : -1)
  867. : data.findIndex((item) => item.IsAxis===1);
  868. temYRightIndex = [3,4].includes(e.ChartInfo.ChartType)
  869. ? (newData[serie_yIndex].IsAxis ? -1 : serie_yIndex)
  870. : data.findIndex((item) => !item.IsAxis);
  871. temYRightTwoIndex = [3,4].includes(e.ChartInfo.ChartType)
  872. ? -1
  873. : data.findIndex((item) => item.IsAxis===2);
  874. axisLimitState.leftIndex=temYLeftIndex
  875. axisLimitState.rightIndex=temYRightIndex
  876. axisLimitState.rightTwoIndex=temYRightTwoIndex
  877. let dynamic_title = item.EdbName;
  878. let dynamic_arr = newData.filter(
  879. (item) => dynamic_title === item.EdbName
  880. );
  881. //处理数据列name
  882. let temName= setDyncmicSerieName(item,dynamic_arr,'zh')
  883. let temNameEN=setDyncmicSerieName(item,dynamic_arr,'en')
  884. //预测指标配置
  885. let predict_params = item.EdbInfoCategoryType === 1 ? getPredictParams(item) : {};
  886. let seriesItemObj={
  887. data:[],
  888. dataGrouping:{
  889. enabled:false
  890. },
  891. type: chartStyle || item.ChartStyle,
  892. yAxis:serie_yIndex,
  893. name:temName,
  894. nameZh:temName,
  895. nameEn:temNameEN,
  896. color: item.ChartColor,
  897. lineWidth: Number(item.ChartWidth),
  898. fillColor: (e.ChartInfo.ChartType === 3 || (e.ChartInfo.ChartType === 6 && item.ChartStyle === 'areaspline')) ? item.ChartColor : undefined,
  899. visible:true,
  900. LatestDate:item.LatestDate,
  901. LatestValue:item.LatestValue,
  902. ...predict_params
  903. }
  904. item.DataList = item.DataList || [];
  905. for (let i of item.DataList) {
  906. seriesItemObj.data.push([i.DataTimestamp, i.Value]);
  907. }
  908. series.push(seriesItemObj)
  909. // 设置y轴
  910. if(item.IsAxis){
  911. temYLeftArr.push(item)
  912. }else{
  913. temYRightArr.push(item)
  914. }
  915. let yItem={
  916. ...basicYAxis,
  917. IsAxis:item.IsAxis,
  918. labels: {
  919. formatter: function (ctx) {
  920. return sameSideIndex !== index ? '' : ctx.value;
  921. },
  922. align: 'center',
  923. x: [0,2].includes(item.IsAxis) ? 5 : -5,
  924. style:{
  925. ...chartTheme&&chartTheme.yAxisOptions.style
  926. },
  927. },
  928. title: {
  929. // text: sameSideIndex !== index ? '' : `${item.Unit}`,
  930. text: item.Unit,
  931. textZh:item.Unit, // 中文
  932. // 中文不存在,无论英文有无都显示空
  933. textEn:item.Unit?item.UnitEn?item.UnitEn:'英文单位':'', // 英文
  934. align: 'high',
  935. rotation: 0,
  936. y: -15,
  937. x: (item.IsAxis===0 && temYRightTwoIndex>-1) ? -newData[temYRightTwoIndex].Unit.length*12 : 0,
  938. textAlign: item.IsAxis===1 ? 'left' : 'right',
  939. reserveSpace: false,
  940. style:{
  941. ...chartTheme&&chartTheme.yAxisOptions.style
  942. },
  943. },
  944. opposite: [0,2].includes(item.IsAxis),
  945. reversed: item.IsOrder,
  946. min: item.MinData,
  947. max: item.MaxData,
  948. tickWidth: sameSideIndex !== index ? 0 : 1,
  949. visible: serie_yIndex === index && sameSideIndex ===index,
  950. plotBands: setAxisPlotAreas(item.IsAxis),
  951. plotLines: setAxisPlotLines(item.IsAxis),
  952. chartEdbInfo:item//指标数据用于在保存时读取指标数据
  953. }
  954. yAxis.push(yItem)
  955. if(item.DataList.length>0){
  956. minAndMaxTimeTemArr.push(item.DataList[0].DataTimestamp)
  957. minAndMaxTimeTemArr.push(item.DataList[item.DataList.length-1].DataTimestamp)
  958. }
  959. })
  960. // 设置x轴
  961. // 找出所有指标的最大和最小时间 分成6段
  962. let minTime=Math.min.apply(null,minAndMaxTimeTemArr)
  963. let maxTime=Math.max.apply(null,minAndMaxTimeTemArr)
  964. const isLessThanOneYear = xTimeDiffer(minTime,maxTime)
  965. xAxis={
  966. ...basicXAxis,
  967. labels: {
  968. formatter: function (ctx) {
  969. return isLessThanOneYear
  970. ? HighchartsFormat.dateFormat('%m/%d', ctx.value)
  971. : HighchartsFormat.dateFormat('%y/%m', ctx.value);
  972. },
  973. style: {
  974. ...chartTheme&&chartTheme.xAxisOptions.style
  975. }
  976. },
  977. tickInterval:((maxTime-minTime)/6)/(24*3600*1000)>30?(maxTime-minTime)/6:24*3600*1000*30,
  978. plotBands: setAxisPlotAreas(3,'datetime'),
  979. plotLines: setAxisPlotLines(3,'datetime')
  980. }
  981. yAxis.forEach(item=>{
  982. if(item.IsAxis === 1){//左轴
  983. axisLimitState.hasLeftAxis=true
  984. axisLimitState.leftMin=data[temYLeftIndex].MinData
  985. axisLimitState.leftMax=data[temYLeftIndex].MaxData
  986. item.min=data[temYLeftIndex].MinData
  987. item.max=data[temYLeftIndex].MaxData
  988. }else if (item.IsAxis===2){ // 右2轴
  989. axisLimitState.hasRightTwoAxis=true
  990. axisLimitState.rightTwoMin=data[temYRightTwoIndex].MinData
  991. axisLimitState.rightTwoMax=data[temYRightTwoIndex].MaxData
  992. item.min=data[temYRightTwoIndex].MinData
  993. item.max=data[temYRightTwoIndex].MaxData
  994. }else{
  995. axisLimitState.hasRightAxis=true
  996. axisLimitState.rightMin=data[temYRightIndex].MinData
  997. axisLimitState.rightMax=data[temYRightIndex].MaxData
  998. item.min=data[temYRightIndex].MinData
  999. item.max=data[temYRightIndex].MaxData
  1000. }
  1001. })
  1002. return {
  1003. series,
  1004. xAxis:xAxis,
  1005. yAxis,
  1006. rangeSelector:{ enabled: false}
  1007. }
  1008. }
  1009. /* 散点图 第一个指标值为x轴 第二个指标为y轴*/
  1010. function setScatterOptions(data){
  1011. axisLimitState.leftIndex=0
  1012. axisLimitState.rightIndex=-1
  1013. axisLimitState.rightTwoIndex=-1
  1014. const dataList=data.EdbInfoList
  1015. const { ChartInfo } = data;
  1016. /* 主题样式*/
  1017. const chartTheme = ChartInfo.ChartThemeStyle ? JSON.parse(ChartInfo.ChartThemeStyle) : null;
  1018. axisLimitState.hasLeftAxis=true
  1019. axisLimitState.leftMin=Number(dataList[0].MinData)
  1020. axisLimitState.leftMax=Number(dataList[0].MaxData)
  1021. axisLimitData.leftMin=Number(dataList[0].MinData)
  1022. axisLimitData.leftMax=Number(dataList[0].MaxData)
  1023. // 取2个指标中日期相同的数据
  1024. const real_data = [];
  1025. let tmpData_date = {};//用来取点对应的日期
  1026. let data1 = _.cloneDeep(dataList)[0].DataList || [];
  1027. let data2 = _.cloneDeep(dataList)[1].DataList || [];
  1028. data1.forEach((_item) => {
  1029. data2.forEach((_item2) => {
  1030. if(_item.DataTimestamp === _item2.DataTimestamp) {
  1031. //日期
  1032. let itemIndex =_item.Value + "_" +_item2.Value
  1033. if(tmpData_date[itemIndex]) {
  1034. tmpData_date[itemIndex].push( moment(_item.DataTimestamp).format('YYYY/MM/DD'))
  1035. } else {
  1036. tmpData_date[itemIndex] = [moment(_item.DataTimestamp).format('YYYY/MM/DD')]
  1037. }
  1038. //值
  1039. real_data.push({
  1040. x: _item.Value,
  1041. y: _item2.Value
  1042. })
  1043. }
  1044. })
  1045. })
  1046. real_data.sort((x,y) => x-y);
  1047. //悬浮窗 拼接日期 原始指标名称
  1048. let tooltip = {
  1049. formatter: function() {
  1050. return `<strong>${ 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() }</strong><br>
  1051. ${dataList[0].EdbName}: <span style="font-weight: 600"> ${this.x}</span><br>
  1052. ${dataList[1].EdbName}: <span style="font-weight: 600"> ${this.y}</span>
  1053. `
  1054. },
  1055. // 中文
  1056. formatterCh: function() {
  1057. return `<strong>${ 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() }</strong><br>
  1058. ${dataList[0].EdbName}: <span style="font-weight: 600"> ${this.x}</span><br>
  1059. ${dataList[1].EdbName}: <span style="font-weight: 600"> ${this.y}</span>
  1060. `
  1061. },
  1062. // 英文
  1063. formatterEn: function() {
  1064. let str1 = `${dataList[0].EdbNameEn}`
  1065. let str2 = `${dataList[1].EdbNameEn}`
  1066. return `<strong>${ 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() }</strong><br>
  1067. ${str1}: <span style="font-weight: 600"> ${this.x}</span><br>
  1068. ${str2}: <span style="font-weight: 600"> ${this.y}</span>
  1069. `
  1070. }
  1071. }
  1072. const { IsOrder,ChartColor } = dataList[0];
  1073. //y轴
  1074. let yAxis = {
  1075. title: {
  1076. text: `${dataList[1].Unit}`,
  1077. textZh:dataList[1].Unit,
  1078. textEn:dataList[1].Unit?dataList[1].UnitEn:'',
  1079. align: 'high',
  1080. rotation: 0,
  1081. y: -15,
  1082. x:0,
  1083. textAlign: 'left',
  1084. reserveSpace: false,
  1085. style:{
  1086. ...chartTheme&&chartTheme.yAxisOptions.style
  1087. },
  1088. },
  1089. labels: {
  1090. formatter: function (ctx) {
  1091. return ctx.value;
  1092. },
  1093. align: 'center',
  1094. style:{
  1095. ...chartTheme&&chartTheme.yAxisOptions.style
  1096. },
  1097. },
  1098. opposite: false,
  1099. reversed: IsOrder,
  1100. min: Number(dataList[0].MinData),
  1101. max: Number(dataList[0].MaxData),
  1102. tickWidth: 1,
  1103. tickLength: 5,
  1104. lineWidth: 1,
  1105. lineColor: '#bfbfbf',
  1106. tickColor: '#bfbfbf',
  1107. offset: 0,
  1108. visible: true,
  1109. gridLineWidth: 0,
  1110. tickPosition: 'inside',
  1111. endOnTick: false,
  1112. startOnTick: false,
  1113. showLastLabel: true,
  1114. tickPixelInterval: 50,
  1115. plotBands: setAxisPlotAreas(1),
  1116. plotLines: setAxisPlotLines(1)
  1117. }
  1118. //数据列
  1119. let series = {
  1120. data: [],
  1121. type: 'scatter',
  1122. name: `${ChartInfo.ChartName}${IsOrder ? '(逆序)' : ''}`,
  1123. nameZh:`${ChartInfo.ChartName}${IsOrder ? '(逆序)' : ''}`,
  1124. nameEn:ChartInfo.ChartNameEn?`${ChartInfo.ChartNameEn}${IsOrder ? '(reverse)' : ''}`:'',
  1125. color: ChartColor,
  1126. visible:true,
  1127. chartType: 'linear',
  1128. marker: {
  1129. radius: (chartTheme&&chartTheme.lineOptions.radius)||5,
  1130. },
  1131. }
  1132. real_data.forEach(_ => {
  1133. series.data.push([_.x,_.y])
  1134. })
  1135. return {
  1136. title: {
  1137. text:''
  1138. },
  1139. series: [ series ],
  1140. yAxis,
  1141. xAxis: {
  1142. ...scatterXAxis,
  1143. title: {
  1144. text: `${dataList[0].Unit}`,
  1145. textZh:dataList[0].Unit,
  1146. textEn:dataList[0].Unit?dataList[0].UnitEn:'',
  1147. align: 'high',
  1148. rotation: 0,
  1149. x: 0,
  1150. offset: 20,
  1151. style: {
  1152. ...chartTheme&&chartTheme.xAxisOptions.style
  1153. },
  1154. },
  1155. labels: {
  1156. style: {
  1157. ...chartTheme&&chartTheme.xAxisOptions.style
  1158. }
  1159. },
  1160. },
  1161. tooltip
  1162. }
  1163. }
  1164. /* 奇怪柱形图 */
  1165. const barDateList = ref([]);//柱形图的绘图数据
  1166. const barXData = ref([]);//柱形图的x轴
  1167. const barEdbData = ref([]);//柱形图的表格数据 只用于取值
  1168. let axisLimitData={}
  1169. /* 奇怪柱状图 和其他逻辑无公用点 依赖数据为单独的数据
  1170. x轴为指标名称的柱形图 以日期作为series
  1171. */
  1172. function setBarChart (e){
  1173. let seriesData = [];
  1174. const data = _.cloneDeep(barDateList.value);
  1175. /* 主题样式*/
  1176. const chartTheme = e.ChartInfo.ChartThemeStyle ? JSON.parse(e.ChartInfo.ChartThemeStyle) : null;
  1177. //x轴
  1178. let xAxis = {
  1179. ...scatterXAxis,
  1180. categories: barXData.value,
  1181. tickWidth: 1,
  1182. labels: {
  1183. style: {
  1184. ...chartTheme&&chartTheme.xAxisOptions.style
  1185. }
  1186. }
  1187. }
  1188. const { leftMin,leftMax } = axisLimitData;
  1189. // console.log(leftMin,leftMax)
  1190. //y轴
  1191. let yAxis = {
  1192. ...basicYAxis,
  1193. title: {
  1194. text: ``,
  1195. textZh: '',
  1196. textEn: '',
  1197. align: 'high',
  1198. rotation: 0,
  1199. y: -15,
  1200. x:0,
  1201. textAlign: 'left',
  1202. reserveSpace: false,
  1203. style:{
  1204. ...chartTheme&&chartTheme.yAxisOptions.style
  1205. },
  1206. },
  1207. labels: {
  1208. formatter: function (ctx) {
  1209. let val = ctx.value;
  1210. return val;
  1211. },
  1212. align: 'center',
  1213. style:{
  1214. ...chartTheme&&chartTheme.yAxisOptions.style
  1215. },
  1216. },
  1217. min: Number(leftMin),
  1218. max: Number(leftMax),
  1219. opposite: false,
  1220. tickWidth: 1,
  1221. plotBands: setAxisPlotAreas(1),
  1222. plotLines: setAxisPlotLines(1)
  1223. }
  1224. //数据列
  1225. data.forEach(item => {
  1226. let serie_item = {
  1227. data: item.Value,
  1228. type: 'column',
  1229. yAxis: 0,
  1230. name: item.Name || item.Date,
  1231. nameZh: item.Name || item.Date,
  1232. nameEn: item.Date,
  1233. color: item.Color,
  1234. chartType: 'linear',
  1235. visible:true,
  1236. };
  1237. seriesData.push(serie_item)
  1238. })
  1239. return {
  1240. title: {
  1241. text:''
  1242. },
  1243. plotOptions: {
  1244. column:{
  1245. stacking: null,
  1246. },
  1247. },
  1248. series: seriesData,
  1249. yAxis: [ yAxis ],
  1250. xAxis
  1251. }
  1252. }
  1253. /* 获取图表详情后赋值柱状图数据 */
  1254. function initBarData(data){
  1255. const { XEdbIdValue,YDataList,EdbInfoList,ChartInfo } = data;
  1256. let xData = XEdbIdValue.map(_ => EdbInfoList.find(edb => edb.EdbInfoId===_).EdbAliasName)
  1257. // console.log(xData)
  1258. axisLimitState.leftIndex=-1
  1259. axisLimitState.rightIndex=-1
  1260. axisLimitState.rightTwoIndex=-1
  1261. barDateList.value = YDataList;
  1262. barXData.value = xData;
  1263. barEdbData.value = EdbInfoList;
  1264. axisLimitState.hasLeftAxis=true
  1265. axisLimitState.leftMin=Number(ChartInfo.LeftMin)
  1266. axisLimitState.leftMax=Number(ChartInfo.LeftMax)
  1267. axisLimitData.leftMin=Number(ChartInfo.LeftMin)
  1268. axisLimitData.leftMax=Number(ChartInfo.LeftMax)
  1269. return setBarChart(data);
  1270. }
  1271. /* 商品价格曲线设置 绘图逻辑同奇怪柱形图*/
  1272. const commodityChartData = ref([]);//商品价格图的绘图数据
  1273. const commodityXData = ref([]);//商品价格图的x轴
  1274. const commodityEdbList = ref([]);//商品价格图的表格数据 只用于取值
  1275. /* 商品价格曲线设置 绘图逻辑同奇怪柱形图*/
  1276. const setCommodityChart = (leftMin,leftMax) => {
  1277. axisLimitState.leftIndex=-1
  1278. axisLimitState.rightIndex=-1
  1279. axisLimitState.rightTwoIndex=-1
  1280. /* 主题样式*/
  1281. const chartTheme = chartData.value.ChartInfo.ChartThemeStyle ? JSON.parse(chartData.value.ChartInfo.ChartThemeStyle) : null;
  1282. let seriesData = [];
  1283. const data = _.cloneDeep(commodityChartData.value);
  1284. console.log(data);
  1285. //x轴
  1286. let xAxis = {
  1287. ...scatterXAxis,
  1288. categories: commodityXData.value.map(_ => _.Name),
  1289. tickWidth: 1,
  1290. labels: {
  1291. style: {
  1292. ...chartTheme&&chartTheme.xAxisOptions.style
  1293. }
  1294. }
  1295. }
  1296. //y轴
  1297. let yAxis = {
  1298. ...basicYAxis,
  1299. title: {
  1300. text: commodityEdbList.value[0].Unit,
  1301. textZh: commodityEdbList.value[0].Unit,
  1302. textEn: commodityEdbList.value[0].Unit?(commodityEdbList.value[0].UnitEn||'英文单位'):'',
  1303. align: 'high',
  1304. rotation: 0,
  1305. y: -15,
  1306. textAlign: 'left',
  1307. reserveSpace: false,
  1308. style:{
  1309. ...chartTheme&&chartTheme.yAxisOptions.style
  1310. },
  1311. },
  1312. labels: {
  1313. formatter: function (ctx) {
  1314. let val = ctx.value;
  1315. return val;
  1316. },
  1317. align: 'center',
  1318. style:{
  1319. ...chartTheme&&chartTheme.yAxisOptions.style
  1320. },
  1321. },
  1322. min: Number(leftMin),
  1323. max: Number(leftMax),
  1324. opposite: false,
  1325. tickWidth: 1,
  1326. }
  1327. //数据列
  1328. data.forEach(item => {
  1329. //处理首或/尾全是无效数据的以null填充
  1330. let filterData = filterInvalidData(item)
  1331. let serie_item = {
  1332. data: filterData,
  1333. type: (chartTheme&&chartTheme.lineOptions.lineType) || 'spline',
  1334. dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
  1335. yAxis: 0,
  1336. name: item.Name,
  1337. nameZh: item.Name,
  1338. nameEn: item.NameEn,
  1339. color: item.Color,
  1340. chartType: 'linear',
  1341. lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth) || 3,
  1342. visible: true,
  1343. marker: {
  1344. enabled: false
  1345. }
  1346. };
  1347. seriesData.push(serie_item)
  1348. })
  1349. //tooltip
  1350. let tooltip = {
  1351. formatter: function() {
  1352. const ctx = this;
  1353. let str = '';
  1354. ctx.points.forEach(item => {
  1355. let obj_item = data.find(_ => _.Name === item.series.name);
  1356. let index = commodityXData.value.findIndex(_ => _.Name === ctx.x);
  1357. // 合约显示
  1358. const haveContract=obj_item.XEdbInfoIdList[index]
  1359. if(haveContract){
  1360. // 利润曲线指标名
  1361. let edb_name = chartData.value.ChartInfo.Source === 5
  1362. ? (index === 0 ? obj_item.NameList[index] : `${chartData.value.DataResp.ProfitName}(${obj_item.NameList[index]})`)
  1363. : commodityEdbList.value.find(_ => _.EdbInfoId === obj_item.XEdbInfoIdList[index]).EdbName;
  1364. str+=`<b>${ edb_name }</b>`
  1365. if(!obj_item.NoDataEdbList.includes(obj_item.XEdbInfoIdList[index])) {
  1366. str += `<br><span style="color:${item.color}">\u25CF</span>${obj_item.Date}: ${item.y}<br>`
  1367. }else {
  1368. str += `<br><span style="color:${item.color}">\u25CF</span>${obj_item.Date}: 无<br>`
  1369. }
  1370. }
  1371. })
  1372. return str||'无合约'
  1373. },
  1374. formatterCh: function() {
  1375. let str = '';
  1376. this.points.forEach(item => {
  1377. let obj_item = data.find(_ => _.Name === item.series.name);
  1378. let index = commodityXData.value.findIndex(_ => _.Name === this.x);
  1379. str+=`<b>${ commodityEdbList.value.find(_ => _.EdbInfoId === obj_item.XEdbInfoIdList[index]).EdbName }</b>`
  1380. if(!obj_item.NoDataEdbList.includes(obj_item.XEdbInfoIdList[index])) {
  1381. str += `<br><span style="color:${item.color}">\u25CF</span>${obj_item.Date}: ${item.y}<br>`
  1382. }else {
  1383. str += `<br><span style="color:${item.color}">\u25CF</span>${obj_item.Date}: 无<br>`
  1384. }
  1385. })
  1386. return str
  1387. },
  1388. formatterEn: function() {
  1389. let str = '';
  1390. this.points.forEach(item => {
  1391. let obj_item = data.find(_ => _.NameEn === item.series.name);
  1392. let index = commodityXData.value.findIndex(_ => _.NameEn === this.x);
  1393. str+=`<b>${ commodityEdbList.value.find(_ => _.EdbInfoId === obj_item.XEdbInfoIdList[index]).EdbNameEn }</b>`
  1394. if(!obj_item.NoDataEdbList.includes(obj_item.XEdbInfoIdList[index])) {
  1395. str += `<br><span style="color:${item.color}">\u25CF</span>${obj_item.Date}: ${item.y}<br>`
  1396. }else {
  1397. str += `<br><span style="color:${item.color}">\u25CF</span>${obj_item.Date}: 无<br>`
  1398. }
  1399. })
  1400. return str
  1401. },
  1402. shared: true
  1403. }
  1404. // console.log(seriesData);
  1405. return {
  1406. title: {
  1407. text:''
  1408. },
  1409. series: seriesData,
  1410. yAxis: [ yAxis ],
  1411. xAxis,
  1412. tooltip
  1413. }
  1414. };
  1415. /* 处理无效数据为null */
  1416. function filterInvalidData(item){
  1417. let validateArr = item.XEdbInfoIdList.filter(_ =>!item.NoDataEdbList.includes(_));
  1418. let first_index = item.XEdbInfoIdList.findIndex(_ => _ === validateArr[0]);
  1419. let last_index = item.XEdbInfoIdList.findIndex(_ => _ === validateArr[validateArr.length-1]);
  1420. // console.log('first_index',first_index)
  1421. // console.log('last_index',last_index)
  1422. let arr = item.Value.map((item,index) => {
  1423. if(index < first_index || index > last_index) {
  1424. return null
  1425. }else {
  1426. return item
  1427. }
  1428. })
  1429. return arr;
  1430. }
  1431. function initCommodityData(data){
  1432. const { XDataList,YDataList,EdbInfoList,ChartInfo,DataResp } = data;
  1433. commodityEdbList.value = EdbInfoList;
  1434. commodityChartData.value = ChartInfo.Source===5?DataResp.YDataList:YDataList
  1435. commodityXData.value = ChartInfo.Source===5?DataResp.XDataList:XDataList
  1436. axisLimitState.hasLeftAxis=true
  1437. axisLimitState.leftMin=Number(ChartInfo.LeftMin)
  1438. axisLimitState.leftMax=Number(ChartInfo.LeftMax)
  1439. return setCommodityChart(ChartInfo.LeftMin,ChartInfo.LeftMax);
  1440. }
  1441. //相关性图表
  1442. function initRelevanceChart(data){
  1443. /* 主题样式*/
  1444. const chartTheme = data.ChartInfo.ChartThemeStyle ? JSON.parse(data.ChartInfo.ChartThemeStyle) : null;
  1445. axisLimitState.leftIndex=-1
  1446. axisLimitState.rightIndex=-1
  1447. axisLimitState.rightTwoIndex=-1
  1448. // 处理X轴
  1449. let xAxis={
  1450. categories: data.ChartInfo.Source===3?data.XEdbIdValue:data.DataResp.XDateTimeValue,
  1451. tickWidth: 1,
  1452. title: {
  1453. text: data.ChartInfo.Source===3 ?`期数(${data.CorrelationChartInfo.LeadUnit})` : null,
  1454. textZh:data.ChartInfo.Source===3 ? `期数(${data.CorrelationChartInfo.LeadUnit})`:null,
  1455. textEn:data.ChartInfo.Source===3 ? `stage(${relevanceUnitEnMap[data.CorrelationChartInfo.LeadUnit]})`:null,
  1456. align: 'high',
  1457. rotation: 0,
  1458. x: 0,
  1459. y:10,
  1460. offset: 20,
  1461. style: {
  1462. ...chartTheme&&chartTheme.xAxisOptions.style
  1463. }
  1464. },
  1465. labels: {
  1466. style: {
  1467. ...chartTheme&&chartTheme.xAxisOptions.style
  1468. }
  1469. },
  1470. tickInterval: 1,
  1471. offset:0,
  1472. tickmarkPlacement:'on'
  1473. }
  1474. // 处理Y轴
  1475. let yAxis={
  1476. ...basicYAxis,
  1477. title: {
  1478. text: '相关性系数',
  1479. textZh: '相关性系数',
  1480. textEn: 'Correlation coefficient',
  1481. align: 'high',
  1482. rotation: 0,
  1483. y: -15,
  1484. textAlign: 'left',
  1485. reserveSpace: false,
  1486. style:{
  1487. ...chartTheme&&chartTheme.yAxisOptions.style
  1488. },
  1489. },
  1490. labels: {
  1491. formatter: function (ctx) {
  1492. let val = ctx.value;
  1493. return val;
  1494. },
  1495. align: 'center',
  1496. style:{
  1497. ...chartTheme&&chartTheme.yAxisOptions.style
  1498. },
  1499. },
  1500. opposite: false,
  1501. tickWidth: 1,
  1502. }
  1503. //处理series
  1504. let seriesData=[]
  1505. data.YDataList.forEach(item=>{
  1506. let serie_item = {
  1507. data: item.Value,
  1508. type: (chartTheme&&chartTheme.lineOptions.lineType) || 'spline',
  1509. dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
  1510. yAxis: 0,
  1511. name: data.ChartInfo.ChartName,
  1512. nameZh: data.ChartInfo.ChartName,
  1513. nameEn: data.ChartInfo.ChartNameEn,
  1514. color: '#00f',
  1515. chartType: 'linear',
  1516. lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth) || 3,
  1517. visible:true,
  1518. marker: {
  1519. enabled: false
  1520. }
  1521. };
  1522. seriesData.push(serie_item)
  1523. })
  1524. const { LeadValue,LeadUnit } = data.CorrelationChartInfo;
  1525. const { Source } = data.ChartInfo;
  1526. let tooltip = {
  1527. formatter: function() {
  1528. let str = `<p>相关性系数:${this.y.toFixed(4)}</p><br><p>领先${ Source===3 ?this.x+'期' : LeadValue+LeadUnit}</p>`
  1529. return str
  1530. },
  1531. formatterCh: function() {
  1532. let str = `<p>相关性系数:${this.y.toFixed(4)}</p><br><p>领先${ Source===3 ?this.x+'期' : LeadValue+LeadUnit}</p>`
  1533. return str
  1534. },
  1535. formatterEn: function() {
  1536. let str = `<p>Correlation coefficient:${this.y.toFixed(4)}</p><br><p>lead${ Source===3 ? this.x+'stage' : LeadValue+relevanceUnitEnMap[LeadUnit]}</p>`
  1537. return str
  1538. }
  1539. }
  1540. nextTick(()=>{
  1541. // if(data.ChartInfo.Source===3){
  1542. // const hEl=document.getElementById(RenderDomId.value)
  1543. // // console.log(hEl.offsetHeight);
  1544. // xAxis.offset=-(hEl.offsetHeight-98)/2
  1545. // }
  1546. options.value = {
  1547. isRelevanceChart:data.ChartInfo.Source===3,
  1548. title: {
  1549. text:''
  1550. },
  1551. series: seriesData,
  1552. yAxis: [yAxis] ,
  1553. xAxis:xAxis,
  1554. tooltip
  1555. }
  1556. ChartIns.update(options.value,true)
  1557. })
  1558. return {
  1559. isRelevanceChart:true,
  1560. title: {
  1561. text:''
  1562. },
  1563. series: seriesData,
  1564. yAxis: [yAxis] ,
  1565. xAxis:xAxis,
  1566. tooltip
  1567. }
  1568. }
  1569. /* 截面散点图设置 sectionScatterData */
  1570. function setSectionScatterChart({DataResp,ChartInfo}) {
  1571. axisLimitState.leftIndex=-1
  1572. axisLimitState.rightIndex=-1
  1573. axisLimitState.rightTwoIndex=-1
  1574. /* 主题样式*/
  1575. const chartTheme = ChartInfo.ChartThemeStyle ? JSON.parse(ChartInfo.ChartThemeStyle) : null;
  1576. const { DataList,XName,XNameEn,XUnitName,XUnitNameEn,YName,YNameEn,YUnitName,YUnitNameEn } = DataResp;
  1577. const leftMin=Number(DataResp.YMinValue)
  1578. const leftMax=Number(DataResp.YMaxValue)
  1579. const xMin=Number(DataResp.XMinValue)
  1580. const xMax=Number(DataResp.XMaxValue)
  1581. axisLimitState.hasLeftAxis=true
  1582. axisLimitState.hasXAxis=true
  1583. axisLimitState.leftMin=leftMin
  1584. axisLimitState.leftMax=leftMax
  1585. axisLimitState.xMin=xMin
  1586. axisLimitState.xMax=xMax
  1587. //y轴
  1588. let yAxis = {
  1589. ...basicYAxis,
  1590. title: {
  1591. text: YName,
  1592. textZh:YName,// 中文
  1593. textEn:YNameEn|| '',
  1594. style:{
  1595. ...chartTheme&&chartTheme.yAxisOptions.style
  1596. },
  1597. align: 'middle',
  1598. },
  1599. labels: {
  1600. style:{
  1601. ...chartTheme&&chartTheme.yAxisOptions.style
  1602. },
  1603. },
  1604. opposite: false,
  1605. reversed: false,
  1606. min: Number(leftMin),
  1607. max: Number(leftMax),
  1608. tickWidth: 1,
  1609. plotBands: setAxisPlotAreas(1),
  1610. plotLines: setAxisPlotLines(1)
  1611. }
  1612. //x轴
  1613. let xAxis = {
  1614. ...scatterXAxis,
  1615. title: {
  1616. text: XName,
  1617. textZh:XName,// 中文
  1618. textEn:XNameEn || '',
  1619. style: {
  1620. ...chartTheme&&chartTheme.xAxisOptions.style
  1621. },
  1622. align: 'middle',
  1623. },
  1624. labels: {
  1625. style:{
  1626. ...chartTheme&&chartTheme.xAxisOptions.style
  1627. },
  1628. },
  1629. min: Number(xMin),
  1630. max: Number(xMax),
  1631. plotBands: setAxisPlotAreas(3),
  1632. plotLines: setAxisPlotLines(3)
  1633. }
  1634. //数据列
  1635. let series = [];
  1636. DataList.forEach(item => {
  1637. //数据列
  1638. let series_item = {
  1639. data: [],
  1640. type: 'scatter',
  1641. name: item.Name,
  1642. nameZh: item.Name,
  1643. nameEn: item.NameEn,
  1644. color: item.Color,
  1645. lineWidth: 0,
  1646. chartType: 'linear',
  1647. zIndex:1,
  1648. visible: true,
  1649. marker: {
  1650. radius: (chartTheme&&chartTheme.lineOptions.radius)||5,
  1651. },
  1652. }
  1653. item.EdbInfoList.forEach(_ => {
  1654. series_item.data.push({
  1655. x: _.XValue,
  1656. y: _.YValue,
  1657. dataLabels: {
  1658. enabled: _.IsShow,
  1659. allowOverlap: true,
  1660. align: 'left',
  1661. format: _.Name,
  1662. formatZh: _.Name,
  1663. formatEn: _.NameEn
  1664. }
  1665. })
  1666. })
  1667. series.push(series_item);
  1668. //趋势线
  1669. if(item.ShowTrendLine) {
  1670. let trend_data = item.TrendLimitData.map((_,_index) => (
  1671. _index === item.TrendLimitData.length-1 ? {
  1672. x: _.X,
  1673. y: _.Y,
  1674. dataLabels: {
  1675. enabled: item.ShowRSquare || item.ShowFitEquation,
  1676. align: 'left',
  1677. color: '#666',
  1678. x: 20,
  1679. y: 30,
  1680. zIndex: 9,
  1681. allowOverlap: true,
  1682. formatter: function(){
  1683. let tag = '';
  1684. item.ShowRSquare && item.ShowFitEquation
  1685. ? tag =`<span>${item.TrendLine}</span><br><span>R²=${item.RSquare}</span>`
  1686. : item.ShowRSquare && !item.ShowFitEquation
  1687. ? tag =`<span>R²=${item.RSquare}</span>`
  1688. : item.ShowFitEquation && !item.ShowRSquare
  1689. ? tag =`<span>${item.TrendLine}</span>`
  1690. : ''
  1691. return tag
  1692. }
  1693. }
  1694. } : {
  1695. x: _.X,
  1696. y: _.Y,
  1697. }
  1698. ))
  1699. let trend_item = {
  1700. data: trend_data,
  1701. type: 'spline',
  1702. linkedTo: ':previous',
  1703. color: item.Color,
  1704. lineWidth: 1,
  1705. chartType: 'linear',
  1706. enableMouseTracking: false,
  1707. dashStyle:'Dash',
  1708. zIndex: 2,
  1709. visible: true,
  1710. marker: {
  1711. enabled: false
  1712. }
  1713. }
  1714. series.push(trend_item)
  1715. }
  1716. })
  1717. let tooltip = {
  1718. formatter: function() {
  1719. let series_obj = DataList.find(_ => _.Name === this.series.name);
  1720. let ponit_obj = series_obj.EdbInfoList.find(_ => _.XValue ===this.x && _.YValue===this.y);
  1721. let str=`<b>${ ponit_obj.Name }</b>`;
  1722. str += `<br><span style="color:${this.color}">\u25CF</span>${ponit_obj.XName}: ${this.x} ${ponit_obj.XDate}<br>`;
  1723. str += `<span style="color:${this.color}">\u25CF</span>${ponit_obj.YName}: ${this.y} (${ponit_obj.YDate})`;
  1724. return str
  1725. },
  1726. formatterCh: function() {
  1727. let series_obj = DataList.find(_ => _.Name === this.series.name);
  1728. let ponit_obj = series_obj.EdbInfoList.find(_ => _.XValue ===this.x && _.YValue===this.y);
  1729. let str=`<b>${ ponit_obj.Name }</b>`;
  1730. str += `<br><span style="color:${this.color}">\u25CF</span>${ponit_obj.XName}: ${this.x} ${ponit_obj.XDate}<br>`;
  1731. str += `<span style="color:${this.color}">\u25CF</span>${ponit_obj.YName}: ${this.y} (${ponit_obj.YDate})`;
  1732. return str
  1733. },
  1734. formatterEn: function() {
  1735. let series_obj = DataList.find(_ => _.NameEn === this.series.name);
  1736. let ponit_obj = series_obj.EdbInfoList.find(_ => _.XValue ===this.x && _.YValue===this.y);
  1737. let str=`<b>${ ponit_obj.NameEn }</b>`;
  1738. str += `<br><span style="color:${this.color}">\u25CF</span>${ponit_obj.XNameEn}: ${this.x} ${ponit_obj.XDate}<br>`;
  1739. str += `<span style="color:${this.color}">\u25CF</span>${ponit_obj.YNameEn}: ${this.y} ${ponit_obj.YDate}`;
  1740. return str
  1741. }
  1742. }
  1743. return {
  1744. title: {
  1745. text:''
  1746. },
  1747. series,
  1748. yAxis: [yAxis],
  1749. xAxis,
  1750. tooltip
  1751. }
  1752. }
  1753. /* 跨品种分析 */
  1754. function setCrossVarietyChart({DataResp,EdbInfoList,ChartInfo}) {
  1755. axisLimitState.leftIndex=-1
  1756. axisLimitState.rightIndex=-1
  1757. axisLimitState.rightTwoIndex=-1
  1758. /* 主题样式*/
  1759. const chartTheme = ChartInfo.ChartThemeStyle ? JSON.parse(ChartInfo.ChartThemeStyle) : null;
  1760. const { DataList,XName,YName,XNameEn,YNameEn,XMaxValue,XMinValue,YMaxValue,YMinValue } = DataResp;
  1761. //y轴
  1762. let yAxis = {
  1763. ...basicYAxis,
  1764. title: {
  1765. text: YName,
  1766. textCh:YName,// 中文
  1767. textEn:YNameEn||YName,
  1768. align: 'middle',
  1769. style: {
  1770. ...chartTheme&&chartTheme.xAxisOptions.style
  1771. }
  1772. },
  1773. labels: {
  1774. style: {
  1775. ...chartTheme&&chartTheme.xAxisOptions.style
  1776. }
  1777. },
  1778. opposite: false,
  1779. reversed: false,
  1780. min: Number(YMinValue),
  1781. max: Number(YMaxValue),
  1782. tickWidth: 1,
  1783. }
  1784. // x轴
  1785. let xAxis = {
  1786. ...scatterXAxis,
  1787. title: {
  1788. text: XName,
  1789. textCh:XName,// 中文
  1790. textEn:XNameEn || XName,
  1791. align: 'middle',
  1792. style: {
  1793. ...chartTheme&&chartTheme.xAxisOptions.style
  1794. }
  1795. },
  1796. labels: {
  1797. style: {
  1798. ...chartTheme&&chartTheme.xAxisOptions.style
  1799. }
  1800. },
  1801. min: Number(XMinValue),
  1802. max: Number(XMaxValue),
  1803. }
  1804. //数据列
  1805. let series = [];
  1806. DataList.forEach(item => {
  1807. //数据列
  1808. let series_item = {
  1809. data: [],
  1810. type: 'scatter',
  1811. name: item.Name,
  1812. nameCh: item.Name,
  1813. nameEn: item.NameEn||item.Name,
  1814. color: item.Color,
  1815. lineWidth: 0,
  1816. chartType: 'linear',
  1817. zIndex:1
  1818. }
  1819. item.CoordinatePointData.forEach(_ => {
  1820. series_item.data.push({x: _.X,y: _.Y,})
  1821. })
  1822. series.push(series_item);
  1823. })
  1824. let tooltip = {
  1825. formatter: function() {
  1826. let series_obj = DataList.find(_ => _.Name === this.series.name);
  1827. let ponit_obj = series_obj.CoordinatePointData.find(_ => _.X ===this.x && _.Y===this.y);
  1828. let xEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.XEdbInfoId);
  1829. let yEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.YEdbInfoId);
  1830. let str=`<b>${ this.series.name }</b>`;
  1831. str += `<br><span style="color:${this.color}">\u25CF</span>${xEdbInfo.EdbName}: ${this.x} ${ponit_obj.XDate}<br>`;
  1832. str += `<span style="color:${this.color}">\u25CF</span>${yEdbInfo.EdbName}: ${this.y} ${ponit_obj.YDate}`;
  1833. return str
  1834. },
  1835. formatterCh: function() {
  1836. let series_obj = DataList.find(_ => _.Name === this.series.name);
  1837. let ponit_obj = series_obj.CoordinatePointData.find(_ => _.X ===this.x && _.Y===this.y);
  1838. let xEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.XEdbInfoId);
  1839. let yEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.YEdbInfoId);
  1840. let str=`<b>${ this.series.name }</b>`;
  1841. str += `<br><span style="color:${this.color}">\u25CF</span>${xEdbInfo.EdbName}: ${this.x} ${ponit_obj.XDate}<br>`;
  1842. str += `<span style="color:${this.color}">\u25CF</span>${yEdbInfo.EdbName}: ${this.y} ${ponit_obj.YDate}`;
  1843. return str
  1844. },
  1845. formatterEn: function() {
  1846. let series_obj = DataList.find(_ => _.NameEn === this.series.name);
  1847. let ponit_obj = series_obj.CoordinatePointData.find(_ => _.X ===this.x && _.Y===this.y);
  1848. let xEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.XEdbInfoId);
  1849. let yEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.YEdbInfoId);
  1850. let str=`<b>${ this.series.name }</b>`;
  1851. str += `<br><span style="color:${this.color}">\u25CF</span>${xEdbInfo.EdbNameEn}: ${this.x} ${ponit_obj.XDate}<br>`;
  1852. str += `<span style="color:${this.color}">\u25CF</span>${yEdbInfo.EdbNameEn}: ${this.y} ${ponit_obj.YDate}`;
  1853. return str
  1854. }
  1855. }
  1856. return {
  1857. title: {
  1858. text:''
  1859. },
  1860. series,
  1861. yAxis: [yAxis],
  1862. xAxis,
  1863. tooltip
  1864. }
  1865. }