如何在chart.js2中根据斜率是正还是负来更改折线图段的颜色?

llmtgqce  于 2023-04-06  发布在  Chart.js
关注(0)|答案(1)|浏览(142)

我目前正试图使一个股票跟踪图表(我知道它的基本,但我还在学习)在sveltekit.在目前的状态下,我没有问题生成一个基本的图形,其中线都是一种颜色,但我想与一个积极的斜率段是绿色和负斜率是紫色.
到目前为止,我已经尝试了2个实现

  1. function generateGradient(ctx, stockData) {
  2. const gradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
  3. for (let i = 1; i < stockData.length; i++) {
  4. const color = getLineColor(stockData[i - 1], stockData[i]);
  5. const position = i / (stockData.length - 1);
  6. gradient.addColorStop(position, color);
  7. }
  8. return gradient;
  9. }
  10. function initializeChart() {
  11. const ctx = canvas.getContext('2d');
  12. const chartLabels = stockData.map((item) => item.datetime.slice(0, 10));
  13. const chartData = stockData.map((item) => parseFloat(item.close));
  14. // const gradientStroke = generateGradient(ctx, stockData);
  15. var gradientStroke = ctx.createLinearGradient(500, 0, 100, 0);
  16. gradientStroke.addColorStop(0, "#80b6f4");
  17. gradientStroke.addColorStop(1, "#f49080");
  18. chart = new Chart(ctx, {
  19. type: 'line',
  20. data: {
  21. labels: chartLabels,
  22. datasets: [
  23. {
  24. label: 'Stock Price',
  25. data: chartData,
  26. // borderColor: getLineColor(),
  27. borderColor: gradientStroke,
  28. borderWidth: 3, // line width
  29. pointRadius: 2, // point radius
  30. fill: false,
  31. },
  32. ],
  33. },
  34. options: {
  35. responsive: true,
  36. maintainAspectRatio: false,
  37. },
  38. });
  39. }

这会根据线段是正还是负生成不同的梯度停止点,这将导致不稳定的梯度,但它只会导致chart.js中的错误。
我的第二个实现是

  1. function generateSegmentedDatasets(stockData) {
  2. const datasets = [];
  3. for (let i = 1; i < stockData.length; i++) {
  4. const color = getLineColor(stockData[i - 1], stockData[i]);
  5. const data = Array(i - 1).fill(null).concat(stockData[i - 1].close, stockData[i].close).concat(Array(stockData.length - i - 1).fill(null));
  6. datasets.push({
  7. label: `Segment ${i}`,
  8. data,
  9. borderColor: color,
  10. borderWidth: 3,
  11. pointRadius: 2,
  12. fill: false,
  13. tension: 0,
  14. });
  15. }
  16. return datasets;
  17. }
  18. function initializeChart() {
  19. const ctx = canvas.getContext('2d');
  20. const chartLabels = stockData.map((item) => item.datetime.slice(0, 10));
  21. const chartData = generateSegmentedDatasets(stockData);
  22. chart = new Chart(ctx, {
  23. type: 'line',
  24. data: {
  25. labels: chartLabels,
  26. datasets: chartData,
  27. },
  28. options: {
  29. responsive: true,
  30. maintainAspectRatio: false,
  31. },
  32. });
  33. }

理论上,这应该会产生不同颜色的完全不同的线段,但我认为我对chartjs的了解不足以判断这是否是一个可行的解决方案,我只是一次性编写了所有代码,而没有进行测试(再次请对我放松,这是第一次项目)
这两个实现都遵循onmount函数,该函数从我存储在项目目录中的.json中获取数据,以便于使用。
这也是在sveltekit中完成的,它增加了一层额外的复杂性,但我怀疑这不是问题所在。

wsxa1bj1

wsxa1bj11#

Chart.js文档中有一个示例,展示了您希望使用segments完成的操作。
这里的关键是segment的定义(简化后去掉了skipped修饰符,只关注down修饰符):

  1. segment: {
  2. borderColor: ctx => down(ctx, 'rgb(192,75,75)'),
  3. },

及其相应的助手:

  1. const down = (ctx, value) => ctx.p0.parsed.y > ctx.p1.parsed.y ? value : undefined;

对于数据集中的每个线段[p0, p1]down助手被调用。如果p0 > p1(即线段是倾斜的),那么助手将返回一个颜色值(在代码中是硬设置为rgb(192,75,75)的),并将其影响到borderColor属性中。
否则,helper函数将返回undefined,并且片段(倾斜 * 向上 *)将默认为其默认配置(在上面链接的示例中,为borderColor: 'rgb(75, 192, 192)')。
为了将所有这些放在Svelte中,我们需要做的就是声明一个canvas元素来保存我们的图表,使用bind:this获取对它的引用,并在onMount()中创建图表,以确保画布已经挂载并且其引用可用:

  1. <script>
  2. import { onMount } from 'svelte';
  3. import Chart from 'chart.js/auto';
  4. let canvas;
  5. const down = (ctx, value) => ctx.p0.parsed.y > ctx.p1.parsed.y ? value : undefined;
  6. const genericOptions = {
  7. fill: false,
  8. interaction: {
  9. intersect: false
  10. },
  11. radius: 0,
  12. };
  13. const config = {
  14. type: 'line',
  15. data: {
  16. labels: ['A', 'B', 'C', 'D', 'E', 'F', 'G'],
  17. datasets: [{
  18. label: 'Price chart',
  19. data: [65, 59, 40, 48, 56, 57, 40],
  20. borderColor: 'rgb(75, 192, 192)',
  21. segment: {
  22. borderColor: ctx => down(ctx, 'rgb(192,75,75)'),
  23. },
  24. }]
  25. },
  26. options: genericOptions
  27. };
  28. onMount(() => {
  29. const chart = new Chart(canvas, config);
  30. });
  31. </script>
  32. <div style="width: 800px;">
  33. <canvas bind:this={canvas}></canvas>
  34. </div>

Demo REPL

展开查看全部

相关问题