简体   繁体   中英

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

I have a ScalaFX LineChart whose XAxis is time. The data is dynamic, being updated in an AnimationTimer . As time progresses the plot moves to the right but the plot always starts at 0, so the visible domain increases, compressing the data points.

在此处输入图像描述

Here is the 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()
  }
}

How do I update the lower/upper bounds of the XAxis in the AnimationTimer update? I tried setting the XAxis.lower/upperBound values during the animation update but it has no effect. I have tried other things to no avail. There are JavaFX solutions I've seen but I can't translate it to ScalaFX because there is not a one-to-one mapping of types.

You can specify an explicit lower bound in a few ways, but all require (to the best of my knowledge) manually also setting an upper bound and tick unit, and disabling auto-ranging:

  1. By specifying the lower & upper bounds, and tick unit, as fixed values, in the NumberAxis constructor for the X-axis . Axes created in this way are automatically not auto-ranging.
  2. By setting the lowerBound , upperBound and tickUnit properties of the X-axis NumberAxis to fixed values. This also requires setting the X-axis 's autoRanging = false .
  3. By binding DoubleProperty instances to the lowerBound , upperBound and tickUnit properties of the X-axis NumberAxis . This allows the bounds and tick unit to be dynamically adjusted, by changing the value of the associated property. This also requires setting autoRanging = false .

Here's an example of the first option:

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()
  }
}

In this example, I'm combining the second and third options to use properties for the lower & upper bounds, with a fixed tick unit.

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()
  }
}

Let me know if this does the trick for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM