继上次实现图谱后,后续发现如果要继续加入不同样式的图谱实现起来太过麻烦,因此考虑将配置项全部提取封装到js文件中,图谱组件只专注于实现各种不同的组件,其中主要封装的点就是各个节点的横坐标(x),纵坐标(y),以及节点宽(width),节点高(height),节点数组(nodes)和节点相连的边(edges),其他如颜色,字体大小等
封装效果如下:
mapData对象中保存每种金属对应的产业链,通过判断来选择取哪部分数据去显示对应的图谱,比如MapData['CU']即为显示铜的图谱,mapHeight为图谱的默认高度,mapPadding为图谱的父节点要显示的padding,因为图谱不一定需要占满显示,因此加了padding,desc为图谱的描述,nodes和edges为节点和边
实现效果如下:
其中mapData.js内容:
//有色金属
export const mapData = {CU: {//铜mapHeight: 450,mapPadding: 35,desc: '<span>铜产业链逻辑:</span>铜产业链分为上、中、下游。上游主要是采选、冶炼,中游是铜材加工,下游是终端消费。铜价主要受产业供需和宏观因素两个方面影响,但从研究分析上来讲产业可看供给,需求看宏观。宏观因素(核心):经济周期、政策周期、通胀/通缩;基本面因素:供需平衡表、库存周期、价差结构与区域溢价(短期)其他因素:商品大环境、资金面(博弈)、情绪面(事件、避险)',nodes: [{id: 'node1',x: 138,y: 135,width: 176,height: 60,label: '全球铜矿山产能',breedCode: 'CU',indexCode: 'OFFRDE0678557898',text: '全球铜矿山产能',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node2',x: 138,y: 209,width: 176,height: 60,label: '全球铜矿产能利用率',breedCode: 'CU',indexCode: 'ID00303168',text: '全球铜矿产能利用率',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node3',x: 394,y: 172,width: 134,height: 60,label: '全球铜矿供应',breedCode: 'CU',indexCode: 'OFFRDE0789849953',text: '全球铜矿供应',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node4',x: 394,y: 264,width: 134,height: 60,label: '加工费',breedCode: 'CU',indexCode: 'OFFRDE0407946063',text: '加工费',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node5',x: 394,y: 357,width: 134,height: 60,label: '国内铜矿供应',breedCode: 'CU',indexCode: 'OFFRDE0503146446',text: '国内铜矿供应',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node6',x: 591,y: 172,width: 158,height: 60,label: '精炼铜供应',breedCode: 'CU',indexCode: 'ID00407927',text: '精炼铜供应',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node7',x: 591,y: 234,width: 158,height: 40,label: '再生(废杂)铜供应',text: '各类政策因素',breedCode: 'JM',text: '再生(废杂)铜供应',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node8',x: 591,y: 286,width: 158,height: 40,label: '各类政策因素',text: '各类政策因素',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node9',x: 838,y: 31,width: 134,height: 60,label: '全球社会库存',text: '全球社会库存',breedCode: 'CU',indexCode: 'OFFRDE0416122129',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node10',x: 984,y: 31,width: 134,height: 60,label: 'LME铜库存',text: 'LME铜库存',breedCode: 'CU',indexCode: 'OFFRDE0099802675',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node11',x: 1130,y: 31,width: 134,height: 60,label: 'SHFE铜库存',text: 'SHFE铜库存',breedCode: 'CU',indexCode: 'OFFRDE0900823051',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node12',x: 1281,y: 31,width: 145,height: 60,label: 'COMEX铜库存',text: 'COMEX铜库存',breedCode: 'CU',indexCode: 'OFFRDE0470038275',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node13',x: 838,y: 136,width: 134,height: 60,label: '总库存变化',breedCode: 'CU',indexCode: 'OFFRDE0704512926',text: '总库存变化',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node14',x: 838,y: 234,width: 134,height: 60,label: '铜现货价',breedCode: 'CU',indexCode: 'ID00303957',text: '铜现货价',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node15',x: 838,y: 326,width: 134,height: 60,label: '比价与价差',text: '比价与价差',indexCode: 'FU00015882',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node16',x: 838,y: 418,width: 134,height: 60,label: '铜期货价',text: '铜期货价',indexCode: 'FU00015764',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node17',x: 1023,y: 136,width: 134,height: 60,label: '库存消费比',breedCode: 'CU',indexCode: 'OFFRDE0881777811',text: '库存消费比',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node18',x: 1023,y: 234,width: 134,height: 60,label: '表观需求',breedCode: 'CU',indexCode: 'ID01167294',text: '表观需求',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node19',x: 1023,y: 326,width: 134,height: 40,label: '贸易流向',text: '贸易流向',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node20',x: 1023,y: 418,width: 134,height: 40,label: '资金因素',text: '资金因素',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node21',x: 1257,y: 157,width: 134,height: 40,label: '房地产开工',text: '房地产开工',type: 'word-rect',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node22',x: 1257,y: 209,width: 134,height: 40,label: '汽车产销',text: '汽车产销',type: 'word-rect',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node23',x: 1257,y: 261,width: 134,height: 40,label: '基建投资',text: '基建投资',type: 'word-rect',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node24',x: 1257,y: 313,width: 134,height: 40,label: '家电等终端',text: '家电等终端',type: 'word-rect',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},],edges: [{ source: 'node1', target: 'node3' },{ source: 'node2', target: 'node3' },{ source: 'node3', target: 'node4', type: 'hvh3' },{ source: 'node4', target: 'node5', type: 'hvh3' },{ source: 'node3', target: 'node6' },{ source: 'node6', target: 'node14' },{ source: 'node7', target: 'node14' },{ source: 'node8', target: 'node14' },{ source: 'node9', target: 'node13', type: 'hvh3' },{source: 'node10',target: 'node13',type: 'hvh3',sourceAnchor: 2,targetAnchor: 0,},{source: 'node11',target: 'node13',type: 'hvh3',sourceAnchor: 2,targetAnchor: 0,},{source: 'node12',target: 'node13',type: 'hvh3',sourceAnchor: 2,targetAnchor: 0,},{ source: 'node13', target: 'node17' },{ source: 'node13', target: 'node14', type: 'hvh3' },{ source: 'node14', target: 'node18' },{ source: 'node14', target: 'node15', type: 'hvh3' },{ source: 'node15', target: 'node19' },{ source: 'node15', target: 'node16', type: 'hvh3' },{ source: 'node16', target: 'node20' },{ source: 'node18', target: 'node21' },{ source: 'node18', target: 'node22' },{ source: 'node18', target: 'node23' },{ source: 'node18', target: 'node24' },],},AL: {//铝mapHeight: 229,mapPadding: 25,desc: '<span>铝产业链逻辑:</span>铝的产业链主要由铝土矿开采、氧化铝提炼、原铝生产和铝材加工四个环节组成。首先是铝土矿开采,再通过对铝土矿溶解、过滤、酸化和灼烧等工序提炼出氧化铝,然后通过电解熔融的方式制备电解铝。电解铝经过重熔提纯后可进一步加工成各种铝材、铝合金以及铝粉等。铝的上游产业链包括铝土矿开采、氧化铝提炼和原铝生产。原铝经过加工,制成铝加工材,应用于下游各行各业。',nodes: [{id: 'block1',x: 176,y: 120,width: 353,height: 218,type: 'block-rect',label: '上游',},{id: 'block2',x: 530,y: 120,width: 330,height: 218,type: 'block-rect',label: '中游',},{id: 'block3',x: 1020,y: 120,width: 626,height: 218,type: 'block-rect',label: '下游',},{id: 'node1',x: 80,y: 63,width: 134,height: 60,label: '铝土矿',breedCode: 'AL',indexCode: 'OFFRDE0116552998',text: '铝土矿',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node2',x: 80,y: 127,width: 134,height: 40,label: '煤炭',text: '煤炭',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node3',x: 80,y: 179,width: 134,height: 40,label: '石灰石和碱',text: '石灰石和碱',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node4',x: 274,y: 127,width: 134,height: 60,label: '氧化铝',breedCode: 'AL',indexCode: 'ID00188139',text: '氧化铝',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node5',x: 444,y: 75,width: 132,height: 40,label: '电力',text: '电力',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node6',x: 444,y: 127,width: 132,height: 40,label: '氧化铝',text: '氧化铝',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node7',x: 444,y: 185,width: 132,height: 52,label: '碳素阳极、氟化盐、冰晶石等',text: '碳素阳极、氟化盐、冰晶石等',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node8',x: 616,y: 127,width: 134,height: 60,label: '电解铝',breedCode: 'AL',indexCode: 'ID00188823',text: '电解铝',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node9',x: 795,y: 127,width: 134,height: 60,label: '铝合金锭',breedCode: 'AL',indexCode: 'ID01224399',text: '铝合金锭',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node10',x: 970,y: 63,width: 74,height: 40,label: '挤压材',text: '挤压材',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node11',x: 970,y: 127,width: 74,height: 40,label: '压制材',text: '压制材',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node12',x: 970,y: 191,width: 74,height: 40,label: '铸造材',text: '铸造材',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node13',x: 1106,y: 63,width: 116,height: 52,label: '管、棒、型、线等',text: '管、棒、型、线等',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node14',x: 1106,y: 127,width: 116,height: 52,label: '板、带、片、箔等',text: '板、带、片、箔等',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node15',x: 1106,y: 191,width: 116,height: 52,label: '汽车轮毂、发动机等',text: '汽车轮毂、发动机等',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node16',x: 1263,y: 63,width: 116,height: 52,label: '建筑、光伏、线缆',text: '建筑、光伏、线缆',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node17',x: 1263,y: 127,width: 116,height: 52,label: '包装、汽车、家电',text: '包装、汽车、家电',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node18',x: 1263,y: 191,width: 116,height: 52,label: '汽车、五金、电器电子',text: '汽车、五金、电器电子',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},],edges: [{ source: 'node1', target: 'node4' },{ source: 'node2', target: 'node4' },{ source: 'node3', target: 'node4' },{ source: 'node4', target: 'node6' },{ source: 'node5', target: 'node8' },{ source: 'node6', target: 'node8' },{ source: 'node7', target: 'node8' },{ source: 'node8', target: 'node9' },{ source: 'node9', target: 'node10' },{ source: 'node9', target: 'node11' },{ source: 'node9', target: 'node12' },{ source: 'node10', target: 'node13' },{ source: 'node11', target: 'node14' },{ source: 'node12', target: 'node15' },{ source: 'node13', target: 'node16' },{ source: 'node14', target: 'node17' },{ source: 'node15', target: 'node18' },],},AO: {//氧化铝,与铝一样mapHeight: 229,mapPadding: 25,desc: '<span>铝产业链逻辑:</span>铝的产业链主要由铝土矿开采、氧化铝提炼、原铝生产和铝材加工四个环节组成。首先是铝土矿开采,再通过对铝土矿溶解、过滤、酸化和灼烧等工序提炼出氧化铝,然后通过电解熔融的方式制备电解铝。电解铝经过重熔提纯后可进一步加工成各种铝材、铝合金以及铝粉等。铝的上游产业链包括铝土矿开采、氧化铝提炼和原铝生产。原铝经过加工,制成铝加工材,应用于下游各行各业。',nodes: [{id: 'block1',x: 176,y: 120,width: 353,height: 218,type: 'block-rect',label: '上游',},{id: 'block2',x: 530,y: 120,width: 330,height: 218,type: 'block-rect',label: '中游',},{id: 'block3',x: 1020,y: 120,width: 626,height: 218,type: 'block-rect',label: '下游',},{id: 'node1',x: 80,y: 63,width: 134,height: 60,label: '铝土矿',breedCode: 'AL',indexCode: 'OFFRDE0116552998',text: '铝土矿',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node2',x: 80,y: 127,width: 134,height: 40,label: '煤炭',text: '煤炭',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node3',x: 80,y: 179,width: 134,height: 40,label: '石灰石和碱',text: '石灰石和碱',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node4',x: 274,y: 127,width: 134,height: 60,label: '氧化铝',breedCode: 'AL',indexCode: 'ID00188139',text: '氧化铝',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node5',x: 444,y: 75,width: 132,height: 40,label: '电力',text: '电力',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node6',x: 444,y: 127,width: 132,height: 40,label: '氧化铝',text: '氧化铝',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node7',x: 444,y: 185,width: 132,height: 52,label: '碳素阳极、氟化盐、冰晶石等',text: '碳素阳极、氟化盐、冰晶石等',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node8',x: 616,y: 127,width: 134,height: 60,label: '电解铝',breedCode: 'AL',indexCode: 'ID00188823',text: '电解铝',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node9',x: 795,y: 127,width: 134,height: 60,label: '铝合金锭',breedCode: 'AL',indexCode: 'ID01224399',text: '铝合金锭',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node10',x: 970,y: 63,width: 74,height: 40,label: '挤压材',text: '挤压材',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node11',x: 970,y: 127,width: 74,height: 40,label: '压制材',text: '压制材',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node12',x: 970,y: 191,width: 74,height: 40,label: '铸造材',text: '铸造材',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node13',x: 1106,y: 63,width: 116,height: 52,label: '管、棒、型、线等',text: '管、棒、型、线等',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node14',x: 1106,y: 127,width: 116,height: 52,label: '板、带、片、箔等',text: '板、带、片、箔等',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node15',x: 1106,y: 191,width: 116,height: 52,label: '汽车轮毂、发动机等',text: '汽车轮毂、发动机等',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node16',x: 1263,y: 63,width: 116,height: 52,label: '建筑、光伏、线缆',text: '建筑、光伏、线缆',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node17',x: 1263,y: 127,width: 116,height: 52,label: '包装、汽车、家电',text: '包装、汽车、家电',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node18',x: 1263,y: 191,width: 116,height: 52,label: '汽车、五金、电器电子',text: '汽车、五金、电器电子',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},],edges: [{ source: 'node1', target: 'node4' },{ source: 'node2', target: 'node4' },{ source: 'node3', target: 'node4' },{ source: 'node4', target: 'node6' },{ source: 'node5', target: 'node8' },{ source: 'node6', target: 'node8' },{ source: 'node7', target: 'node8' },{ source: 'node8', target: 'node9' },{ source: 'node9', target: 'node10' },{ source: 'node9', target: 'node11' },{ source: 'node9', target: 'node12' },{ source: 'node10', target: 'node13' },{ source: 'node11', target: 'node14' },{ source: 'node12', target: 'node15' },{ source: 'node13', target: 'node16' },{ source: 'node14', target: 'node17' },{ source: 'node15', target: 'node18' },],},PB: {//铅mapHeight: 501,mapPadding: 100,desc: '',nodes: [{id: 'block1',x: 165,y: 255,width: 328,height: 490,type: 'block-rect',label: '原料端',labelCfg: { style: { width: 52, height: 20 } },},{id: 'block2',x: 475,y: 255,width: 270,height: 490,type: 'block-rect',label: '冶炼端',labelCfg: { style: { width: 52, height: 20 } },},{id: 'block3',x: 751,y: 255,width: 258,height: 490,type: 'block-rect',label: '初端下游产品',labelCfg: { style: { width: 88, height: 20 } },},{id: 'block4',x: 1037,y: 255,width: 290,height: 490,type: 'block-rect',label: '终端需求',labelCfg: { style: { width: 64, height: 20 } },},{id: 'node1',x: 50,y: 183,width: 74,height: 40,label: '铅原矿',text: '铅原矿',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node2',x: 164,y: 183,width: 74,height: 40,label: '铅精矿',text: '铅精矿',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node3',x: 279,y: 183,width: 74,height: 40,label: '粗铅',text: '粗铅',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node4',x: 432,y: 131,width: 74,height: 40,label: '阳极泥',text: '阳极泥',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node5',x: 554,y: 131,width: 88,height: 40,label: '金银锡锑',text: '金银锡锑',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node6',x: 554,y: 183,width: 88,height: 40,label: '原生铅',text: '原生铅',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node7',x: 778,y: 104,width: 156,height: 40,label: '其他',text: '其他',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node8',x: 778,y: 156,width: 156,height: 40,label: '蓄电池企业 (>85%)',text: '蓄电池企业 (>85%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',no_compute: true,},{id: 'node9',x: 778,y: 312,width: 156,height: 40,label: '氧化铅',text: '氧化铅',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node10',x: 778,y: 364,width: 156,height: 40,label: '铅合金',text: '铅合金',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node11',x: 778,y: 416,width: 156,height: 40,label: '铅材',text: '铅材',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node12',x: 1044,y: 52,width: 172,height: 40,label: '汽车启动',text: '汽车启动',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node13',x: 1044,y: 104,width: 172,height: 40,label: '电动车',text: '电动车',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node14',x: 1044,y: 156,width: 172,height: 40,label: '通信基站',text: '通信基站',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node15',x: 1044,y: 208,width: 172,height: 40,label: '电力',text: '电力',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node16',x: 1044,y: 260,width: 172,height: 40,label: '其他',text: '其他',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node17',x: 1044,y: 312,width: 172,height: 40,label: '铝盐、稳定剂、助溶剂',text: '铝盐、稳定剂、助溶剂',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node18',x: 1044,y: 364,width: 172,height: 40,label: '轴承、焊料、铅弹',text: '轴承、焊料、铅弹',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node19',x: 1044,y: 416,width: 172,height: 40,label: '铅板、铅管、电缆护套',text: '铅板、铅管、电缆护套',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node20',x: 778,y: 468,width: 156,height: 40,label: '回收',text: '回收',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FFF4F4 1:#FFE1E1',strock: '#F8C3C3',},{id: 'node21',x: 49,y: 312,width: 74,height: 40,label: '铅废料',text: '铅废料',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FFF4F4 1:#FFE1E1',strock: '#F8C3C3',},{id: 'node22',x: 279,y: 312,width: 74,height: 40,label: '还原铅',text: '还原铅',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FFF4F4 1:#FFE1E1',strock: '#F8C3C3',},{id: 'node23',x: 554,y: 312,width: 88,height: 40,label: '再生铅',text: '再生铅',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FFF4F4 1:#FFE1E1',strock: '#F8C3C3',},],edges: [{ source: 'node1', target: 'node2' },{ source: 'node2', target: 'node3' },{ source: 'node3', target: 'node4' },{source: 'node3',target: 'node6',label: '火法',subLabel: '电解',labelCfg: { style: { fontSize: 12, fill: '#245A9A' } },subLabelCfg: { style: { fontSize: 12, fill: '#245A9A' } },},{ source: 'node4', target: 'node5' },{ source: 'node6', target: 'node7' },{ source: 'node6', target: 'node8' },{source: 'node6',target: 'node9',sourceAnchor: 1,targetAnchor: 3,},{source: 'node6',target: 'node10',sourceAnchor: 1,targetAnchor: 3,},{source: 'node6',target: 'node11',sourceAnchor: 1,targetAnchor: 3,},{ source: 'node8', target: 'node12' },{ source: 'node8', target: 'node13' },{ source: 'node8', target: 'node14' },{ source: 'node8', target: 'node15' },{ source: 'node8', target: 'node16' },{ source: 'node9', target: 'node17' },{ source: 'node10', target: 'node18' },{ source: 'node11', target: 'node19' },{source: 'node12',target: 'node20',sourceAnchor: 1,targetAnchor: 1,type: 'hvh_custom',direction: 'left',path: [[1150, 52],[1150, 234],[1170, 234],[1170, 468],],},{source: 'node19',target: 'node20',sourceAnchor: 1,targetAnchor: 1,type: 'hvh_custom',path: [[1150, 416],[1150, 234],[1170, 234],[1170, 468],],},{source: 'node20',target: 'node21',sourceAnchor: 3,targetAnchor: 2,type: 'hvh2',corner: true,},{source: 'node21',target: 'node22',label: '火法',subLabel: '湿法',labelCfg: { style: { fontSize: 12, fill: '#245A9A' } },subLabelCfg: { style: { fontSize: 12, fill: '#245A9A' } },},{ source: 'node22', target: 'node23' },],},ZN: {//锌mapHeight: 323,mapPadding: 0,desc: '<span>锌产业链逻辑:</span>锌生产过程以及实际的行业结构来看,行业价值链主要有三个主体:矿山、锌冶炼商、锌消费企业。矿山负责勘查和开采锌精矿,并将锌精矿出售给下游的锌冶炼企业,锌冶炼企业根据锌消费市场的需求冶炼出符合市场需要的精炼锌以及相关的副产品,锌的最终消费企业从锌冶炼企业购买所需的锌产品。价值链的分析主要侧重在各环节成本、收入的分析,由于矿山的收入基本等于冶炼商原料采购的成本,因此锌精矿的定价机制是研究各环节盈利能力的关键所在。由于锌精矿以加工费(TC/RC)的方式核算,因此锌金属价格和加工费(TC/RC)的高低是影响矿山和冶炼商收入的主要因素。',nodes: [{id: 'block1',x: 878.5,y: 54,width: 411,height: 108,type: 'block-rect',label: '',},{id: 'block2',x: 1155.5,y: 265,width: 425,height: 108,type: 'block-rect',label: '',},{id: 'block3',x: 696,y: 265,width: 454,height: 108,type: 'custom-node',label: '',strock: '#BCD0EE',shadowColor: 'rgba(54,78,128,0.1)',pieceList: [{type: 'rect',x: -227,y: -54,width: 26,height: 108,fill: '#4580D9',stroke: '',lineWidth: 0,radius: [4, 0, 0, 4],label: '一吨锌锭成本',},{type: 'text',x: -220,y: -40,label: '一',fontSize: 12,align: 'left',fill: '#fff',weight: 400},{type: 'text',x: -220,y: -24,label: '吨',fontSize: 12,align: 'left',fill: '#fff',weight: 400},{type: 'text',x: -220,y: -8,label: '锌',fontSize: 12,align: 'left',fill: '#fff',weight: 400},{type: 'text',x: -220,y: 8,label: '锭',fontSize: 12,align: 'left',fill: '#fff',weight: 400},{type: 'text',x: -220,y: 24,label: '成',fontSize: 12,align: 'left',fill: '#fff',weight: 400},{type: 'text',x: -220,y: 40,label: '本',fontSize: 12,align: 'left',fill: '#fff',weight: 400},{type: 'text',x: -191,y: -35,label: '原料成本:70%-80%、加工成本:20%-30%',fontSize: 12,align: 'left',fill: '#D91212',weight: 400},{type: 'text',x: -191,y: -11,label: '锌精矿:1.042吨 用电量:3500-3700kwh 硫酸:300-400kg',fontSize: 12,align: 'left',fill: '#333',weight: 400},{type: 'text',x: -191,y: 11,label: '锌辅料:250元 人工费:300-500元 锌粉:(55-65kg)*40%',fontSize: 12,align: 'left',fill: '#333',weight: 400},{type: 'text',x: -191,y: 33,label: '其他成本:(20-30%) ',fontSize: 12,align: 'left',fill: '#333',weight: 400},]},{id: 'node1',x: 37,y: 89,width: 74,height: 40,label: '锌矿石',text: '锌矿石',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node2',x: 152,y: 89,width: 74,height: 40,label: '锌精矿',text: '锌精矿',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node3',x: 290,y: 89,width: 88,height: 40,label: '加工酸浸',text: '加工酸浸',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node4',x: 290,y: 159,width: 88,height: 40,label: '焙烧',text: '焙烧',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node5',x: 290,y: 230,width: 88,height: 40,label: '常压酸浸',text: '常压酸浸',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node6',x: 412,y: 159,width: 74,height: 40,label: '浸出液',text: '浸出液',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node7',x: 527,y: 159,width: 74,height: 40,label: '净化',text: '净化',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node8',x: 642,y: 159,width: 74,height: 40,label: '电积',text: '电积',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node9',x: 757,y: 159,width: 74,height: 40,label: '电解锌',text: '电解锌',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node10',x: 879,y: 159,width: 88,height: 40,label: '初级消费',text: '初级消费',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node11',x: 1155,y: 159,width: 88,height: 40,label: '终端消费',text: '终端消费',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node12',x: 754.5,y: 28,width: 147,height: 40,label: '镀锌 (30%)',text: '镀锌 (30%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',no_compute: true,fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node13',x: 754.5,y: 80,width: 147,height: 40,label: '压铸锌合金 (30%)',text: '压铸锌合金 (30%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',no_compute: true,fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node14',x: 899.5,y: 28,width: 119,height: 40,label: '黄铜 (22%)',text: '黄铜 (22%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',no_compute: true,fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node15',x: 899.5,y: 80,width: 119,height: 40,label: '氧化锌 (22%)',text: '氧化锌 (22%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',no_compute: true,fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node16',x: 1023.5,y: 28,width: 105,height: 40,label: '电池 (22%)',text: '电池 (22%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',no_compute: true,fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node17',x: 1023.5,y: 80,width: 105,height: 40,label: '其它 (22%)',text: '其它 (22%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',no_compute: true,fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node18',x: 1038.5,y: 239,width: 175,height: 40,label: '房地产及建筑业 (30%)',text: '房地产及建筑业 (30%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',no_compute: true,fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node19',x: 1038.5,y: 291,width: 175,height: 40,label: '基础设施建设 (22%)',text: '基础设施建设 (22%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',no_compute: true,fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node20',x: 1190.5,y: 239,width: 105,height: 40,label: '锌合金 (22%)',text: '锌合金 (22%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',no_compute: true,fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node21',x: 1190.5,y: 291,width: 105,height: 40,label: '汽车 (22%)',text: '汽车 (22%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',no_compute: true,fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node22',x: 1307.5,y: 239,width: 105,height: 40,label: '化工 (22%)',text: '化工 (22%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',no_compute: true,fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node23',x: 1307.5,y: 291,width: 105,height: 40,label: '其它 (22%)',text: '其它 (22%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',no_compute: true,fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},],edges: [{ source: 'node1', target: 'node2' },{ source: 'node2', target: 'node3' },{ source: 'node2', target: 'node4' },{source: 'node3',target: 'node6',sourceAnchor: 1,targetAnchor: 0,type: 'hvh3',corner: true,},{ source: 'node4', target: 'node5', type: 'hvh3' },{ source: 'node4', target: 'node6' },{source: 'node5',target: 'node6',sourceAnchor: 1,targetAnchor: 2,type: 'hvh2',corner: true,},{ source: 'node6', target: 'node7' },{ source: 'node7', target: 'node8' },{ source: 'node8', target: 'node9' },{ source: 'node9', target: 'node10' },{ source: 'node10', target: 'node11' },{ source: 'node10', target: 'block1', type: 'hvh2' },{ source: 'node11', target: 'block2', type: 'hvh3' },],},NI: {//镍mapHeight: 362,mapPadding: 40,desc: '<span>镍产业链逻辑:</span>镍按照生产原料的不同可分为原生镍和再生镍,原生镍的生产原料来自于 镍矿,再生镍的生产原料来自于含镍废料。按照镍金属的含量,原生镍可以分为 四大产品系列,分别是电解镍、含镍生铁、镍铁、其它(镍盐、通用镍等)。',nodes: [{id: 'block1',x: 152.5,y: 184,width: 305,height: 350,type: 'block-rect',label: '上游',labelCfg: { style: { width: 42, height: 20 } },},{id: 'block2',x: 644.5,y: 184,width: 657,height: 350,type: 'block-rect',label: '中游',labelCfg: { style: { width: 40, height: 20 } },},{id: 'block3',x: 1145.5,y: 184,width: 323,height: 350,type: 'block-rect',label: '下游',labelCfg: { style: { width: 40, height: 20 } },},{id: 'block4',x: 56,y: 115,width: 88,height: 56,type: 'custom-node',label: '',strock: '#BCD0EE',shadowColor: 'rgba(54,78,128,0.1)',fill: 'rgba(255,255,255,0.9)',pieceList: [{type: 'text',x: 0,y: -11,label: '自有矿 (19%)',fontSize: 12,align: 'center',fill: '#333',weight: 400},{type: 'text',x: 0,y: 11,label: '进口矿 (81%)',fontSize: 12,align: 'center',fill: '#333',weight: 400},]},{id: 'block5',x: 868,y: 330,width: 177,height: 34,type: 'custom-node',label: '',strock: '#BCD0EE',shadowColor: 'rgba(54,78,128,0.1)',fill: 'rgba(255,255,255,0.9)',pieceList: [{type: 'text',x: 0,y: 0,label: '进口 (30%) 国内产量 (70%)',fontSize: 12,align: 'center',fill: '#333',weight: 400},]},{id: 'node1',x: 56,y: 195,width: 74,height: 40,label: '镍矿',text: '镍矿',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node2',x: 229,y: 127,width: 128,height: 50,label: '硫化锂矿',text: '硫化锂矿',subLabel: '(全球产量占36%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node3',x: 229,y: 261,width: 128,height: 54,label: '氧化锂矿',text: '氧化锂矿',subLabel: '(全球产量占64%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node4',x: 389,y: 127,width: 102,height: 50,label: '采矿',text: '采矿',subLabel: '(含镍1.5%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node5',x: 389,y: 261,width: 102,height: 50,label: '采矿',text: '采矿',subLabel: '(含镍1%-2%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node6',x: 546,y: 127,width: 102,height: 50,label: '镍精矿',text: '镍精矿',subLabel: '(含镍7-10%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node7',x: 703,y: 127,width: 102,height: 50,label: '高冰镍',text: '高冰镍',subLabel: '(含镍70%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node8',x: 868,y: 94,width: 114,height: 50,label: '镍盐',text: '镍盐',subLabel: '(含镍22%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node9',x: 868,y: 156,width: 114,height: 50,label: '电解镍',text: '电解镍',subLabel: '(含镍99.96%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node10',x: 868,y: 261,width: 114,height: 40,label: '镍铁',text: '镍铁',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node11',x: 1040,y: 156,width: 74,height: 40,label: '原生镍',text: '原生镍',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',},{id: 'node12',x: 1217,y: 52,width: 156,height: 40,label: '不锈钢 (84%)',text: '不锈钢 (84%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',no_compute: true,},{id: 'node13',x: 1217,y: 104,width: 156,height: 40,label: '电池 (4%)',text: '电池 (4%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',no_compute: true,},{id: 'node14',x: 1217,y: 156,width: 156,height: 40,label: '电镀 (4%)',text: '电镀 (4%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',no_compute: true,},{id: 'node15',x: 1217,y: 208,width: 156,height: 40,label: '镍造和镍合金 (5%)',text: '镍造和镍合金 (5%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',no_compute: true,},{id: 'node16',x: 1217,y: 260,width: 156,height: 40,label: '其他 (2%)',text: '其他 (2%)',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',fill: 'l(90) 0:#FBFCFF 1:#E9EDF3',strock: '#D4DBE7',no_compute: true,},],edges: [{ source: 'node1', target: 'block4', type: 'hvh2',lineDash: [2,2]},// 自定义虚线模式 { source: 'node1', target: 'node2' },{ source: 'node1', target: 'node3' },{ source: 'node2', target: 'node4' },{ source: 'node3', target: 'node5' },{source: 'node4', target: 'node6', label: '选矿',subLabel: '',labelCfg: { style: { fontSize: 12, fill: '#245A9A' } },subLabelCfg: { style: { fontSize: 12, fill: '#245A9A' } },},{source: 'node4', target: 'node9', sourceAnchor: 2,type: 'hvh_custom',direction: 'top',path: [[389, 201],[868, 201],],targetAnchor: 2, label: '湿法',subLabel: '',labelCfg: { style: { fontSize: 12, fill: '#245A9A' }, startPoint: { x: 389, y: 201 }, endPoint: { x: 868, y: 201 } },//自定义节点传文本所在边的起始点和终点subLabelCfg: { style: { fontSize: 12, fill: '#245A9A' } },},{source: 'node5', target: 'node10', label: '火法',subLabel: '',labelCfg: { style: { fontSize: 12, fill: '#245A9A' } },subLabelCfg: { style: { fontSize: 12, fill: '#245A9A' } },},{source: 'node6', target: 'node7', label: '湿法',subLabel: '',labelCfg: { style: { fontSize: 12, fill: '#245A9A' } },subLabelCfg: { style: { fontSize: 12, fill: '#245A9A' } },},{ source: 'node7', target: 'node8' },{ source: 'node7', target: 'node9' },{ source: 'node8', target: 'node11' },{ source: 'node9', target: 'node11' },{ source: 'node10', target: 'node11' },{ source: 'node10', target: 'block5', type: 'hvh3',lineDash: [2,2] },{source: 'node11', target: 'node12', sourceAnchor: 1,targetAnchor: 3,},{ source: 'node11', target: 'node13' },{ source: 'node11', target: 'node14' },{ source: 'node11', target: 'node15' },{source: 'node11', target: 'node16', sourceAnchor: 1,targetAnchor: 3,},]}
}
//默认黑色品种
export const defaultData = {mapHeight: 366,mapPadding: 0,desc: '',nodes: [{id: 'block1',x: 487,y: 117,width: 972,height: 232,type: 'block-rect',label: '长流程',},{id: 'block2',x: 670,y: 304,width: 604,height: 122,type: 'block-rect',label: '短流程',},{id: 'node1',x: 78,y: 42,label: '焦煤',breedCode: 'JM',indexCode: 'FU00008663',text: '焦煤',dataValue: '8302',chg: '0.16',anchorPoints: [[0, 0.5],[1, 0.5],],},{id: 'node2',x: 244,y: 42,label: '焦炭',breedCode: 'J',indexCode: 'FU00010732',text: '焦炭',dataValue: '8302',chg: '0.16',anchorPoints: [[0, 0.5],[1, 0.5],],},{id: 'node3',x: 244,y: 115,label: '铁矿石',breedCode: 'I',indexCode: 'FU00005559',text: '铁矿石',dataValue: '8302',chg: '-0.82',anchorPoints: [[0, 0.5],[1, 0.5],],},{id: 'node4',x: 466,y: 81,label: '高炉炼铁',dataValue: '8302',chg: '0.16',type: 'breed-rect',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node5',x: 394,y: 189,label: '硅铁',breedCode: 'SF',indexCode: 'FU00000314',text: '硅铁',dataValue: '8302',chg: '0',anchorPoints: [[0, 0],[0.5, 0],],},{id: 'node6',x: 540,y: 189,label: '硅锰',breedCode: 'SM',indexCode: 'FU00000202',text: '硅锰',dataValue: '8302',chg: '-0.16',anchorPoints: [[0, 0.5],[0.5, 0],],},{id: 'node7',x: 669,y: 81,dataValue: '8302',chg: '0.16',anchorPoints: [[0, 0.5],[1, 0.5],],codes: [{label: '产能利用率',chg: '88.54',desc: '历史低位',indexCode: 'ID00183114',text: '高炉炼铁-产能利用率',},{label: '开工率',chg: '88.54',desc: '历史低位',indexCode: 'ID00183109',text: '高炉炼铁-开工率',},{label: '钢厂盈利率',chg: '88.54',desc: '历史低位',indexCode: 'ID00183126',text: '高炉炼铁-钢厂盈利率',},],type: 'rate-rect',},{id: 'node8',x: 886,y: 81,label: '生铁产量',indexCode: 'ID00184088',text: '生铁产量',dataValue: '6669.9',chg: '2.3',type: 'ratio-rect',desc: '高于近一年平均增速',anchorPoints: [[0, 0.5],[1, 0.5],],},{id: 'node9',x: 466,y: 284,label: '废钢',indexCode: 'OFFRDE0554363373',text: '废钢',dataValue: '8302',chg: '0.16',type: 'breed-rect',desc1: '相对高位',desc2: '利好',desc3: '独立电炉企业',anchorPoints: [[0, 0.5],[1, 0.5],],},{id: 'node10',x: 660,y: 284,label: '电炉炼钢',dataValue: '8302',chg: '0.16',type: 'breed-rect',anchorPoints: [[0, 0.5],[1, 0.5],],},{id: 'node11',x: 854,y: 284,label: '',codes: [{label: '产能利用率',chg: '88.54',desc: '历史低位',indexCode: 'ID01302473',text: '电炉炼钢-产能利用率',},{label: '电炉炼钢利润',chg: '88.54',desc: '历史低位',indexCode: 'ID01040556',text: '电炉炼钢-电炉炼钢利率',},],type: 'rate-rect',anchorPoints: [[0, 0.5],[1, 0.5],],},{id: 'node12',x: 1100,y: 188,label: '粗钢',indexCode: 'ID00182958',text: '粗钢',dataValue: '6669.9',chg: '3.3',type: 'ratio-rect',desc: '高于近一年平均增速',anchorPoints: [[0, 0.5],[1, 0.5],],},{id: 'node13',x: 1307,y: 42,label: '螺纹钢',breedCode: 'RB',indexCode: 'FU00001454',text: '螺纹钢',dataValue: '8302',chg: '0.16',anchorPoints: [[0, 0.5],[1, 0.5],],},{id: 'node14',x: 1307,y: 115,label: '线材',breedCode: 'WR',indexCode: 'FU00005821',noClick: true, //是否节点可点击text: '线材',dataValue: '8302',chg: '0.16',anchorPoints: [[0, 0.5],[1, 0.5],],},{id: 'node15',x: 1307,y: 188,label: '热轧板卷',breedCode: 'HC',indexCode: 'FU00002440',text: '热轧板卷',dataValue: '8302',chg: '0.16',anchorPoints: [[0, 0.5],[1, 0.5],],},{id: 'node16',x: 1307,y: 261,label: '不锈钢',breedCode: 'SS',indexCode: 'FU00000075',text: '不锈钢',dataValue: '8302',chg: '0.16',anchorPoints: [[0, 0.5],[1, 0.5],],},{id: 'node17',x: 1307,y: 324,label: '其他',dataValue: '8302',chg: '0.16',type: 'breed-rect',anchorPoints: [[0, 0.5],[1, 0.5],],},],edges: [{ source: 'node1', target: 'node2' },{ source: 'node2', target: 'node4' },{ source: 'node3', target: 'node4' },{ source: 'node5', target: 'node4', type: 'hvh2' },{ source: 'node6', target: 'node4', type: 'hvh2' },{ source: 'node4', target: 'node7', disableArrow: true },{ source: 'node7', target: 'node8' },{ source: 'node9', target: 'node10' },{ source: 'node10', target: 'node11', disableArrow: true },{ source: 'node8', target: 'node12' },{ source: 'node11', target: 'node12' },{ source: 'node12', target: 'node13' },{ source: 'node12', target: 'node14' },{ source: 'node12', target: 'node15' },{ source: 'node12', target: 'node16' },{ source: 'node12', target: 'node17' },],
}
图谱组件link-map.vue:
<template><div class="link-map"><div class="link-title">{{ breedName + props.elementName }}</div><div class="link-desc" v-if="desc !== ''" v-html="desc"></div><gl-spin :spinning="mapLoading"><divid="mountNode":style="{height: mapHeight + 'px',padding: isBlank ? '' : `0 ${mapPadding}px`,maxHeight: maxHeight + 'px',}"></div></gl-spin></div>
</template>
<script setup>
import { onMounted, getCurrentInstance } from 'vue'
import { formatNumValue } from '@/utils/index'
import G6 from '@antv/g6/dist/g6.min'
import { mapData, defaultData } from './mapData'
import { map } from 'lodash'
const { proxy } = getCurrentInstance()
const route = useRoute()
const props = defineProps({secCode: {type: String,default: '',},elementName: {type: String,default: '',},elementCode: {type: String,default: '',},
})
const emit = defineEmits(['breed-select'])
const nodes = ref([])
const edges = ref([])
const mapLoading = ref(false)
const graph2 = ref(null)
const color_breed = ref(['CU', 'AL', 'PB', 'ZN', 'SN', 'NI', 'LC', 'SI', 'AO']) //铜、铝、铅、锌、锡、镍、碳酸锂、工业硅、氧化铝
const mapHeight = ref(mapData[window.breedCode]? mapData[window.breedCode].mapHeight: defaultData.mapHeight
)
const maxHeight = ref(mapData[window.breedCode]? mapData[window.breedCode].mapHeight: defaultData.mapHeight
)
const isBlank = ref(color_breed.value.includes(window.breedCode) ? false : true) //是否黑色品种
const mapPadding = ref(mapData[window.breedCode]? mapData[window.breedCode].mapPadding: defaultData.mapPadding
)
const breedName = ref(window.breedName)
const isDragging = ref(false)
const desc = ref('')const tong_nodes = ref([{id: 'node1',x: 138,y: 136,width: 176,height: 61,label: '全球铜矿山产能',breedCode: 'JM',indexCode: 'OFFRDE0678557898',text: '全球铜矿山产能',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node2',x: 138,y: 209,width: 176,height: 61,label: '全球铜矿产能利用率',breedCode: 'JM',indexCode: 'ID00303168',text: '全球铜矿产能利用率',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node3',x: 394,y: 172,width: 134,height: 61,label: '全球铜矿供应',breedCode: 'JM',indexCode: 'OFFRDE0789849953',text: '全球铜矿供应',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node4',x: 394,y: 264,width: 134,height: 61,label: '加工费',breedCode: 'JM',indexCode: 'OFFRDE0407946063',text: '加工费',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node5',x: 394,y: 357,width: 134,height: 61,label: '国内铜矿供应',breedCode: 'JM',indexCode: 'OFFRDE0503146446',text: '国内铜矿供应',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node6',x: 591,y: 172,width: 158,height: 61,label: '精炼铜供应',breedCode: 'JM',indexCode: 'ID00407927',text: '精炼铜供应',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node7',x: 591,y: 234,width: 158,height: 39,label: '再生(废杂)铜供应',text: '各类政策因素',breedCode: 'JM',text: '再生(废杂)铜供应',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node8',x: 591,y: 286,width: 158,height: 39,label: '各类政策因素',text: '各类政策因素',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node9',x: 838,y: 31,width: 134,height: 61,label: '全球社会库存',text: '全球社会库存',breedCode: 'JM',indexCode: 'OFFRDE0416122129',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node10',x: 984,y: 31,width: 134,height: 61,label: 'LME铜库存',text: 'LME铜库存',breedCode: 'JM',indexCode: 'OFFRDE0099802675',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node11',x: 1130,y: 31,width: 134,height: 61,label: 'SHFE铜库存',text: 'SHFE铜库存',breedCode: 'JM',indexCode: 'OFFRDE0900823051',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node12',x: 1281,y: 31,width: 145,height: 61,label: 'COMEX铜库存',text: 'COMEX铜库存',breedCode: 'JM',indexCode: 'OFFRDE0470038275',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node13',x: 838,y: 136,width: 134,height: 61,label: '总库存变化',breedCode: 'JM',indexCode: 'OFFRDE0704512926',text: '总库存变化',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node14',x: 838,y: 234,width: 134,height: 61,label: '铜现货价',breedCode: 'JM',indexCode: 'ID00303957',text: '铜现货价',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node15',x: 838,y: 326,width: 134,height: 61,label: '比价与价差',text: '比价与价差',indexCode: 'FU00015882',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node16',x: 838,y: 418,width: 134,height: 61,label: '铜期货价',text: '铜期货价',indexCode: 'FU00015764',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node17',x: 1023,y: 136,width: 134,height: 61,label: '库存消费比',breedCode: 'JM',indexCode: 'OFFRDE0881777811',text: '库存消费比',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node18',x: 1023,y: 234,width: 134,height: 61,label: '表观需求',breedCode: 'JM',indexCode: 'ID01167294',text: '表观需求',dataValue: '-',chg: '-',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node19',x: 1023,y: 326,width: 134,height: 39,label: '贸易流向',text: '贸易流向',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node20',x: 1023,y: 418,width: 134,height: 39,label: '资金因素',text: '资金因素',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],type: 'word-rect',},{id: 'node21',x: 1257,y: 157,width: 134,height: 39,label: '房地产开工',text: '房地产开工',type: 'word-rect',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node22',x: 1257,y: 209,width: 134,height: 39,label: '汽车产销',text: '汽车产销',type: 'word-rect',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node23',x: 1257,y: 261,width: 134,height: 39,label: '基建投资',text: '基建投资',type: 'word-rect',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},{id: 'node24',x: 1257,y: 313,width: 134,height: 39,label: '家电等终端',text: '家电等终端',type: 'word-rect',anchorPoints: [[0.5, 0], // 上[1, 0.5], // 右[0.5, 1], // 下[0, 0.5], // 左],},
])
const tong_edges = ref([{ source: 'node1', target: 'node3' },{ source: 'node2', target: 'node3' },{ source: 'node3', target: 'node4', type: 'hvh3' },{ source: 'node4', target: 'node5', type: 'hvh3' },{ source: 'node3', target: 'node6' },{ source: 'node6', target: 'node14' },{ source: 'node7', target: 'node14' },{ source: 'node8', target: 'node14' },{ source: 'node9', target: 'node13', type: 'hvh3' },{source: 'node10',target: 'node13',type: 'hvh3',sourceAnchor: 2,targetAnchor: 0,},{source: 'node11',target: 'node13',type: 'hvh3',sourceAnchor: 2,targetAnchor: 0,},{source: 'node12',target: 'node13',type: 'hvh3',sourceAnchor: 2,targetAnchor: 0,},{ source: 'node13', target: 'node17' },{ source: 'node13', target: 'node14', type: 'hvh3' },{ source: 'node14', target: 'node18' },{ source: 'node14', target: 'node15', type: 'hvh3' },{ source: 'node15', target: 'node19' },{ source: 'node15', target: 'node16', type: 'hvh3' },{ source: 'node16', target: 'node20' },{ source: 'node18', target: 'node21' },{ source: 'node18', target: 'node22' },{ source: 'node18', target: 'node23' },{ source: 'node18', target: 'node24' },
])
const getSvg = (type, iconColor) => {// 动态生成SVG内容const generateSVG1 = (iconColor) => {return `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14px" height="14px" viewBox="0 0 14 14" version="1.1"><title>Icon/涨</title><g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Q2_5_4期限分析_供给分析_最小宽度1180" transform="translate(-388.000000, -226.000000)"><g id="价格" transform="translate(164.000000, 102.000000)"><g id="编组-13" transform="translate(46.000000, 116.000000)"><g id="产业链/期货/涨备份-3" transform="translate(70.000000, 0.000000)"><g id="Icon/涨" transform="translate(108.000000, 8.000000)"><rect id="矩形" x="0" y="0" width="14" height="14"/><path d="M13.234199,3.55970481 C13.5098844,3.54382543 13.7462444,3.75443985 13.7621238,4.03012528 C13.7633238,4.05095907 13.7632183,4.07184754 13.761808,4.09266815 L13.5387743,7.38534552 C13.5201122,7.66085657 13.2816378,7.86907379 13.0061267,7.8504117 C12.8875582,7.84238031 12.775727,7.7923795 12.6906807,7.70937277 L11.522514,6.56902231 C11.5039313,6.59161598 11.4837258,6.61329794 11.4619021,6.63390921 L7.52440214,10.3526592 C7.19748321,10.661416 6.66840549,10.5862535 6.44041171,10.1986641 L4.67251566,7.193375 L1.15091069,10.1604378 C0.879839379,10.3887084 0.486186576,10.3759255 0.230649525,10.1444346 L0.164577825,10.075895 C-0.0844446196,9.78018087 -0.0465935113,9.33858461 0.249120641,9.08956216 L4.40537064,5.58956216 C4.73689384,5.31038473 5.23987001,5.39651159 5.45961961,5.77008591 L7.20126566,8.731625 L10.5006292,5.61609079 L10.525,5.59589343 L9.5175239,4.6123147 C9.3199065,4.41943657 9.31606456,4.10287739 9.5089427,3.90525999 C9.59608394,3.81597757 9.71345538,3.76249833 9.83800849,3.75532412 L13.234199,3.55970481 Z" id="形状结合" fill="${iconColor}" fill-rule="nonzero"/></g></g></g></g></g></g></svg>`}// 下跌const generateSVG2 = (iconColor) => {return `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14px" height="14px" viewBox="0 0 14 14" version="1.1"><title>Icon/跌</title><g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Q2_5_4期限分析_供给分析_最小宽度1180" transform="translate(-547.000000, -226.000000)"><g id="价格" transform="translate(164.000000, 102.000000)"><g id="编组-13" transform="translate(46.000000, 116.000000)"><g id="产业链/期货/跌备份-4" transform="translate(229.000000, 0.000000)"><g id="Icon/跌" transform="translate(108.000000, 8.000000)"><rect id="矩形" x="0" y="0" width="14" height="14"/><path d="M13.234199,3.50481138 C13.5098844,3.48893201 13.7462444,3.69954643 13.7621238,3.97523186 C13.7633238,3.99606564 13.7632183,4.01695412 13.761808,4.03777472 L13.5387743,7.3304521 C13.5201122,7.60596314 13.2816378,7.81418036 13.0061267,7.79551827 C12.8875582,7.78748688 12.775727,7.73748607 12.6906807,7.65447934 L11.522514,6.51412888 C11.5039313,6.53672256 11.4837258,6.55840451 11.4619021,6.57901578 L7.52440214,10.2977658 C7.19748321,10.6065225 6.66840549,10.5313601 6.44041171,10.1437707 L4.67251566,7.13848157 L1.15091069,10.1055444 C0.879839379,10.333815 0.486186576,10.3210321 0.230649525,10.0895412 L0.164577825,10.0210016 C-0.0844446196,9.72528744 -0.0465935113,9.28369118 0.249120641,9.03466874 L4.40537064,5.53466874 C4.73689384,5.25549131 5.23987001,5.34161816 5.45961961,5.71519249 L7.20126566,8.67673157 L10.5006292,5.56119737 L10.525,5.541 L9.5175239,4.55742128 C9.3199065,4.36454314 9.31606456,4.04798397 9.5089427,3.85036657 C9.59608394,3.76108415 9.71345538,3.70760491 9.83800849,3.70043069 L13.234199,3.50481138 Z" id="形状结合" fill="${iconColor}" fill-rule="nonzero" transform="translate(6.883798, 6.994464) scale(1, -1) translate(-6.883798, -6.994464) "/></g></g></g></g></g></g></svg>`}// 持平const generateSVG3 = (iconColor) => {return `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14px" height="14px" viewBox="0 0 14 14" version="1.1"><title>Icon/跌</title><g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Q2_5_4期限分析_供给分析_最小宽度1180" transform="translate(-706.000000, -226.000000)"><g id="价格" transform="translate(164.000000, 102.000000)"><g id="编组-13" transform="translate(46.000000, 116.000000)"><g id="产业链/期货/跌备份-3" transform="translate(388.000000, 0.000000)"><g id="Icon/跌" transform="translate(108.000000, 8.000000)"><rect id="矩形" x="0" y="0" width="14" height="14"/><path d="M2.8,6 L11.2,6 C11.6418278,6 12,6.3581722 12,6.8 C12,7.2418278 11.6418278,7.6 11.2,7.6 L2.8,7.6 C2.3581722,7.6 2,7.2418278 2,6.8 C2,6.3581722 2.3581722,6 2.8,6 Z" id="矩形" fill="${iconColor}"/></g></g></g></g></g></g></svg>`}return ('data:image/svg+xml;charset=utf-8,' +encodeURIComponent(type > 0? generateSVG1(iconColor): type === 0? generateSVG3(iconColor): generateSVG2(iconColor)))
}
const linkData = ref({link1: {indexCode: 'FU00008663',text: '焦煤',dataValue: '',dataChg: '',desc: '',},link2: {indexCode: 'FU00010732',text: '焦炭',dataValue: '',dataChg: '',desc: '',},link3: {indexCode: 'FU00005559',text: '铁矿石',dataValue: '',dataChg: '',desc: '',},link4: {indexCode: 'FU00000314',text: '硅铁',dataValue: '',dataChg: '',desc: '',},link5: {indexCode: 'FU00000202',text: '硅锰',dataValue: '',dataChg: '',desc: '',},link6: {indexCode: 'ID00183114',text: '高炉炼铁-产能利用率',dataValue: '',dataChg: '',desc: '',},link7: {indexCode: 'ID00183109',text: '高炉炼铁-开工率',dataValue: '',dataChg: '',desc: '',},link8: {indexCode: 'ID00183126',text: '高炉炼铁-钢厂盈利率',dataValue: '',dataChg: '',desc: '',},link9: {indexCode: 'ID00184088',text: '生铁产量',dataValue: '',dataChg: '',desc: '',},link10: {indexCode: 'OFFRDE0554363373',text: '废钢',dataValue: '',dataChg: '',desc: '',},link11: {indexCode: 'ID01302473',text: '电炉炼钢-产能利用率',dataValue: '',dataChg: '',desc: '',},link12: {indexCode: 'ID01040556',text: '电炉炼钢-电炉炼钢利率',dataValue: '',dataChg: '',desc: '',},link13: {indexCode: 'ID00182958',text: '粗钢',dataValue: '',dataChg: '',desc: '',},link14: {indexCode: 'FU00001454',text: '螺纹钢',dataValue: '',dataChg: '',desc: '',},link15: {indexCode: 'FU00005821',text: '线材',dataValue: '',dataChg: '',desc: '',},link16: {indexCode: 'FU00002440',text: '热轧板卷',dataValue: '',dataChg: '',desc: '',},link17: {indexCode: 'FU00000075',text: '不锈钢',dataValue: '',dataChg: '',desc: '',},
})
//查询指定品种下链路图数据
const loadGraphData = (menuCode) => {mapLoading.value = trueproxy.$request.get(`/futures-api/api/futures/data/chain?breedCode=${window.breedCode}&elementCode=${props.elementCode}`).then((res) => {console.log('品种下链路图数据', res)mapLoading.value = falseif (res.data) {const data = res.data// if (!isBlank.value) {// console.log('显示铜产业链')// edges.value = tong_edges.value// nodes.value = tong_nodes.value// }console.log('nodes.value', nodes.value)nodes.value.forEach((val) => {if (val.indexCode) {let list = data.filter((item) => item.indexCode == val.indexCode)if (list.length > 0) {val.dataValue = list[0].dataValueval.chg = list[0].dataChgval.desc = list[0].descval.unit = list[0].unitval.sumYoy = list[0].sumYoyif (val.indexCode == 'OFFRDE0554363373') {let descList = list[0].desc.replace(';<br>', '').split(' ')val.desc1 = descList[0]val.desc2 = descList[1]val.desc3 = descList[2]}}} else if (val.codes) {val.codes.forEach((ele) => {if (ele.indexCode) {let list = data.filter((item) => item.indexCode == ele.indexCode)if (list.length > 0) {ele.dataValue = list[0].dataValueele.chg = list[0].dataChgele.desc = list[0].descele.unit = list[0].unit}}})}})nextTick(() => {initGrah()})}})
}
const initGrah = () => {//创建模块节点G6.registerNode('block-rect', {draw(cfg, group) {// 主矩形配置const width = cfg.widthconst height = cfg.heightconst fill = '#FAFCFF'const stroke = '#4376CE'// 创建主矩形const mainRect = group.addShape('rect', {attrs: {x: -width / 2,y: -height / 2,width,height,stroke,fill,lineDash: [2, 2], // 激活状态用实线,非激活用虚线lineWidth: 1,radius: [4, 4, 4, 4],padding: 0,zIndex: -99,},name: 'main-rect',})if (cfg.label == '长流程') {group.addShape('rect', {attrs: {x: -width / 2 + 12,y: height / 2 - 10,width: 52,height: 20,fill: '#4580D9',stroke: '',lineWidth: 0,radius: [2, 2, 2, 2],zIndex: -99,},name: 'top-rect',})group.addShape('text', {attrs: {x: -width / 2 + 37,y: height / 2 + 6,text: '长流程',textAlign: 'center',fill: '#fff',fontSize: 12,zIndex: -99,},name: 'text1',})}if (cfg.label == '短流程') {group.addShape('rect', {attrs: {x: -width / 2 - 26,y: -10,width: 52,height: 20,fill: '#4580D9',stroke: '',lineWidth: 0,radius: [2, 2, 2, 2],zIndex: -99,},name: 'top-rect',})group.addShape('text', {attrs: {x: -width / 2,y: 7,text: '短流程',textAlign: 'center',fill: '#fff',fontSize: 12,zIndex: -99,},name: 'text1',})}let list = ['上游','中游','下游','原料端','冶炼端','初端下游产品','终端需求',]if (list.includes(cfg.label)) {group.addShape('rect', {attrs: {x: -(cfg.labelCfg?.style?.width / 2 || 20),y: -height / 2 - (cfg.labelCfg?.style?.height / 2 || 10),width: cfg.labelCfg?.style?.width || 40,height: cfg.labelCfg?.style?.height || 20,fill: '#4580D9',stroke: '#4580D9',lineWidth: 1,radius: [2, 2, 2, 2],zIndex: -99,},name: 'top-rect',})group.addShape('text', {attrs: {x: 0,y: -height / 2 + 6,text: cfg.label,textAlign: 'center',fill: '#fff',fontSize: 12,zIndex: -99,},name: 'text1',})}return mainRect},})//创建上下分割节点G6.registerNode('split-rect', {draw(cfg, group) {// 主矩形配置const width = 135const height = 60const fill = cfg.chg > 0 ? '#FBEAEC' : cfg.chg < 0 ? '#DFF5EB' : '#F1F2FA'const stroke =cfg.chg > 0 ? '#F8DDE0' : cfg.chg < 0 ? '#B8DDCC' : '#D7DCEA'// 创建主矩形const mainRect = group.addShape('rect', {attrs: {x: -width / 2,y: -height / 2,width,height,fill,stroke,lineWidth: 1,radius: [4, 4, 4, 4],padding: 12,},name: 'main-rect',})// 添加分割线(水平中线)group.addShape('line', {attrs: {x1: -width / 2 + 12,y1: 0,x2: width / 2 - 12,y2: 0,stroke: cfg.chg > 0 ? '#E6C5C6' : cfg.chg < 0 ? '#ACD5C3' : '#D3D9E8',lineWidth: 1,cursor: cfg.text !== '线材' ? 'pointer' : '',},name: 'divider-line',})// 添加上半部分小矩形group.addShape('rect', {attrs: {x: -width / 2,y: -height / 2,width: width,height: 30,fill: '',stroke: '#666',lineWidth: 0,radius: [4, 4, 0, 0],cursor: cfg.text !== '线材' ? 'pointer' : '',},name: 'top-rect',})// 添加下半部分小矩形group.addShape('rect', {attrs: {x: -width / 2,y: 0, // 从分割线下方开始width: width,height: 30,fill: '',stroke: '',lineWidth: 0,radius: [0, 0, 4, 4],cursor: cfg.text !== '线材' ? 'pointer' : '',},name: 'bottom-rect',})if (cfg.label) {group.addShape('text', {attrs: {text: cfg.label,x: -width / 2 + 12,y: -8,textAlign: 'left',fill: '#333',fontSize: 12,fontWeight: 600,cursor: cfg.text !== '线材' ? 'pointer' : '',},name: 'text1',})// 添加SVG图像group.addShape('image', {attrs: {x: width / 2 - 24,y: -22,width: 14,height: 14,img:cfg.chg > 0? getSvg(1, '#D91212'): cfg.chg < 0? getSvg(-1, '#12A96E'): getSvg(0, '#999'),cursor: cfg.text !== '线材' ? 'pointer' : '',},name: 'img-1',})group.addShape('text', {attrs: {text: formatNumValue(cfg.dataValue),x: -width / 2 + 12,y: 22,textAlign: 'left',fill: cfg.chg > 0 ? '#D91212' : cfg.chg < 0 ? '#12A96E' : '#666',fontSize: 12,fontWeight: 600,cursor: cfg.text !== '线材' ? 'pointer' : '',},name: 'text3',})group.addShape('text', {attrs: {text: (cfg.chg > 0 ? '+' : cfg.chg < 0 ? '' : '') + cfg.chg + '%',x: width / 2 - 12,y: 22,textAlign: 'right',fill: cfg.chg > 0 ? '#D91212' : cfg.chg < 0 ? '#12A96E' : '#666',fontSize: 12,fontWeight: 600,cursor: cfg.text !== '线材' ? 'pointer' : '',},name: 'text4',})}return mainRect},// 响应状态变化setState(name, value, item) {// console.log('name', name, value, item)let cfg = item._cfg.modelif (name === 'highlight') {const group = item.getContainer()const main_rect = group.find((ele) => ele.get('name') === 'main-rect')main_rect.attr('stroke',value? cfg.chg > 0? '#D12323': cfg.chg < 0? '#12A96E': '#8E92A1': cfg.chg > 0? '#F8DDE0': cfg.chg < 0? '#B8DDCC': '#D7DCEA')main_rect.attr('cursor', 'pointer')main_rect.attr('lineWidth', value ? 2 : 1)const top_rect = group.find((ele) => ele.get('name') === 'top-rect')// 改变背景色top_rect.attr('fill',value? cfg.chg > 0? '#D12323': cfg.chg < 0? '#12A96E': '#8E92A1': '')const bottom_rect = group.find((ele) => ele.get('name') === 'bottom-rect')// 改变背景色bottom_rect.attr('fill',value? cfg.chg > 0? '#FFF6F7': cfg.chg < 0? '#E9FBF3': '#F8F9FE': '')const text1 = group.find((ele) => ele.get('name') === 'text1')text1.attr('fill', value ? '#FFF' : '#333')const img_1 = group.find((ele) => ele.get('name') === 'img-1')img_1.attr('img',value? cfg.chg > 0? getSvg(1, '#fff'): cfg.chg < 0? getSvg(-1, '#fff'): getSvg(0, '#fff'): cfg.chg > 0? getSvg(1, '#D91212'): cfg.chg < 0? getSvg(-1, '#12A96E'): getSvg(0, '#999'))}if (name === 'hover' && cfg.text != '线材') {const group = item.getContainer()const main_rect = group.find((ele) => ele.get('name') === 'main-rect')main_rect.attr('stroke',value || item.getStates().includes('highlight')? cfg.chg > 0? '#D12323': cfg.chg < 0? '#12A96E': '#8E92A1': cfg.chg > 0? '#F8DDE0': cfg.chg < 0? '#B8DDCC': '#D7DCEA')main_rect.attr('cursor', 'pointer')}},getAnchorPoints() {return [[0.5, 0],[1, 0.5],[0.5, 1],[0, 0.5], // 四边中点]},})//创建品种文本节点G6.registerNode('breed-rect', {draw(cfg, group) {// 主矩形配置const width = cfg.width ? cfg.width : cfg.label == '其他' ? 134 : 120const height = cfg.height ? cfg.height : 40const fill = '#FFF'const stroke = '#C3CDE8'// 创建主矩形const mainRect = group.addShape('rect', {attrs: {x: -width / 2,y: -height / 2,width,height,fill,stroke,lineWidth: 1,radius: [4, 4, 4, 4],padding: 0,shadowOffsetX: 0,shadowOffsetY: 2,shadowBlur: 6,spread: 2,shadowColor: 'rgba(149,157,174,0.1)',},name: 'main-rect',})if (cfg.label) {group.addShape('text', {attrs: {text: cfg.label,x: 0,y: 7,textAlign: 'center',fill: '#333',fontSize: 14,fontWeight: 600,},name: 'text1',})if (cfg.label == '废钢') {group.addShape('text', {attrs: {text: `螺废差:${cfg.dataValue}`,x: -width / 2,y: 46,textAlign: 'left',fill: '#333',fontSize: 12,},name: 'text2',})group.addShape('text', {attrs: {text: `(${cfg.desc1})`,x: -width / 2 + (4 * 12 + (cfg.dataValue.length + '') * 6) + 8,y: 46,textAlign: 'left',fill: '#D91212',fontSize: 12,},name: 'text2-desc1',})group.addShape('text', {attrs: {text: `${cfg.desc2}:`,x: -width / 2,y: 68,textAlign: 'left',fill: '#D91212',fontSize: 12,},name: 'text2-desc2',})group.addShape('text', {attrs: {text: `${cfg.desc3}`,x: -width / 2 + cfg.desc2.length * 12 + 8,y: 68,textAlign: 'left',fill: '#333',fontSize: 12,},name: 'text2-desc3',})}}return mainRect},setState(name, value, item) {if (name === 'hover') {const group = item.getContainer()const main_rect = group.find((ele) => ele.get('name') === 'main-rect')main_rect.attr('shadowColor',value ? 'rgba(149,157,174,0.2)' : 'rgba(149,157,174,0.1)')}},})//创建文本利率节点G6.registerNode('rate-rect', {draw(cfg, group) {// 主矩形配置const width = cfg.codes && cfg.codes.length > 2 ? 204 : 212const height = 12 + cfg.codes.length * 22const fill = '#FFF'const stroke = '#fff'// 创建主矩形const mainRect = group.addShape('rect', {attrs: {x: -width / 2,y: -height / 2,width,height,fill,stroke,lineWidth: 0,radius: [4, 4, 4, 4],padding: 0,shadowOffsetX: 0,shadowOffsetY: 2,shadowBlur: 6,spread: 2,shadowColor: 'rgba(54,78,128,0.1)',},name: 'main-rect',})if (cfg.codes) {cfg.codes.forEach((item, index) => {group.addShape('text', {attrs: {text: `${item.label}: ${item.chg}%`,x: -width / 2 + 12,y: -height / 2 + 24 + 22 * index,textAlign: 'left',fill: '#333',fontSize: 12,},name: `text-${index + 1}`,})group.addShape('text', {attrs: {text: `(${item.desc})`,x:-width / 2 +12 +((item.label.length + 1) * 12 +((item.chg + '').length + 1) * 6) +12,y: -height / 2 + 24 + 22 * index,textAlign: 'left',fill: '#D91212',fontSize: 12,},name: `text-${index + 1}-desc`,})})}return mainRect},})//创建产量同比节点G6.registerNode('ratio-rect', {draw(cfg, group) {// 主矩形配置const width = 147const height = 86const fill = '#FFF'const stroke = '#C3CDE8'// 创建主矩形const mainRect = group.addShape('rect', {attrs: {x: -width / 2,y: -height / 2,width,height,fill,stroke,lineWidth: 1,radius: [4, 4, 4, 4],padding: 0,shadowOffsetX: 0,shadowOffsetY: 2,shadowBlur: 6,spread: 2,shadowColor: 'rgba(149,157,174,0.1)',},name: 'main-rect',})group.addShape('text', {attrs: {text: cfg.label,x: 0,y: -height / 2 + 24,textAlign: 'center',fill: '#333',fontSize: 14,fontWeight: 600,},name: 'text1',})group.addShape('line', {attrs: {x1: -width / 2 + 12,y1: -14,x2: width / 2 - 12,y2: -14,stroke: '#DDE3F2',lineWidth: 1,},name: 'divider-line',})group.addShape('text', {attrs: {text: `${cfg.dataValue}`,x: 16,y: -height / 2 + 55,textAlign: 'right',fill: '#333',fontSize: 16,fontWeight: 600,},name: 'text2',})group.addShape('text', {attrs: {text: `${cfg.unit}`,x: 20,y: -height / 2 + 53,textAlign: 'left',fill: '#666',fontSize: 12,},name: 'text2',})group.addShape('text', {attrs: {text: `累计同比${cfg.sumYoy > 0 ? '上涨' : cfg.sumYoy < 0 ? '下降' : '持平'}`,x: -width / 2 + 12,y: -height / 2 + 75,textAlign: 'left',fill: '#666',fontSize: 12,},name: 'text3',})group.addShape('text', {attrs: {text: `${Math.abs(cfg.sumYoy).toFixed(2)}%`,x: width / 2 - 14,y: -height / 2 + 76,textAlign: 'right',fill:cfg.sumYoy > 0 ? '#D91212' : cfg.sumYoy < 0 ? '#12A96E' : '#666666',fontSize: 14,fontWeight: 600,},name: 'text3-chg',})group.addShape('text', {attrs: {text: `${cfg.desc}`,x: 0,y: -height / 2 + 85 + 22,textAlign: 'center',fill: '#D91212',fontSize: 12,},name: 'text4',})return mainRect},setState(name, value, item) {if (name === 'hover') {const group = item.getContainer()const main_rect = group.find((ele) => ele.get('name') === 'main-rect')main_rect.attr('shadowColor',value ? 'rgba(149,157,174,0.2)' : 'rgba(149,157,174,0.1)')}},})//创建产量价格节点G6.registerNode('product-rect', {draw(cfg, group) {// 主矩形配置const width = cfg.width ? cfg.width : 134const height = cfg.height ? cfg.height : 60const fill = cfg.chg > 0 ? '#FBEAEC' : cfg.chg < 0 ? '#DFF5EB' : '#F1F2FA'const stroke =cfg.chg > 0 ? '#F8DDE0' : cfg.chg < 0 ? '#B8DDCC' : '#D7DCEA'// 创建主矩形const mainRect = group.addShape('rect', {attrs: {x: -width / 2,y: -height / 2,width,height,fill,stroke,lineWidth: 1,radius: [4, 4, 4, 4],padding: 12,},name: 'main-rect',})// 添加分割线(水平中线)group.addShape('line', {attrs: {x1: -width / 2 + 12,y1: 0,x2: width / 2 - 12,y2: 0,stroke: cfg.chg > 0 ? '#E6C5C6' : cfg.chg < 0 ? '#ACD5C3' : '#D3D9E8',lineWidth: 1,},name: 'divider-line',})// 添加上半部分小矩形group.addShape('rect', {attrs: {x: -width / 2,y: -height / 2,width: width,height: 30,fill: '',stroke: '#666',lineWidth: 0,radius: [4, 4, 0, 0],},name: 'top-rect',})// 添加下半部分小矩形group.addShape('rect', {attrs: {x: -width / 2,y: 0, // 从分割线下方开始width: width,height: 30,fill: '',stroke: '',lineWidth: 0,radius: [0, 0, 4, 4],},name: 'bottom-rect',})if (cfg.label) {group.addShape('text', {attrs: {text: cfg.label,x: -width / 2 + 12,y: -8,textAlign: 'left',fill: '#333',fontSize: 12,fontWeight: 600,},name: 'text1',})// 添加SVG图像group.addShape('image', {attrs: {x: width / 2 - 24,y: -22,width: 14,height: 14,img:cfg.chg > 0? getSvg(1, '#D91212'): cfg.chg < 0? getSvg(-1, '#12A96E'): getSvg(0, '#999'),cursor: cfg.text !== '线材' ? 'pointer' : '',},name: 'img-1',})group.addShape('text', {attrs: {text: formatNumValue(cfg.dataValue),x: -width / 2 + 12,y: 22,textAlign: 'left',fill: cfg.chg > 0 ? '#D91212' : cfg.chg < 0 ? '#12A96E' : '#666',fontSize: 12,fontWeight: 600,},name: 'text3',})group.addShape('text', {attrs: {text:(cfg.chg > 0 ? '+' : cfg.chg < 0 ? '' : '') +cfg.chg +(cfg.chg && cfg.chg != '-' ? '%' : ''),x: width / 2 - 12,y: 22,textAlign: 'right',fill: cfg.chg > 0 ? '#D91212' : cfg.chg < 0 ? '#12A96E' : '#666',fontSize: 12,fontWeight: 600,},name: 'text4',})}return mainRect},})//创建文本节点G6.registerNode('word-rect', {draw(cfg, group) {// 主矩形配置const width = cfg.width ? cfg.width : 120const height = cfg.height ? cfg.height : 40let fill = cfg.fill ? cfg.fill : 'l(90) 0:#F5F9FF 1:#E0EDFF'const stroke = cfg.strock ? cfg.strock : '#BCD0EE'// 创建主矩形const mainRect = group.addShape('rect', {attrs: {x: -width / 2,y: -height / 2,width,height,fill: fill,stroke,lineWidth: 1,radius: [4, 4, 4, 4],padding: 0,shadowOffsetX: 0,shadowOffsetY: 2,shadowBlur: 6,spread: 2,shadowColor: 'rgba(149,157,174,0.1)',},name: 'main-rect',})//no_compute,是否不需要计算换行//如果文本长度大于矩形宽度,则进行换行if (cfg.label.length * 16 > cfg.width && !cfg.no_compute) {let startLength = Math.floor((cfg.width - 20) / 16)let lines = Math.ceil(cfg.label.length / startLength)let startTop = (cfg.height - 16 * lines + 2 * (lines - 1)) / 2for (let i = 0; i < lines; i++) {group.addShape('text', {attrs: {x: 0,y: -height / 2 + 6 + startTop + i * 18,text: cfg.label.substring(i * startLength, (i + 1) * startLength),fontSize: 14,textAlign: 'center',textBaseline: 'middle',fill: '#333',fontSize: 14,fontWeight: 600,},name: 'text-shape',})}} else {group.addShape('text', {attrs: {text: cfg.label,x: 0,y: cfg.subLabel ? -2 : 8,textAlign: 'center',fill: '#333',fontSize: 14,fontWeight: 600,},name: 'text1',})if (cfg.subLabel) {group.addShape('text', {attrs: {text: cfg.subLabel,x: 0,y: 17,textAlign: 'center',fill: cfg.subLabel?.style?.fill || '#666',fontSize: cfg.subLabel?.style?.fontSize || 12,fontWeight: cfg.subLabel?.style?.weight || 400,},name: 'text2',})}}return mainRect},setState(name, value, item) {if (name === 'hover') {const group = item.getContainer()const main_rect = group.find((ele) => ele.get('name') === 'main-rect')main_rect.attr('shadowColor',value ? 'rgba(149,157,174,0.2)' : 'rgba(149,157,174,0.1)')}},})//创建自定义节点G6.registerNode('custom-node', {draw(cfg, group) {// 主矩形配置const width = cfg.widthconst height = cfg.heightconst fill = cfg.fill || '#fff'const stroke = cfg.strock// 创建主矩形const mainRect = group.addShape('rect', {attrs: {x: -width / 2,y: -height / 2,width,height,fill: fill,stroke,lineWidth: cfg.lineWidth || 1,radius: cfg.radius || [4, 4, 4, 4],padding: 0,shadowOffsetX: 0,shadowOffsetY: 2,shadowBlur: 6,spread: 2,shadowColor: cfg.shadowColor || 'rgba(149,157,174,0.1)',},name: 'main-rect',})cfg.pieceList &&cfg.pieceList.forEach((e, i) => {if (e.type == 'rect') {group.addShape('rect', {attrs: {x: e.x,y: e.y,width: e.width,height: e.height,fill: e.fill || '#fff',stroke: e.strock || '#fff',lineWidth: e.lineWidth || 0,radius: e.radius,},name: 'top-rect' + i,})}if (e.type == 'text') {group.addShape('text', {attrs: {x: e.x,y: e.y,text: e.label,fontSize: e.fontSize,textAlign: e.align,textBaseline: 'middle',fill: e.fill,fontWeight: e.weight,},name: 'text-shape',})}})return mainRect},setState(name, value, item) {if (name === 'hover') {const group = item.getContainer()const main_rect = group.find((ele) => ele.get('name') === 'main-rect')main_rect.attr('shadowColor',value ? 'rgba(149,157,174,0.2)' : 'rgba(149,157,174,0.1)')}},})//从左往右的箭头G6.registerEdge('hvh', {draw(cfg, group) {const startPoint = cfg.startPointconst endPoint = cfg.endPointconst shape = group.addShape('path', {attrs: {stroke: '#8993AA',path: [['M', startPoint.x, startPoint.y],['L', endPoint.x / 2 + (1 / 2) * startPoint.x, startPoint.y], // 二分之一处['L', endPoint.x / 2 + (1 / 2) * startPoint.x, endPoint.y], // 二分之一处['L', endPoint.x, endPoint.y],],lineWidth: 1,lineDash: cfg.lineDash ? cfg.lineDash : '', // 自定义虚线模式zIndex: 10, // 确保边在顶部// startArrow: {// path: "M 10,0 L -10,-10 L -10,10 Z",// d: 10,// },// endArrow: {// path: "M 10,0 L -10,-10 L -10,10 Z",// d: 5,// },// endArrow: {// path: G6.Arrow.triangle(10, 12, 25), // 三角形箭头// fill: "#333", // 填充颜色// stroke: "#333", // 边框颜色// },},})// 计算箭头方向const angle = Math.atan2(endPoint.y - startPoint.y,endPoint.x - startPoint.x)// 自定义箭头路径生成方法function getArrowPath(x, y, angle) {const length = 9 // 箭头长度const width = 4 // 箭头宽度// 计算箭头三个点的坐标const x1 = x - length * Math.cos(angle)const y1 = y - length * Math.sin(angle)const x2 = x1 - width * Math.cos(angle + Math.PI / 2)const y2 = y1 - width * Math.sin(angle + Math.PI / 2)const x3 = x1 - width * Math.cos(angle - Math.PI / 2)const y3 = y1 - width * Math.sin(angle - Math.PI / 2)return [['M', x, y], ['L', x2, y2], ['L', x3, y3], ['Z']]}//是否不需要显示箭头if (!cfg.disableArrow) {// 在终点绘制自定义箭头group.addShape('path', {attrs: {path: getArrowPath(endPoint.x, endPoint.y, 0),fill: '#8993AA',stroke: '#8993AA',lineWidth: 1,},})}// //在边上画循环点const circle = group.addShape('ellipse', {attrs: {x: cfg.startPoint.x,y: cfg.startPoint.y,fill: 'l(0) 0:rgba(102,212,255,0.7) 1:#1A56FF',rx: 4,ry: 1,shadowColor: '#1A56FF',shadowBlur: 4,shadowOffsetY: 1,},name: 'circle-shape',})const time =(Math.abs(cfg.endPoint.x - cfg.startPoint.x) +Math.abs(cfg.endPoint.y - cfg.startPoint.y)) /0.05circle.show()circle.animate((ratio) => {const tmpPoint = shape.getPoint(ratio)const pos = G6.Util.getLabelPosition(shape, ratio)let matrix = [1, 0, 0, 0, 1, 0, 0, 0, 1]matrix = G6.Util.transform(matrix, [['t', -tmpPoint.x, -tmpPoint.y],['r', pos.angle],['t', tmpPoint.x, tmpPoint.y],])return {x: tmpPoint.x,y: tmpPoint.y,matrix,}},{repeat: true,duration: time,easing: 'easeLinear',delay: 0,})// 计算边的中点const midX = (startPoint.x + endPoint.x) / 2const midY = (startPoint.y + endPoint.y) / 2// 计算边的角度(用于文本旋转)const angle2 = Math.atan2(endPoint.y - startPoint.y,endPoint.x - startPoint.x)// 添加上方文本if (cfg.label) {group.addShape('text', {attrs: {x: midX,y: midY - 6, // 上方偏移text: cfg.label,fill: cfg.labelCfg?.style?.fill || '#333',fontSize: cfg.labelCfg?.style?.fontSize || 12,textAlign: 'center',textBaseline: 'bottom',rotate: angle2,},})}// 添加下方文本if (cfg.subLabel) {group.addShape('text', {attrs: {x: midX,y: midY + 6, // 下方偏移text: cfg.subLabel,fill: cfg.subLabelCfg?.style?.fill || '#666',fontSize: cfg.subLabelCfg?.style?.fontSize || 12,textAlign: 'center',textBaseline: 'top',rotate: angle2,},})}return shape},})//从下往上的边G6.registerEdge('hvh2', {draw(cfg, group) {const startPoint = cfg.startPointconst endPoint = cfg.endPoint//默认显示2个拐角let shape = nullif (cfg.corner) {//只显示一个拐角shape = group.addShape('path', {attrs: {stroke: '#8993AA',path: [['M', startPoint.x, startPoint.y],['L', endPoint.x, startPoint.y],['L', endPoint.x, endPoint.y],],lineWidth: 1,lineDash: cfg.lineDash ? cfg.lineDash : '', // 自定义虚线模式zIndex: 10, // 确保边在顶部},})} else {shape = group.addShape('path', {attrs: {stroke: '#8993AA',path: [['M', startPoint.x, startPoint.y],['L',startPoint.x,(2 / 3) * startPoint.y + (1 / 3) * endPoint.y,], // 三分之一处['L', endPoint.x, (2 / 3) * startPoint.y + (1 / 3) * endPoint.y], // 三分之二处['L', endPoint.x, endPoint.y],],lineWidth: 1,lineDash: cfg.lineDash ? cfg.lineDash : '', // 自定义虚线模式zIndex: 10, // 确保边在顶部},})}// 计算箭头方向const angle = Math.atan2(endPoint.y - startPoint.y,endPoint.x - startPoint.x)// 自定义箭头路径生成方法function getArrowPath(x, y, angle) {const length = 9 // 箭头长度const width = 4 // 箭头宽度// 计算箭头三个点的坐标const x1 = xconst y1 = yconst x2 = x1 - widthconst y2 = y1 + lengthconst x3 = x1 + widthconst y3 = y1 + lengthreturn [['M', x, y], ['L', x2, y2], ['L', x3, y3], ['Z']]}// 在终点绘制自定义箭头group.addShape('path', {attrs: {path: getArrowPath(endPoint.x, endPoint.y, 0),fill: '#8993AA',stroke: '#8993AA',lineWidth: 1,},})// //在边上画循环点const circle = group.addShape('ellipse', {attrs: {x: cfg.startPoint.x,y: cfg.startPoint.y,fill: 'l(0) 0:rgba(102,212,255,0.7) 1:#1A56FF',rx: 4,ry: 1,shadowColor: '#1A56FF',shadowBlur: 4,shadowOffsetY: 1,},name: 'circle-shape',})const time =(Math.abs(cfg.endPoint.x - cfg.startPoint.x) +Math.abs(cfg.endPoint.y - cfg.startPoint.y)) /0.05circle.show()circle.animate((ratio) => {const tmpPoint = shape.getPoint(ratio)const pos = G6.Util.getLabelPosition(shape, ratio)let matrix = [1, 0, 0, 0, 1, 0, 0, 0, 1]matrix = G6.Util.transform(matrix, [['t', -tmpPoint.x, -tmpPoint.y],['r', pos.angle],['t', tmpPoint.x, tmpPoint.y],])return {x: tmpPoint.x,y: tmpPoint.y,matrix,}},{repeat: true,duration: time,easing: 'easeLinear',delay: 0,})return shape},})//从上往下的边G6.registerEdge('hvh3', {draw(cfg, group) {const startPoint = cfg.startPointconst endPoint = cfg.endPoint//默认显示2个拐角let shape = nullif (cfg.corner) {//只显示一个拐角shape = group.addShape('path', {attrs: {stroke: '#8993AA',path: [['M', startPoint.x, startPoint.y],['L', endPoint.x, startPoint.y],['L', endPoint.x, endPoint.y],],lineWidth: 1,lineDash: cfg.lineDash ? cfg.lineDash : '', // 自定义虚线模式},})} else {shape = group.addShape('path', {attrs: {stroke: '#8993AA',path: [['M', startPoint.x, startPoint.y],['L',startPoint.x,(2 / 3) * startPoint.y + (1 / 3) * endPoint.y,], // 三分之一处['L', endPoint.x, (2 / 3) * startPoint.y + (1 / 3) * endPoint.y], // 三分之二处['L', endPoint.x, endPoint.y],],lineWidth: 1,lineDash: cfg.lineDash ? cfg.lineDash : '', // 自定义虚线模式},})}// 计算箭头方向const angle = Math.atan2(endPoint.y - startPoint.y,endPoint.x - startPoint.x)// 自定义箭头路径生成方法function getArrowPath(x, y, angle) {const length = 9 // 箭头长度const width = 4 // 箭头宽度// 计算箭头三个点的坐标const x1 = xconst y1 = yconst x2 = x1 - widthconst y2 = y1 - lengthconst x3 = x1 + widthconst y3 = y1 - lengthreturn [['M', x, y], ['L', x2, y2], ['L', x3, y3], ['Z']]}// 在终点绘制自定义箭头group.addShape('path', {attrs: {path: getArrowPath(endPoint.x, endPoint.y, 0),fill: '#8993AA',stroke: '#8993AA',lineWidth: 1,},})// //在边上画循环点const circle = group.addShape('ellipse', {attrs: {x: cfg.startPoint.x,y: cfg.startPoint.y,fill: 'l(0) 0:rgba(102,212,255,0.7) 1:#1A56FF',rx: 4,ry: 1,shadowColor: '#1A56FF',shadowBlur: 4,shadowOffsetY: 1,},name: 'circle-shape',})const time =(Math.abs(cfg.endPoint.x - cfg.startPoint.x) +Math.abs(cfg.endPoint.y - cfg.startPoint.y)) /0.05circle.show()circle.animate((ratio) => {const tmpPoint = shape.getPoint(ratio)const pos = G6.Util.getLabelPosition(shape, ratio)let matrix = [1, 0, 0, 0, 1, 0, 0, 0, 1]matrix = G6.Util.transform(matrix, [['t', -tmpPoint.x, -tmpPoint.y],['r', pos.angle],['t', tmpPoint.x, tmpPoint.y],])return {x: tmpPoint.x,y: tmpPoint.y,matrix,}},{repeat: true,duration: time < 1000 ? 1000 : time,easing: 'easeLinear',delay: 0,})return shape},})//从右往左的边G6.registerEdge('hvh4', {draw(cfg, group) {const startPoint = cfg.startPointconst endPoint = cfg.endPointconst shape = group.addShape('path', {attrs: {stroke: '#8993AA',path: [['M', startPoint.x, startPoint.y],['L', startPoint.x - 20, startPoint.y], // 三分之一处['L',startPoint.x - 20,(1 / 3) * startPoint.y + (2 / 3) * endPoint.y,], // 三分之二处['L', endPoint.x, (1 / 3) * startPoint.y + (2 / 3) * endPoint.y], // 三分之二处['L', endPoint.x, endPoint.y],],lineWidth: 1,lineDash: cfg.lineDash ? cfg.lineDash : '', // 自定义虚线模式},})// 计算箭头方向const angle = Math.atan2(endPoint.y - startPoint.y,endPoint.x - startPoint.x)// 自定义箭头路径生成方法function getArrowPath(x, y, angle) {const length = 9 // 箭头长度const width = 4 // 箭头宽度// 计算箭头三个点的坐标const x1 = xconst y1 = yconst x2 = x1 - widthconst y2 = y1 - lengthconst x3 = x1 + widthconst y3 = y1 - lengthreturn [['M', x, y], ['L', x2, y2], ['L', x3, y3], ['Z']]}// 在终点绘制自定义箭头group.addShape('path', {attrs: {path: getArrowPath(endPoint.x, endPoint.y, 0),fill: '#8993AA',stroke: '#8993AA',lineWidth: 1,},})// //在边上画循环点const circle = group.addShape('ellipse', {attrs: {x: cfg.startPoint.x,y: cfg.startPoint.y,fill: 'l(0) 0:rgba(102,212,255,0.7) 1:#1A56FF',rx: 4,ry: 1,shadowColor: '#1A56FF',shadowBlur: 4,shadowOffsetY: 1,},name: 'circle-shape',})const time =(Math.abs(cfg.endPoint.x - cfg.startPoint.x) +Math.abs(cfg.endPoint.y - cfg.startPoint.y)) /0.05circle.show()circle.animate((ratio) => {const tmpPoint = shape.getPoint(ratio)const pos = G6.Util.getLabelPosition(shape, ratio)let matrix = [1, 0, 0, 0, 1, 0, 0, 0, 1]matrix = G6.Util.transform(matrix, [['t', -tmpPoint.x, -tmpPoint.y],['r', pos.angle],['t', tmpPoint.x, tmpPoint.y],])return {x: tmpPoint.x,y: tmpPoint.y,matrix,}},{repeat: true,duration: time,easing: 'easeLinear',delay: 0,})return shape},})//自定义边G6.registerEdge('hvh_custom', {draw(cfg, group) {const startPoint = cfg.startPointconst endPoint = cfg.endPointlet path = []//默认连接起始点和终端,中间的线段通过传入的数组连接path.push(['M', startPoint.x, startPoint.y])for (let i = 0; i < cfg.path.length; i++) {path.push(['L', cfg.path[i][0], cfg.path[i][1]])}path.push(['L', endPoint.x, endPoint.y])const shape = group.addShape('path', {attrs: {stroke: '#8993AA',path: path,lineWidth: 1,lineDash: cfg.lineDash ? cfg.lineDash : '', // 自定义虚线模式},})// 自定义箭头路径生成方法function getArrowPath(x, y, direction) {const length = 9 // 箭头长度const width = 4 // 箭头宽度// 计算箭头三个点的坐标const x1 = xconst y1 = ylet x2, y2, x3, y3if (direction == 'top') {x2 = x1 - widthy2 = y1 + lengthx3 = x1 + widthy3 = y1 + length} else if (direction == 'right') {x2 = x1 - lengthy2 = y1 - widthx3 = x1 - lengthy3 = y1 + width} else if (direction == 'bottom') {x2 = x1 - widthy2 = y1 - lengthx3 = x1 + widthy3 = y1 - length} else {//默认箭头往左x2 = x1 + lengthy2 = y1 - widthx3 = x1 + lengthy3 = y1 + width}return [['M', x, y], ['L', x2, y2], ['L', x3, y3], ['Z']]}// 在终点绘制自定义箭头group.addShape('path', {attrs: {path: getArrowPath(endPoint.x, endPoint.y, cfg.direction),fill: '#8993AA',stroke: '#8993AA',lineWidth: 1,},})// //在边上画循环点const circle = group.addShape('ellipse', {attrs: {x: cfg.startPoint.x,y: cfg.startPoint.y,fill: 'l(0) 0:rgba(102,212,255,0.7) 1:#1A56FF',rx: 4,ry: 1,shadowColor: '#1A56FF',shadowBlur: 4,shadowOffsetY: 1,},name: 'circle-shape',})const time =(Math.abs(cfg.endPoint.x - cfg.startPoint.x) +Math.abs(cfg.endPoint.y - cfg.startPoint.y)) /0.05circle.show()circle.animate((ratio) => {const tmpPoint = shape.getPoint(ratio)const pos = G6.Util.getLabelPosition(shape, ratio)let matrix = [1, 0, 0, 0, 1, 0, 0, 0, 1]matrix = G6.Util.transform(matrix, [['t', -tmpPoint.x, -tmpPoint.y],['r', pos.angle],['t', tmpPoint.x, tmpPoint.y],])return {x: tmpPoint.x,y: tmpPoint.y,matrix,}},{repeat: true,duration: time,easing: 'easeLinear',delay: 0,})// 计算边的中点let midX = (startPoint.x + endPoint.x) / 2let midY = (startPoint.y + endPoint.y) / 2//自定义边传入的起始点及结束点if (cfg.labelCfg && cfg.labelCfg.startPoint && cfg.labelCfg.endPoint) {midX = (cfg.labelCfg.startPoint.x + cfg.labelCfg.endPoint.x) / 2midY = (cfg.labelCfg.startPoint.y + cfg.labelCfg.endPoint.y) / 2}// 计算边的角度(用于文本旋转)const angle2 = Math.atan2(endPoint.y - startPoint.y,endPoint.x - startPoint.x)// 添加上方文本if (cfg.label) {group.addShape('text', {attrs: {x: midX,y: midY - 6, // 上方偏移text: cfg.label,fill: cfg.labelCfg?.style?.fill || '#333',fontSize: cfg.labelCfg?.style?.fontSize || 12,textAlign: 'center',textBaseline: 'bottom',rotate: angle2,},})}// 添加下方文本if (cfg.subLabel) {group.addShape('text', {attrs: {x: midX,y: midY + 6, // 下方偏移text: cfg.subLabel,fill: cfg.subLabelCfg?.style?.fill || '#666',fontSize: cfg.subLabelCfg?.style?.fontSize || 12,textAlign: 'center',textBaseline: 'top',rotate: angle2,},})}return shape},})const graph = new G6.Graph({container: 'mountNode',width: 1380,height: mapHeight.value,minZoom: 0.4,maxZoom: 1,modes: {default: ['click-select',{ type: 'drag-canvas', enableOptimize: true },{type: 'zoom-canvas',optimizeZoom: true,shouldUpdate: () => false,onWheel: (e) => {e.preventDefault()const currentZoom = graph.getZoom()let ratio =e.wheelDelta > 0? Math.min(currentZoom + 0.1, 1): Math.max(currentZoom - 0.1, 0.4)graph.zoomTo(ratio, {x: graph.getWidth() / 2,y: graph.getHeight() / 2,})if (e.wheelDelta > 0 && ratio >= graph.getMaxZoom()) {graph.moveTo(0, 0)}},},],},// defaultNode: {// type: 'split-rect',// size: [120, 80],// style: { fill: '#FBEAEC', stroke: '#F8DDE0' },// label: '',// },defaultNode: {type: 'product-rect',size: [120, 80],style: { fill: '#FBEAEC', stroke: '#F8DDE0' },label: '',},defaultEdge: {type: 'hvh',zIndex: 2,},})graph.data({edges: edges.value,nodes: nodes.value,})graph.render()nextTick(() => {const edgeGroup = graph.get('edgeGroup')edgeGroup.toFront()graph.paint()})// 提取公共方法function resetNodeStates() {graph.getNodes().forEach((node) => {if (node.getStates().includes('highlight')) {node.clearStates('highlight')}})}function handleNodeClick(evt) {console.log('handleNodeClick')const { item } = evtconst model = item.getModel()if (item._cfg.currentShape === 'split-rect' && !item._cfg.model.noClick) {resetNodeStates()item.setState('highlight', true)if (item._cfg.model?.breedCode) {emit('breed-select', item._cfg.model.breedCode)}}}function handleNodeHover(ev, state) {const { item } = evif (['split-rect', 'breed-rect', 'ratio-rect', 'word-rect'].includes(item._cfg.currentShape)) {graph.setItemState(item, 'hover', state)}}graph.on('node:click', handleNodeClick)graph.on('node:mouseenter', (ev) => {graph.setAutoPaint(false)handleNodeHover(ev, true)graph.paint()graph.setAutoPaint(true)})graph.on('node:mouseleave', (ev) => {handleNodeHover(ev, false)})let startX = 0let startY = 0graph.on('node:mousedown', (e) => {if (e.item._cfg.currentShape === 'block-rect') {isDragging.value = truestartX = e.canvasXstartY = e.canvasY}})graph.on('node:mousemove', (e) => {if (isDragging.value) {const dx = e.canvasX - startXconst dy = e.canvasY - startYgraph.translate(dx, dy, false, { duration: 500, easing: 'easeLinear' })startX = e.canvasXstartY = e.canvasY}})graph.on('node:mouseup', () => {console.log('node:mouseup')isDragging.value = false//document.removeEventListener('mousemove', initDrag)})graph.on('canvas:mousemove', () => {isDragging.value = false//document.removeEventListener('mousemove', initDrag)})graph.on('canvas:mouseup', () => {isDragging.value = false//document.removeEventListener('mousemove', initDrag)})graph.on('viewportchange', () => {graph.refresh()graph.paint()})//默认选中品种graph.getNodes().forEach((node) => {// console.log('node', node._cfg.model.label)if (node._cfg.model.breedCode == window.breedCode) {node.setState('highlight', true)}})graph2.value = graphnextTick(() => {mapResize()})
}
const mapResize = () => {console.log('mapResize')nextTick(() => {let parentWidth = document.querySelector('.supply-analysis').clientWidthlet width = parentWidthlet autoHeight =((!isBlank.value? mapData[window.breedCode].mapHeight: defaultData.mapHeight) *width) /1426mapHeight.value = autoHeightmapPadding.value =((!isBlank.value? mapData[window.breedCode].mapPadding: defaultData.mapPadding) *width) /1376console.log('缩小比例', width / 1426)let ratio = document.getElementById('mountNode').clientWidth / 1376console.log('ratio', ratio)graph2.value &&graph2.value.zoomTo(ratio, {x: graph2.value.getWidth() / 2,y: graph2.value.getHeight() / 2,})graph2.value && graph2.value.moveTo(0, 0)})
}
//在移动节点过程中有时会丢失鼠标状态,因此通过页面监听鼠标移动事件获取鼠标状态
const initDrag = (e) => {//console.log('initDrag', e)if (e) {if (e.which == 0) {isDragging.value = false}}
}
onMounted(() => {console.log('mapData', mapData)if (!isBlank.value) {//console.log('显示铜产业链')edges.value = mapData[window.breedCode].edgesnodes.value = mapData[window.breedCode].nodesmapHeight.value = mapData[window.breedCode].mapHeightmapPadding.value = mapData[window.breedCode].mapPaddingdesc.value = mapData[window.breedCode].desc} else {edges.value = defaultData.edgesnodes.value = defaultData.nodesmapHeight.value = defaultData.mapHeightmapPadding.value = defaultData.mapPadding}const { menuCode } = route.querymenuCode && loadGraphData(menuCode)//通用模块监听事件proxy.$bus.on('echartResize', mapResize)document.addEventListener('mousemove', initDrag)
})
onBeforeUnmount(() => {proxy.$bus.off('echartResize', mapResize)document.removeEventListener('mousemove', initDrag)
})
</script>
<style lang="less" scoped>
.link-map {padding: 12px;.link-title {font-weight: 600;font-size: 16px;color: #333333;line-height: 24px;text-align: center;margin-bottom: 12px;}.link-desc {font-size: 12px;margin-top: -4px;margin-bottom: 12px;:deep(span:nth-child(1)) {color: #245a9a;}}
}
#mountNode {width: 100%;height: 449px;// border: 1px solid #efefef;position: relative;overflow: hidden;max-width: 1376px;margin: 0 auto;//max-height: 379.299px;
}
</style>