charts.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. // 融资需求与货币供给 — 图表配置
  2. import { palette as C } from './data'
  3. const tipOpt = {
  4. backgroundColor: 'rgba(12,43,94,.94)',
  5. borderWidth: 0,
  6. textStyle: { color: '#fff', fontSize: 12 },
  7. padding: [8, 12],
  8. extraCssText: 'box-shadow:0 6px 18px rgba(12,43,94,.3);border-radius:6px;',
  9. }
  10. function axisStyle(opts = {}) {
  11. return {
  12. axisLine: { lineStyle: { color: '#E4E9F2' } },
  13. axisTick: { show: false },
  14. axisLabel: { color: C.mut, fontSize: 11 },
  15. splitLine: { lineStyle: { color: '#F2F5FA', type: 'dashed' } },
  16. ...opts,
  17. }
  18. }
  19. const sliceYM = (s) => s.map((x) => String(x[0]).slice(2, 7))
  20. // ============== 图1 社融增速和M2增速 ==============
  21. export function tsfM2LineOption(m2Series, tsfSeries) {
  22. const m2Map = new Map(m2Series.map((x) => [String(x[0]).slice(0, 10), x[1]]))
  23. const tsfMap = new Map(tsfSeries.map((x) => [String(x[0]).slice(0, 10), x[1]]))
  24. const cats = tsfSeries.map((x) => String(x[0]).slice(2, 7))
  25. return {
  26. tooltip: { ...tipOpt, trigger: 'axis' },
  27. legend: {
  28. data: ['社融存量同比', 'M2 同比'],
  29. top: 6, textStyle: { color: C.mut, fontSize: 11 }, itemWidth: 14, itemHeight: 8,
  30. },
  31. grid: { top: 32, left: 46, right: 18, bottom: 28 },
  32. xAxis: { type: 'category', data: cats, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10, hideOverlap: true } }) },
  33. yAxis: { type: 'value', name: '%', ...axisStyle() },
  34. series: [
  35. {
  36. name: '社融存量同比',
  37. type: 'line', smooth: true, showSymbol: false, symbol: 'circle', symbolSize: 5,
  38. data: tsfSeries.map((x) => x[1]),
  39. lineStyle: { color: C.brandD, width: 2.4 },
  40. itemStyle: { color: C.brandD },
  41. areaStyle: {
  42. type: 'linear', x: 0, y: 0, x2: 0, y2: 1,
  43. colorStops: [{ offset: 0, color: 'rgba(14,58,150,.14)' }, { offset: 1, color: 'rgba(14,58,150,0)' }],
  44. },
  45. markLine: { symbol: ['none', 'none'], data: [{ yAxis: 0, lineStyle: { color: C.faint, type: 'dashed', width: 1 } }], label: { show: false } },
  46. },
  47. {
  48. name: 'M2 同比',
  49. type: 'line', smooth: true, showSymbol: false, symbol: 'circle', symbolSize: 5,
  50. data: cats.map((_, i) => {
  51. const full = tsfSeries[i][0]
  52. return m2Map.get(String(full).slice(0, 10)) ?? null
  53. }),
  54. lineStyle: { color: C.warn, width: 2.2 },
  55. itemStyle: { color: C.warn },
  56. markLine: { symbol: ['none', 'none'], data: [{ yAxis: 0, lineStyle: { color: C.faint, type: 'dashed', width: 1 } }], label: { show: false } },
  57. },
  58. ],
  59. }
  60. }
  61. // ============== 图2 社融分项结构 ==============
  62. const TSF_COLORS = ['#1552D0', '#7A4FCB', '#5B8DEF', '#0E3A96', '#E8912D', '#3DB389', '#E13B3B', '#6B7A96']
  63. const TSF_LEGEND = ['人民币贷款', '外币贷款', '委托贷款', '信托贷款', '未贴现银行承兑汇票', '企业债券融资', '股票融资', '政府债券']
  64. export function tsfStructureOption(d) {
  65. const cats = (d.categories || []).map((x) => String(x).slice(2, 7))
  66. const series = [
  67. { key: 'rmbLoan', name: '人民币贷款' },
  68. { key: 'fxLoan', name: '外币贷款' },
  69. { key: 'wtLoan', name: '委托贷款' },
  70. { key: 'xtxLoan', name: '信托贷款' },
  71. { key: 'wtzbpj', name: '未贴现银行承兑汇票' },
  72. { key: 'corpBond', name: '企业债券融资' },
  73. { key: 'equity', name: '股票融资' },
  74. { key: 'govBond', name: '政府债券' },
  75. ]
  76. return {
  77. tooltip: { ...tipOpt, trigger: 'axis', axisPointer: { type: 'shadow' } },
  78. legend: {
  79. data: TSF_LEGEND,
  80. top: 6, type: 'scroll', textStyle: { color: C.mut, fontSize: 11 }, itemWidth: 14, itemHeight: 8,
  81. },
  82. grid: { top: 32, left: 56, right: 18, bottom: 28 },
  83. xAxis: { type: 'category', data: cats, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10, hideOverlap: true } }) },
  84. yAxis: { type: 'value', name: '亿元', ...axisStyle() },
  85. series: series.map((s, idx) => ({
  86. name: s.name, type: 'bar', stack: 'tsf', data: d[s.key] || [],
  87. itemStyle: { color: TSF_COLORS[idx], borderRadius: idx === 0 ? [3, 3, 0, 0] : 0 },
  88. barWidth: 18,
  89. })),
  90. }
  91. }
  92. // ============== 图3 信贷分项结构 ==============
  93. const LOAN_COLORS = ['#1552D0', '#E8912D', '#0E3A96', '#7A4FCB', '#189A65']
  94. const LOAN_LEGEND = ['居民-短贷', '居民-中长贷', '企业-短贷', '企业-中长贷', '企业-票据融资']
  95. export function loanStructureOption(d) {
  96. const cats = (d.categories || []).map((x) => String(x).slice(2, 7))
  97. const series = [
  98. { key: 'hhShort', name: '居民-短贷' },
  99. { key: 'hhMid', name: '居民-中长贷' },
  100. { key: 'corpShort', name: '企业-短贷' },
  101. { key: 'corpMid', name: '企业-中长贷' },
  102. { key: 'bill', name: '企业-票据融资' },
  103. ]
  104. return {
  105. tooltip: { ...tipOpt, trigger: 'axis', axisPointer: { type: 'shadow' } },
  106. legend: {
  107. data: LOAN_LEGEND,
  108. top: 6, type: 'scroll', textStyle: { color: C.mut, fontSize: 11 }, itemWidth: 14, itemHeight: 8,
  109. },
  110. grid: { top: 32, left: 56, right: 18, bottom: 28 },
  111. xAxis: { type: 'category', data: cats, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10, hideOverlap: true } }) },
  112. yAxis: { type: 'value', name: '亿元', ...axisStyle() },
  113. series: series.map((s, idx) => ({
  114. name: s.name, type: 'bar', stack: 'loan', data: d[s.key] || [],
  115. itemStyle: { color: LOAN_COLORS[idx], borderRadius: idx === 0 ? [3, 3, 0, 0] : 0 },
  116. barWidth: 18,
  117. })),
  118. }
  119. }
  120. // ============== 图4 近1年票据融资额 vs 10年国债(双 Y 轴) ==============
  121. export function billVsBond10Option(d) {
  122. const cats = (d.categories || []).map((x) => String(x).slice(2, 7))
  123. return {
  124. tooltip: { ...tipOpt, trigger: 'axis' },
  125. legend: {
  126. data: [
  127. { name: '近1年票据融资额', itemStyle: { color: '#7A4FCB' } },
  128. '10年国债到期收益率',
  129. ],
  130. top: 6, type: 'scroll', textStyle: { color: C.mut, fontSize: 11 }, itemWidth: 14, itemHeight: 8,
  131. },
  132. grid: { top: 32, left: 56, right: 56, bottom: 28 },
  133. xAxis: { type: 'category', data: cats, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10, hideOverlap: true } }) },
  134. yAxis: [
  135. {
  136. type: 'value', name: '亿元', position: 'left',
  137. ...axisStyle({ nameTextStyle: { color: C.mut, fontSize: 10 }, nameGap: 14 }),
  138. },
  139. {
  140. type: 'value', name: '%', position: 'right',
  141. min: 0, max: 5,
  142. ...axisStyle({ nameTextStyle: { color: C.mut, fontSize: 10 }, nameGap: 14 }),
  143. },
  144. ],
  145. series: [
  146. {
  147. name: '近1年票据融资额', type: 'bar',
  148. data: d.bill12m || [],
  149. barWidth: 12,
  150. itemStyle: {
  151. color: (p) => ({
  152. type: 'linear', x: 0, y: 0, x2: 0, y2: 1,
  153. colorStops: [{ offset: 0, color: '#7A4FCB' }, { offset: 1, color: '#5B3DAE' }],
  154. }),
  155. borderRadius: [3, 3, 0, 0],
  156. },
  157. yAxisIndex: 0,
  158. },
  159. {
  160. name: '10年国债到期收益率', type: 'line', smooth: true,
  161. showSymbol: false, symbol: 'circle', symbolSize: 5,
  162. data: d.bond10 || [],
  163. yAxisIndex: 1,
  164. lineStyle: { color: C.warn, width: 2.4 },
  165. itemStyle: { color: C.warn },
  166. markLine: { symbol: ['none', 'none'], data: [{ yAxis: 0, lineStyle: { color: C.faint, type: 'dashed', width: 1 } }], label: { show: false } },
  167. },
  168. ],
  169. }
  170. }
  171. // ============== 图5 M1 同比 vs 10年国债(双 Y 轴) ==============
  172. export function m1VsBond10Option(d) {
  173. const cats = (d.categories || []).map((x) => String(x).slice(2, 7))
  174. return {
  175. tooltip: { ...tipOpt, trigger: 'axis' },
  176. legend: {
  177. data: ['M1 同比', '10年国债到期收益率'],
  178. top: 6, textStyle: { color: C.mut, fontSize: 11 }, itemWidth: 14, itemHeight: 8,
  179. },
  180. grid: { top: 32, left: 46, right: 46, bottom: 28 },
  181. xAxis: { type: 'category', data: cats, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10, hideOverlap: true } }) },
  182. yAxis: [
  183. {
  184. type: 'value', name: '%', position: 'left',
  185. ...axisStyle({ nameTextStyle: { color: C.mut, fontSize: 10 }, nameGap: 14 }),
  186. },
  187. {
  188. type: 'value', name: '%', position: 'right',
  189. min: 0, max: 5,
  190. ...axisStyle({ nameTextStyle: { color: C.mut, fontSize: 10 }, nameGap: 14 }),
  191. },
  192. ],
  193. series: [
  194. {
  195. name: 'M1 同比', type: 'line', smooth: true,
  196. showSymbol: false, symbol: 'circle', symbolSize: 5,
  197. data: d.m1Yoy || [],
  198. lineStyle: { color: C.brandD, width: 2.4 },
  199. itemStyle: { color: C.brandD },
  200. areaStyle: {
  201. type: 'linear', x: 0, y: 0, x2: 0, y2: 1,
  202. colorStops: [{ offset: 0, color: 'rgba(14,58,150,.10)' }, { offset: 1, color: 'rgba(14,58,150,0)' }],
  203. },
  204. yAxisIndex: 0,
  205. markLine: { symbol: ['none', 'none'], data: [{ yAxis: 0, lineStyle: { color: C.faint, type: 'dashed', width: 1 } }], label: { show: false } },
  206. },
  207. {
  208. name: '10年国债到期收益率', type: 'line', smooth: true,
  209. showSymbol: false, symbol: 'circle', symbolSize: 5,
  210. data: d.bond10 || [],
  211. yAxisIndex: 1,
  212. lineStyle: { color: C.warn, width: 2.4 },
  213. itemStyle: { color: C.warn },
  214. markLine: { symbol: ['none', 'none'], data: [{ yAxis: 0, lineStyle: { color: C.faint, type: 'dashed', width: 1 } }], label: { show: false } },
  215. },
  216. ],
  217. }
  218. }
  219. export function latestOf(series) {
  220. if (!series || !series.length) return null
  221. const last = series[series.length - 1]
  222. return { value: last[1], date: last[0] }
  223. }