-1

我正在尝试像这样实施现金流入和流出的时间表:

现金周转

我不知道是否有任何图表类型可能有所帮助。有可能实现这样的图表吗?

4

2 回答 2

2

没有图表类型可以开箱即用地生成所需的图表。但是,可以使用条形图和一些自定义代码来创建它。

插件核心 API提供了不同的钩子,让您可以执行自定义代码。您可以定义一个内联插件,并通过CanvasRenderingContext2D. 我将使用beforeDraw如下可运行代码片段所示的钩子:

function drawVerticalTriangle(ctx, x, y1, y2) {
  ctx.beginPath();
  ctx.moveTo(x, y1);
  ctx.lineTo(x + 6, y2);
  ctx.lineTo(x - 6, y2);
  ctx.fill();
};

function drawRightArrow(ctx, xLeft, xRight, y) {
  ctx.lineWidth = 3;
  ctx.beginPath(); 
  ctx.moveTo(xLeft, y);
  ctx.lineTo(xRight - 5, y);
  ctx.stroke();      
  ctx.beginPath();      
  ctx.moveTo(xRight, y);
  ctx.lineTo(xRight - 10, y + 6);
  ctx.lineTo(xRight - 10, y - 6);
  ctx.fill();
};

function drawTopArrow(ctx, x, yBottom, yTop) {
  ctx.lineWidth = 3;
  ctx.beginPath(); 
  ctx.moveTo(x, yBottom);
  ctx.lineTo(x, yTop - 5);
  ctx.stroke();      
  drawVerticalTriangle(ctx, x, yTop -10, yTop);
};

new Chart('myChart', {
  type: 'bar',
  plugins: [{
    beforeDraw: chart => {      
      let ctx = chart.ctx; 
      let xAxis = chart.scales.x;
      let yAxis = chart.scales.y;
      xAxis.ticks.forEach((v, i) => {       
        let x = xAxis.getPixelForTick(i);      
        let y = yAxis.getPixelForValue(chart.data.datasets[0].data[i]) - 3; 
        ctx.fillStyle = chart.data.datasets[0].borderColor;
        drawVerticalTriangle(ctx, x, y, y + 10);
        y = yAxis.getPixelForValue(chart.data.datasets[1].data[i]) + 3; 
        ctx.fillStyle = chart.data.datasets[1].borderColor;
        drawVerticalTriangle(ctx, x, y, y - 10);
      }); 
      ctx.strokeStyle = '#9999FF';
      ctx.fillStyle = '#9999FF';      
      let y = yAxis.getPixelForValue(0);
      drawRightArrow(ctx, xAxis.left - 5, xAxis.right + 40, y);
      ctx.font = '12px Arial';
      ctx.textAlign = 'right';
      ctx.fillText('PERIOD', xAxis.right + 30, y + 20);
      drawTopArrow(ctx, xAxis.left, yAxis.bottom + 10, yAxis.top - 10);
    }    
  }],
  data: {
    labels: ['1st year', '2nd year', '3rd year', '4th year'],
    datasets: [
      {
        label: 'Cash inflow', 
        data: [560, 590, 520, 620],   
        backgroundColor: '#0F9D58',    
        borderColor: '#0F9D58',
        barThickness: 4
      },
      {
        label: 'Cash outflow', 
        data: [-600, -550, -410, -570],   
        backgroundColor: '#DB4437',    
        borderColor: '#DB4437',
        barThickness: 4        
      }     
    ]
  },
  options: {
    animation: {
      duration: 100      
    },
    layout: {
      padding: {
        right: 40
      }
    },
    scales: {
      y: {
        grid: {  
          display: false,
        }        
      },
      x: {
        stacked: true,
        grid: {
          display: false,
          drawBorder: false
        }   
      }
    }
  }
});
canvas {
  max-width: 400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.0/chart.min.js"></script>
<canvas id="myChart" height="110"></canvas>

于 2021-06-27T11:04:18.837 回答
0

到目前为止我能做的最好的是:

// Import from the chart.js npm module.
import { Chart } from "chart.js"; 

// Get the context of the canvas element in our HTML file.
let ctx = document.querySelector("canvas#chart").getContext("2d"); 

// Create a chart.
var chrt = new Chart(ctx, {
  type: "bar",
  data: {
    labels: ["1st year", "2nd year", "3rd year"],
    datasets: [
      {
        data: [-y1out.value, -y2out.value, -y3out.value]
        , backgroundColor: ["#DB4437", "#DB4437", "#DB4437"]
        , label: 'Cash outflow',
      }
      , {
        data: [y1in.value, y2in.value, y3in.value]
        , backgroundColor: ["#0F9D58", "#0F9D58", "#0F9D58"]
        , label: 'Cash inflow',
      }
    ]
  }
});

// Update chart when user modifies input values
var els = document.getElementsByTagName("input");
for (var i = 0; i < els.length; i++) {
  els[i].addEventListener('input', function() {
    chrt.data.datasets[0].data = [-y1out.value, -y2out.value, -y3out.value]
    chrt.data.datasets[1].data = [y1in.value, y2in.value, y3in.value]
    chrt.update();
  });
}

结果

结果截图

于 2021-06-27T03:54:16.830 回答