首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在画布上的每支蜡烛上放置几个符号。

在画布上的每支蜡烛上放置几个符号。
EN

Stack Overflow用户
提问于 2020-10-22 05:17:52
回答 1查看 165关注 0票数 1

创建了一个简单的示例来说明我需要什么。这个系列有50个项目。每个项目都有一个由五个+符号组成的垂直列表。

代码语言:javascript
复制
const data = [...Array(50).keys()];

const container = document.querySelector('d3fc-canvas');
const xScale = d3.scaleLinear().domain([0, data.length - 1]);
const yScale = d3.scaleLinear().domain(fc.extentLinear()(data));

const series = fc
  .seriesCanvasPoint()
  .xScale(xScale)
  .yScale(yScale)
  .crossValue((_, i) => i)
  .mainValue(d => d)
  .size((_, i) => 0)
  .decorate((context, datum) => {

    // Draw 5 symbols above current value

    for (let i = 0; i < 5; i++) {

      const y = yScale.invert(datum + i)

      context.textAlign = 'center';
      context.fillStyle = '#000';
      context.font = '25px Arial';
      context.fillText('+', 0, 0);
      context.translate(0, y);
    }
  });

d3.select(container)
  .on('draw', () => {
    series(data);
  })
  .on('measure', () => {
    const {
      width,
      height
    } = event.detail;
    xScale.range([0, width]);
    yScale.range([height, 0]);

    const ctx = container.querySelector('canvas').getContext('2d');
    series.context(ctx);
  });

container.requestRedraw();
代码语言:javascript
复制
body {
  color: #1b1e23;
  font-size: small;
  font-family: sans-serif;
  height: calc(100vh - 2em);
  margin: 1em;
  display: flex;
}

body>* {
  flex: auto;
}

.domain,
.gridline-y,
.gridline-x,
.annotation-line>line {
  stroke: currentColor;
  stroke-opacity: 0.1;
}
代码语言:javascript
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<script src="https://unpkg.com/d3fc/build/d3fc.js"></script>
<d3fc-canvas use-device-pixel-ratio></d3fc-canvas>

现在,我试图使它与实际的财务图表工作,并将这五个+符号垂直放置在每支蜡烛内。它不起作用,因为我不知道如何正确地将每个+的Y值转换为画布的坐标系。

代码语言:javascript
复制
const stream = fc.randomFinancial().stream();
const data = stream.take(20);
const scaleX = d3.scalePoint();
const scaleY = d3.scaleLinear();
const yExtent = fc.extentLinear().accessors([d => d.high, d => d.low]);
const xExtent = fc.extentLinear().accessors([d => d.date.getTime()]);
const gridlines = fc.annotationCanvasGridline();
const candlestick = fc.seriesCanvasCandlestick()
  .crossValue((o, i) => o.date.getTime())
  .lowValue((o, i) => o.low)
  .highValue((o, i) => o.high)
  .openValue((o, i) => o.open)
  .closeValue((o, i) => o.close);

const points = fc
  .seriesCanvasPoint()
  .crossValue((o, i) => o.date.getTime())
  .mainValue(d => d.close)
  .size((_, i) => 0)
  .decorate((context, datum) => {

    const arrows = getMarks(datum.open, datum.close);

    //context.translate(0, 0);

    // Draw 5 symbols above current value

    for (let i = 0; i < arrows.length; i++) {

      const posCurrent = scaleY.invert(arrows[i])

      //context.translate(0, 15);
      context.translate(0, posCurrent); // move to current arrow's position
      context.textAlign = 'center';
      context.fillStyle = '#000';
      context.font = '25px Arial';
      context.fillText('+', 0, 0);
      context.translate(0, -posCurrent); // reset and go back to start point
    }
  });

const multi = fc
  .seriesCanvasMulti()
  .series([gridlines, candlestick, points]);

const chart = fc
  .chartCartesian(scaleX, scaleY)
  .canvasPlotArea(multi);

function getMarks(open, close) {

  let price = close;

  const arrows = [];
  const gap = Math.abs(close - open) / 5;

  for (let i = 0; i < 5; i++) {
    arrows.push(close > open ? price -= gap : price += gap);
  }

  return arrows;
}

function renderChart() {

  data.push(stream.next());
  data.shift();

  scaleX.domain(data.map(o => o.date.getTime()));
  scaleY.domain(yExtent(data));

  chart
    .xDomain(scaleX.domain())
    .yDomain(scaleY.domain());

  d3.select('#chart')
    .datum(data)
    .call(chart);
}

renderChart();
setInterval(renderChart, 1000);
代码语言:javascript
复制
#chart {
  height: 500px;
}
代码语言:javascript
复制
<script src="https://unpkg.com/d3"></script>
<script src="https://unpkg.com/d3fc"></script>
<div id="chart"></div>

有办法在蜡烛上正确地显示这些标记吗?

有关更多细节和例子,请参考Github。

https://github.com/d3fc/d3fc/issues/1635

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-10-24 10:38:20

首先,scale.invert是指当你有像素坐标,而不是相应的基准值。例如,当您在屏幕上单击时,这是相关的。在这种情况下,它不是适合这项工作的工具。您已经可以访问datum,所以只需调用scaleY(datum.close)即可。

但是,d3fc使用canvas.translate()将零点更改为.mainvalue()。因此,不能简单地使用scaleY(datum.close)来获得关闭值的y坐标。而不是(x, y),您想要画的每一个点都变成(0, y(arrow) - y(d.close))。所以你需要改变逻辑来反映这一点。

需要在使用context.translate()之后进行清理是一个bug的秘诀,避免这样的事情几乎总是更好。

最后,我对您的getMarks函数有一些困惑。如果你想画5个箭头均匀分布在你的酒吧,你需要有一个1/4的杆高的差距。把它想象成街上的树。如果树相隔10英尺,街道有100英尺长,你就会有11棵树,而不是10棵。正因为如此,我画了6个附加的标志,而不是5个,因为否则它看起来有点不平衡。

代码语言:javascript
复制
const stream = fc.randomFinancial().stream();
const data = stream.take(20);
const scaleX = d3.scalePoint();
const scaleY = d3.scaleLinear();
const yExtent = fc.extentLinear().accessors([d => d.high, d => d.low]);
const xExtent = fc.extentLinear().accessors([d => d.date.getTime()]);
const gridlines = fc.annotationCanvasGridline();
const candlestick = fc.seriesCanvasCandlestick()
  .crossValue((o, i) => o.date.getTime())
  .lowValue((o, i) => o.low)
  .highValue((o, i) => o.high)
  .openValue((o, i) => o.open)
  .closeValue((o, i) => o.close);

const points = fc
  .seriesCanvasPoint()
  .crossValue((o, i) => o.date.getTime())
  .mainValue(d => d.close)
  .size((_, i) => 0)
  .decorate((context, datum) => {
    const arrows = getMarks(datum.open, datum.close);
    const top = scaleY(datum.close);

    // We need a little bit of offset, because the "+" is 20 pixels high
    // and we want it in the middle of the point, not above it.
    const offset = 10;

    // Draw 5 symbols above current value
    for (let i = 0; i < arrows.length; i++) {
      context.textAlign = 'center';
      context.fillStyle = '#000';
      context.font = '25px Arial';
      context.fillText('+', 0, scaleY(arrows[i]) - top + offset);
    }
  });

const multi = fc
  .seriesCanvasMulti()
  .series([gridlines, candlestick, points]);

const chart = fc
  .chartCartesian(scaleX, scaleY)
  .canvasPlotArea(multi);

function getMarks(open, close) {

  let price = Math.min(open, close);

  const arrows = [];
  const gap = Math.abs(close - open) / 5;

  for (let i = 0; i < 6; i++) {
    arrows.push(price + i * gap);
  }

  return arrows;
}

function renderChart() {

  data.push(stream.next());
  data.shift();

  scaleX.domain(data.map(o => o.date.getTime()));
  scaleY.domain(yExtent(data));

  chart
    .xDomain(scaleX.domain())
    .yDomain(scaleY.domain());

  d3.select('#chart')
    .datum(data)
    .call(chart);
}

renderChart();
setInterval(renderChart, 1000);
代码语言:javascript
复制
#chart {
  height: 500px;
}
代码语言:javascript
复制
<script src="https://unpkg.com/d3"></script>
<script src="https://unpkg.com/d3fc"></script>
<div id="chart"></div>

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64475739

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档