具有工具提示和折线图的D3js 5多折线图?

时间:2020-06-14 22:11:36

标签: javascript d3.js

我在StackOverflow上已经多次看到这个问题。

有很多不同的答案,其中一些我已经尝试过,其他的与我需要的并没有真正的联系。

我有一个多线图,当您将鼠标悬停在图表上时,需要有一个工具提示+圆圈。我在这里here中有一个可行的示例(对不起,我添加数据的可怕方式是在从api传入的真实代码中,格式更好)

那太好了,所有对象都按预期工作,圆,焦点线和工具提示按预期工作。

现在是棘手的部分。
因为我们正在处理给定时间的图形成千上万条记录(有时每隔15分钟要花费数年的时间),所以我们在混合中添加了行简化功能,从而从api中删除了数据。 我们正在使用https://mourner.github.io/simplify-js/删除每一行的数据点。

使用与上述相同的代码,但是使用简化的数据,这就是发生的here,因为在那个时候缺少数据点。

经过几天的黑客攻击,环顾了StackOverflow,最接近图表的工作是here,但是正如您所看到的,圆圈根本不接近直线(并且值,它们使用相同的数据)。

基本上我需要做的是获取X的鼠标点处每条线在Y处的线的计算值

要点是,每隔15分钟仅更改一次值。 我无所适从,到这里去是非常重​​要的,能够使用线路简化功能是非常重要的,因为大多数数据是在移动设备上查看的,或者在互联网连接速度较慢的区域内查看,我们无法找到客户等待10mb的数据下载

请注意:完整的代码位于小提琴链接中,在此处过多发布

初始代码

  mouseMove(item) {
    const mouseX = d3.mouse(item)[0]
    const x0 = this.x.invert(mouseX)
    const line = this.getLine(this.sensors.byTime, x0)

    // update the date reference
    this.tooltip.header.text(formatDate(line.time))

    // update the line values
    this.tooltip.readings.values.text(item => `${line[item.id]}${item.unit}`)

    // update the irrigation value
    if (line.irrigation) {
      this.showTooltipBar('irrigation')
      this.tooltip.irrigation.value.text(`${line.irrigation}mm`)
    } else {
      this.hideTooltipBar('irrigation')
    }

    // update the rainfall value
    if (line.rainfall) {
      this.showTooltipBar('rainfall')
      this.tooltip.rainfall.value.text(`${line.rainfall}mm`)
    } else {
      this.hideTooltipBar('rainfall')
    }

    if (line.rainfall || line.irrigation) {
      this.setTooltipNamePositions()
    }

    // adjust the size of the box
    const boxWidth =
      this.getTooltipBoxWidth() + this.dimensions.tooltip.left + this.dimensions.tooltip.right
    const boxHeight =
      this.getTooltipBoxHeight() + this.dimensions.tooltip.top + this.dimensions.tooltip.bottom
    this.tooltip.background.attr('width', boxWidth).attr('height', boxHeight)

    // move the focus line across the x of the graph
    this.focus.line.attr('transform', `translate(${mouseX}, 0)`)

    // move the circles across the x of the graph
    this.focus.circles.attr('cy', e => this.y(line[e.id])).attr('cx', this.x(line.time))


    // swap the tooltip to the left / right of the line
    if (mouseX > this.dimensions.width - this.dimensions.width / 4) {
      this.tooltip.group.attr(
        'transform',
        `translate(${mouseX - boxWidth - this.dimensions.tooltip.lines.gap}, ${this.dimensions
          .height / 2.5})`,
      )
    } else {
      this.tooltip.group.attr('transform', `translate(${mouseX}, ${this.dimensions.height / 2.5})`)
    }
  }

使用行简化

  mouseMove(item) {
    const mouseX = d3.mouse(item)[0]
    const x0 = this.x.invert(mouseX)
    const line = this.getLine(this.sensors.byTime, x0)

    // update the date reference
    this.tooltip.header.text(formatDate(line.time))

    // update the line values
    this.tooltip.readings.values.text(item => `${line[item.id]}${item.unit}`)

    // update the irrigation value
    if (line.irrigation) {
      this.showTooltipBar('irrigation')
      this.tooltip.irrigation.value.text(`${line.irrigation}mm`)
    } else {
      this.hideTooltipBar('irrigation')
    }

    // update the rainfall value
    if (line.rainfall) {
      this.showTooltipBar('rainfall')
      this.tooltip.rainfall.value.text(`${line.rainfall}mm`)
    } else {
      this.hideTooltipBar('rainfall')
    }

    if (line.rainfall || line.irrigation) {
      this.setTooltipNamePositions()
    }

    // adjust the size of the box
    const boxWidth =
      this.getTooltipBoxWidth() + this.dimensions.tooltip.left + this.dimensions.tooltip.right
    const boxHeight =
      this.getTooltipBoxHeight() + this.dimensions.tooltip.top + this.dimensions.tooltip.bottom
    this.tooltip.background.attr('width', boxWidth).attr('height', boxHeight)

    // move the focus line across the x of the graph
    this.focus.line.attr('transform', `translate(${mouseX}, 0)`)

    // move the circles across the x of the graph
    this.focus.circles.attr('cy', e => this.y(line[e.id])).attr('cx', this.x(line.time))


    // swap the tooltip to the left / right of the line
    if (mouseX > this.dimensions.width - this.dimensions.width / 4) {
      this.tooltip.group.attr(
        'transform',
        `translate(${mouseX - boxWidth - this.dimensions.tooltip.lines.gap}, ${this.dimensions
          .height / 2.5})`,
      )
    } else {
      this.tooltip.group.attr('transform', `translate(${mouseX}, ${this.dimensions.height / 2.5})`)
    }
  }

通过简化行计算值

  mouseMove(item) {
    const mouseX = d3.mouse(item)[0]
    const x0 = this.x.invert(mouseX)
    const line = this.getLine(this.sensors.byTime, x0)
    const per = this.dimensions.width / mouseX
    const values = []

    this.lines.each((d, i, nodes) => {
      const node = nodes[i]
      const lineLength = node.getTotalLength()
      const point = node.getPointAtLength(lineLength / per)
      const value = this.y.invert(point.y)
      values.push({ value: `${value.toFixed(2)}${this.meta.unit}`, y: point.y })
    })

    // update the date reference
    this.tooltip.header.text(formatDate(line.time))

    // update the line values
    this.tooltip.readings.values.text((item, index) => values[index].value)

    // update the irrigation value
    if (line.irrigation) {
      this.showTooltipBar('irrigation')
      this.tooltip.irrigation.value.text(`${line.irrigation}mm`)
    } else {
      this.hideTooltipBar('irrigation')
    }

    // update the rainfall value
    if (line.rainfall) {
      this.showTooltipBar('rainfall')
      this.tooltip.rainfall.value.text(`${line.rainfall}mm`)
    } else {
      this.hideTooltipBar('rainfall')
    }

    if (line.rainfall || line.irrigation) {
      this.setTooltipNamePositions()
    }

    // adjust the size of the box
    const boxWidth =
      this.getTooltipBoxWidth() + this.dimensions.tooltip.left + this.dimensions.tooltip.right
    const boxHeight =
      this.getTooltipBoxHeight() + this.dimensions.tooltip.top + this.dimensions.tooltip.bottom
    this.tooltip.background.attr('width', boxWidth).attr('height', boxHeight)

    // move the focus line across the x of the graph
    this.focus.line.attr('transform', `translate(${mouseX}, 0)`)

    // move the circles across the x of the graph
    this.focus.circles
      .attr('cy', (item, index) => {
        return values[index].y
      })
      .attr('cx', mouseX)

    // swap the tooltip to the left / right of the line
    if (mouseX > this.dimensions.width - this.dimensions.width / 4) {
      this.tooltip.group.attr(
        'transform',
        `translate(${mouseX - boxWidth - this.dimensions.tooltip.lines.gap}, ${this.dimensions
          .height / 2.5})`,
      )
    } else {
      this.tooltip.group.attr('transform', `translate(${mouseX}, ${this.dimensions.height / 2.5})`)
    }
  }

0 个答案:

没有答案