ソースを参照

feat(bond/supply-demand): 利率/信用/金融债图表统一单纵坐标尺度

ligb 4 日 前
親
コミット
85bc697008

+ 7 - 8
web-app/src/views/bond/supply-demand/charts.js

@@ -27,22 +27,21 @@ const downGrad = (color) => ({
   colorStops: [{ offset: 0, color: '#A9CBF0' }, { offset: 1, color }],
 })
 
-// 发行量 vs 到期量 + 净融资
-export function issueMatureNetOption(issue, mature) {
+// 发行量 vs 到期量 + 净融资(单纵轴)
+// yMax 用于在多个图之间统一纵坐标尺度
+export function issueMatureNetOption(issue, mature, { yMax = null } = {}) {
   const cats = sliceDate(issue)
   const matMap = new Map(mature.map(([d, v]) => [String(d).slice(2, 7), v]))
   const issVals = issue.map((x) => x[1])
   const matVals = cats.map((d) => matMap.get(d) ?? 0)
   const netVals = issVals.map((v, i) => v - matVals[i])
+  const useMax = yMax == null ? Math.max(0, ...issVals, ...matVals) : yMax
   return {
     tooltip: { ...tipOpt, trigger: 'axis', axisPointer: { type: 'shadow' } },
     legend: { data: ['发行量', '到期量', '净融资'], top: 4, textStyle: { color: C.mut, fontSize: 11 }, itemWidth: 14, itemHeight: 8 },
-    grid: { top: 32, left: 60, right: 60, bottom: 28 },
+    grid: { top: 32, left: 56, right: 16, bottom: 28 },
     xAxis: { type: 'category', data: cats, ...axisStyle({ axisLabel: { color: C.mut, fontSize: 10 } }) },
-    yAxis: [
-      { type: 'value', name: '亿元', ...axisStyle() },
-      { type: 'value', name: '亿元', position: 'right', ...axisStyle() },
-    ],
+    yAxis: { type: 'value', name: '亿元', max: useMax, ...axisStyle() },
     series: [
       {
         name: '发行量', type: 'bar',
@@ -55,7 +54,7 @@ export function issueMatureNetOption(issue, mature) {
         itemStyle: { color: downGrad(C.warn), borderRadius: [2, 2, 0, 0] },
       },
       {
-        name: '净融资', type: 'line', smooth: true, showSymbol: false, yAxisIndex: 1,
+        name: '净融资', type: 'line', smooth: true, showSymbol: false,
         data: netVals,
         lineStyle: { color: C.up, width: 2.2 },
         itemStyle: { color: C.up },

+ 31 - 3
web-app/src/views/bond/supply-demand/index.vue

@@ -423,9 +423,37 @@ function formatDate(d) {
   return String(d).slice(0, 10)
 }
 
-const rateOpt   = computed(() => issueMatureNetOption(rateIssueSeries.value,   rateMatureSeries.value))
-const creditOpt = computed(() => issueMatureNetOption(creditIssueSeries.value, creditMatureSeries.value))
-const finOpt    = computed(() => issueMatureNetOption(finIssueSeries.value,    finMatureSeries.value))
+const unifiedAxis = computed(() => {
+  const pairs = [
+    [rateIssueSeries.value,   rateMatureSeries.value],
+    [creditIssueSeries.value, creditMatureSeries.value],
+    [finIssueSeries.value,    finMatureSeries.value],
+  ]
+  let max = 0
+  for (const [issue, mature] of pairs) {
+    const issVals = issue.map((x) => x[1])
+    if (issVals.length) max = Math.max(max, Math.max(...issVals))
+    if (mature.length) max = Math.max(max, Math.max(...mature.map((x) => x[1])))
+  }
+  return { yMax: ceilNice(max) }
+})
+function ceilNice(v) {
+  if (!v || v <= 0) return null
+  const exp = Math.floor(Math.log10(v))
+  const base = Math.pow(10, exp)
+  const m = v / base
+  let nice
+  if (m <= 1) nice = 1
+  else if (m <= 2) nice = 2
+  else if (m <= 2.5) nice = 2.5
+  else if (m <= 5) nice = 5
+  else nice = 10
+  return nice * base
+}
+
+const rateOpt   = computed(() => issueMatureNetOption(rateIssueSeries.value,   rateMatureSeries.value,   unifiedAxis.value))
+const creditOpt = computed(() => issueMatureNetOption(creditIssueSeries.value, creditMatureSeries.value, unifiedAxis.value))
+const finOpt    = computed(() => issueMatureNetOption(finIssueSeries.value,    finMatureSeries.value,    unifiedAxis.value))
 
 const rateComment = computed(() => {
   if (rateNetLatest.value == null) return '持续观察'