如何在 ScalaFX 中更改 LineChart XAxis lower/upper 边界?

How to change LineChart XAxis lower/upper bounds in ScalaFX?

我有一个 ScalaFX LineChart,它的 XAxis 是时间。数据是动态的,在 AnimationTimer 内更新。随着时间的推移,绘图向右移动,但绘图始终从 0 开始,因此可见域增加,压缩数据点。

这里是 Stage:

new Stage {
  title = plotTitle
  scene = new Scene(600, 600) {
    val series = new XYChart.Series[Number, Number]()
    series.setName(s"Simple")
    val xAxis = NumberAxis("Time (s)")
    val yAxis = NumberAxis("Amplitude")
    val lineChart = new LineChart(xAxis, yAxis)
    lineChart.setAnimated(false)
    lineChart.getData.add(series)
    lineChart.setCreateSymbols(false)
    root = lineChart

    var index = 0
    val timer = AnimationTimer { time =>
      series.getData.add(XYChart.Data[Number, Number](index, math.cos(index)))
      if (series.getData.size > 100) series.getData.remove(0, series.getData.size() - 100)
      xAxis.lowerBound.value = math.max(index - 100, 0) // this has no effect
      xAxis.upperBound.value = math.max(index, 100) // this has no effect
      index += 1
    }
    timer.start()
  }
}

如何在 AnimationTimer 更新中更新 XAxis 的 lower/upper 边界?我尝试在动画更新期间设置 XAxis.lower/upperBound 值,但没有效果。我尝试过其他方法无济于事。我见过 JavaFX 解决方案,但我无法将其转换为 ScalaFX,因为没有一对一的类型映射。

您可以通过几种方式指定明确的下限,但都需要(据我所知)手动设置上限和刻度单位,并禁用自动调整范围:

  1. 通过在 X 轴NumberAxis 构造函数中将下限和上限以及刻度单位指定为固定值。以这种方式创建的轴自动不会自动调整范围。
  2. 通过将 X 轴 NumberAxislowerBoundupperBoundtickUnit 属性设置为固定值。这也需要设置X轴autoRanging = false.
  3. 通过将 DoubleProperty 实例绑定到 X 轴 lowerBoundupperBoundtickUnit 属性 NumberAxis。这允许通过更改关联的 属性 的值来动态调整边界和刻度单位。这也需要设置autoRanging = false.

这是第一个选项的示例:

new Stage {
  title = plotTitle
  scene = new Scene(600, 600) {
    val series = new XYChart.Series[Number, Number]()
    series.setName(s"Simple")

    // Specify an X-axis with fixed upper & lower bounds, and tick unit
    // (separation of major tick values).
    //
    // Note: This is automatically not an auto-ranging axis.
    val xAxis = NumberAxis("Time (s)", 115.0, 225.0, 25.0)
    val yAxis = NumberAxis("Amplitude")
    val lineChart = new LineChart(xAxis, yAxis)
    lineChart.setAnimated(false)
    lineChart.getData.add(series)
    lineChart.setCreateSymbols(false)
    root = lineChart

    var index = 0
    val timer = AnimationTimer { time =>
      series.getData.add(XYChart.Data[Number, Number](index, math.cos(index)))
      if (series.getData.size > 100) series.getData.remove(0, series.getData.size() - 100)
      index += 1
    }
    timer.start()
  }
}

在这个例子中,我结合了第二个和第三个选项,使用固定刻度单位的下限和上限属性。

new Stage {
  title = plotTitle
  scene = new Scene(600, 600) {
    val series = new XYChart.Series[Number, Number]()
    series.setName(s"Simple")

    // Note: This axis is automatically auto-ranging.
    val xAxis = NumberAxis("Time (s)")
    val yAxis = NumberAxis("Amplitude")

    // Disable auto-ranging of the xAxis.
    xAxis.autoRanging = false

    // Create a double property whose value will be used as the lower bound of the
    // X-axis. If the value of this property is changed, the chart will update
    // accordingly, automatically. Make this 0 initially.
    val xLowBound = DoubleProperty(0.0)

    // Bind this property to the lowerBound of the X-axis
    xAxis.lowerBound <== xLowBound

    // Repeat for the upper bound. 100, initially.
    val xUpBound = DoubleProperty(100.0)
    xAxis.upperBound <== xUpBound

    // Set the tick unit to a fixed value.
    xAxis.tickUnit = 25.0

    val lineChart = new LineChart(xAxis, yAxis)
    lineChart.setAnimated(false)
    lineChart.getData.add(series)
    lineChart.setCreateSymbols(false)
    root = lineChart

    var index = 0
    val timer = AnimationTimer { time =>
      series.getData.add(XYChart.Data[Number, Number](index, math.cos(index)))
      if (series.getData.size > 100) series.getData.remove(0, series.getData.size() - 100)

      // Dynamically update the lower & upper bounds.
      xLowBound.value = math.max(index - 100, 0)
      xUpBound.value = math.max(index, 100)

      index += 1
    }
    timer.start()
  }
}

让我知道这是否适合您。