antv/g6 圖譜封裝配置(二)

繼上次實現圖譜后,后續發現如果要繼續加入不同樣式的圖譜實現起來太過麻煩,因此考慮將配置項全部提取封裝到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>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/81984.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/81984.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/81984.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從芯片互連到機器人革命:英偉達雙線出擊,NVLink開放生態+GR00T模型定義AI計算新時代

5月19日&#xff0c;在臺灣舉辦的Computex 2025上&#xff0c;英偉達推出新技術“NVLink Fusion”&#xff0c;允許非英偉達CPU和GPU&#xff0c;同英偉達產品以及高速GPU互連技術NVLink結合使用&#xff0c;加速AI芯片連接。新技術的推出旨在保持英偉達在人工智能開發和計算領…

Qt window frame + windowTitle + windowIcon屬性(3)

文章目錄 window frame屬性window frame的概念1. window frame的影響2. 圖片演示3. 代碼演示 API接口widget.cpp&#xff08;測試代碼&#xff09; windowTitle屬性API接口問題 注意點widget.cpp&#xff08;屬性用法&#xff09; windowIcon屬性API接口啥是窗口圖標玩法1. 先…

Git 分支管理:merge、rebase、cherry-pick 的用法與規范

Git 分支管理&#xff1a;merge、rebase、cherry-pick 的用法與規范 在團隊開發和個人項目中&#xff0c;合理管理 Git 分支至關重要。merge、rebase 和 cherry-pick 是最常用的三種分支操作命令。本文將介紹它們的基本用法、適用場景及最佳實踐規范&#xff0c;幫助大家更高效…

VR全景制作方法都有哪些?需要注意什么?

VR全景制作是將線下實景場景轉化為具有沉浸式體驗的全景圖像的相關技術流程。通過圖像處理和軟件拼接等手段及技術&#xff0c;可以制作出VR全景圖。后面&#xff0c;我們科普詳細的VR全景制作方法指南&#xff0c;順便介紹眾趣科技在相關領域提供的支持方案。 選定拍攝地點與準…

計算機系統結構1-3章節 期末背誦內容

Amdahl定律: 加快某部件執行速度所能獲得的系統性能加速比&#xff0c;受限于該部件的執行時間占系統中總執行時間的百分比。 加速比依賴于: 可改進比例&#xff1a;在改進前的系統中&#xff0c;可改進部分的執行時間在總的執行時間中所占的比例。 部件加速比&#xff1a;可改…

JS實現直接下載PDF文件

pdf文件通過a標簽直接下載會打開頁面&#xff0c;所以&#xff0c;請求該文件的blob文件流數據&#xff0c;再通過window.URL.createObjectURL轉成鏈接&#xff0c;就可以直接下載了。 只需要替換url和文件名稱就行&#xff0c;文件名的后綴記得要寫上pdf&#xff0c;不然會變成…

深度解析Pytest中Fixture機制與實戰案例

一、為什么我們需要Fixture&#xff1f; 在某次金融系統重構項目中&#xff0c;我們的測試團隊曾遇到這樣的困境&#xff1a;隨著測試用例增長到500&#xff0c;使用unittest框架編寫的測試代碼出現了嚴重的維護問題——setup方法臃腫不堪&#xff0c;測試數據混亂&#xff0c…

文檔結構化專家:數字化轉型的核心力量

文檔結構化專家:定義、職責與行業應用的全方位解析 一、文檔結構化的定義與核心價值 文檔結構化是將非結構化或半結構化文檔(如文本、圖像、表格)轉換為計算機可處理的規范化數據形式的過程。其核心在于通過語義解析、信息單元劃分和標準化格式(如XML/JSON),實現信息的…

Linux系統管理與編程16番外篇:PXE自動化安裝部署OpenEuler24.03LTS

蘭生幽谷&#xff0c;不為莫服而不芳&#xff1b; 君子行義&#xff0c;不為莫知而止休。 Preboot Execution Environment 本機服務器操作系統&#xff1a;CentOS7.9.2207 目標服務器安裝系統&#xff1a;openEuler-24.03-LTS-SP1-everything-x86_64-dvd.iso 虛擬機&#xff1…

Enhanced RTMP H.265(HEVC)技術規格解析:流媒體協議的新突破

Enhanced RTMP H.265&#xff08;HEVC&#xff09;技術規格解析&#xff1a;流媒體協議的新突破 “每一幀畫面都是時間的映射&#xff0c;壓縮之后的靈魂&#xff0c;依然能栩栩如生。” 隨著流媒體技術的快速發展&#xff0c;視頻編碼標準不斷推陳出新。H.264/AVC雖然已經成為…

Visual Studio Code 改成中文模式(漢化)

1、打開工具軟件&#xff08;雙擊打開&#xff09; 2、軟件左邊圖標點開 3、在搜索框&#xff0c;搜索 chinese 出現的第一個 就是簡體中文 4、點擊第一個簡體中文&#xff0c;右邊會出來基本信息 點擊 install 就可以安裝了&#xff08;記得聯網&#xff09;。 5、安裝完右…

Linux--初識文件系統fd

01. C/系統調用文件操作 C/系統調用文件操作 02. 文件系統(ext2)結構 Linux ext2文件系統&#xff0c;上圖為磁盤文件系統圖&#xff08;內核內存映像肯定有所不同&#xff09;&#xff0c;磁盤是典型的塊設備&#xff0c;硬盤分區被劃分為一個個的block。一個塊的大小(有1MB,…

算法中的數學:歐拉函數

1.相關定義 互質&#xff1a;a與b的最大公約數為1 歐拉函數&#xff1a;在1~n中&#xff0c;與n互質的數的個數就是歐拉函數的值 eg&#xff1a; n1時&#xff0c;歐拉函數的值為1&#xff0c;因為1和1是互質的 n2是&#xff0c;值為2&#xff0c;因為1和2都是互質的 積性函數&…

BaseDao指南

1. BaseDao類 import java.sql.*;/*** 通用的工具類 ,負責連接數據&#xff0c; 執行增刪改查的通用方法*/ public class BaseDao {private Connection connection;private PreparedStatement pstm;private ResultSet rs;/*** 建立數據庫連接** return*/public Boolean getCon…

SpringBoot JAR 啟動原理

文章目錄 版本概述JAR 包結構MANIFEST.MF 描述文件JarLauncherArchive 接口launch 方法Handlers.register() 方法getClassPathUrls 方法createClassLoader 方法 時序圖參考 版本 Java 17SpringBoot 3.2.4 概述 JAR 啟動原理可以簡單理解為“java -jar的啟動原理” SpringBo…

YOLO11解決方案之速度估算探索

概述 Ultralytics提供了一系列的解決方案&#xff0c;利用YOLO11解決現實世界的問題&#xff0c;包括物體計數、模糊處理、熱力圖、安防系統、速度估計、物體追蹤等多個方面的應用。 YOLO速度估算結合物體檢測和跟蹤技術&#xff0c;使用YOLO11 模型檢測每幀中的物體&#xf…

初識C++:模版

本篇博客主要講解C模版的相關內容。 目錄 1.泛型編程 2.函數模板 2.1 函數模版概念 2.2 函數模版格式 2.3 函數模版的原理 2.4 函數模版的實例化 1.隱式實例化&#xff1a;讓編譯器根據實參推演模板參數的實際類型 2. 顯式實例化&#xff1a;在函數名后的<>中指定模…

人工智能100問?第27問:神經網絡與貝葉斯網絡的關系?

神經網絡與貝葉斯網絡是兩種互補的智能模型:神經網絡通過多層非線性變換從數據中學習復雜模式,擅長大規模特征提取和預測,而貝葉斯網絡基于概率推理建模變量間的條件依賴關系,擅長處理不確定性和因果推斷。兩者的融合(如貝葉斯神經網絡)結合了深度學習的表征能力與概率建…

【node.js】入門基礎

個人主頁&#xff1a;Guiat 歸屬專欄&#xff1a;node.js 文章目錄 1. Node.js簡介1.1 Node.js的核心特點1.2 Node.js適用場景 2. 第一個Node.js程序2.1 創建并運行Hello World2.2 創建簡單的HTTP服務器 3. Node.js核心概念3.1 模塊系統3.1.1 創建和導出模塊3.1.2 導入和使用模…

百度飛槳PaddleOCR 3.0開源發布 OCR精度躍升13%

百度飛槳 PaddleOCR 3.0 開源發布 2025 年 5 月 20 日&#xff0c;百度飛槳團隊正式發布了 PaddleOCR 3.0 版本&#xff0c;并將其開源。這一新版本在文字識別精度、多語種支持、手寫體識別以及高精度文檔解析等方面取得了顯著進展&#xff0c;進一步提升了 PaddleOCR 在 OCR …