Как изменить нижнюю/верхнюю границы LineChart XAxis в 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()
  }
}

Как обновить нижнюю/верхнюю границы XAxis в обновлении AnimationTimer? Я пытался установить значения XAxis.lower/upperBound во время обновления анимации, но это не дало никакого эффекта. Я пробовал другие вещи безрезультатно. Есть решения JavaFX, которые я видел, но я не могу перевести их на ScalaFX, потому что нет однозначного сопоставления типов.


person user1332148    schedule 12.05.2020    source источник
comment
Установка xAxis.forceZeroInRange = false дает желаемый эффект, но я не думаю, что это ответ, потому что я хочу знать, как установить верхние/нижние границы по осям и обновить их во время анимации.   -  person user1332148    schedule 12.05.2020


Ответы (1)


Вы можете указать явную нижнюю границу несколькими способами, но все они требуют (насколько мне известно) вручную также установить верхнюю границу и тиковую единицу, а также отключить автоматический выбор диапазона:

  1. Указав нижнюю и верхнюю границы и единицу деления в качестве фиксированных значений в конструкторе NumberAxis для оси X. Оси, созданные таким образом, автоматически не выбирают диапазон.
  2. Установив для свойств lowerBound, upperBound и tickUnit ось X NumberAxis фиксированные значения. Для этого также необходимо установить значение autoRanging = false для оси X.
  3. Путем привязки экземпляров DoubleProperty к свойствам lowerBound, upperBound и tickUnit оси X 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()
  }
}

Дайте мне знать, если это поможет вам.

person Mike Allen    schedule 12.05.2020
comment
Первый пример не прокручивает XAxis для меня, но второй пример делает именно то, что я хочу. Благодарю вас! - person user1332148; 13.05.2020