2013-08-02 3 views
5

Используя диаграммы JavaFX, мне нужно инвертировать ось y диаграммы с разбивкой по областям, чтобы положительный ноль находился сверху, а положительные числа работали вниз по оси y. Ниже приведен макет того, что я пытаюсь достичь.Диаграмма с инвертированной осью y

Inverted Y-Axis with positive numbers

Что лучше (читайте: кратчайшее время разработки и высокое кодовое повторное использование) способ достижения этой цели в JavaFX?

UPDATE

Преобразование данных в отрицательных чисел не вариант. Я ищу ответы, которые будут работать с положительными цифрами, «нетронутыми».

ответ

2

Вы можете использовать правильную ось с отрицательными значениями, но добавьте TickLabelFormatter, который будет пропускать знак минус.

final NumberAxis yAxis = new NumberAxis(-25, 0, 5); 

    yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) { 
     @Override 
     public String toString(Number value) { 
      // note we are printing minus value 
      return String.format("%7.1f", -value.doubleValue()); 
     } 
    }); 

    series1.getData().add(new XYChart.Data("Jan", -1)); 
    series1.getData().add(new XYChart.Data("Feb", -5)); 
    series1.getData().add(new XYChart.Data("Mar", -20)); 
+0

Вы предлагаете преобразовать все мои данные в отрицательные числа, прежде чем использовать их в диаграммах? – mawcsco

+0

есть. Разумеется, это не лучший способ, но гораздо быстрее, чем расширение графика с функциями инверсии. Чтобы избежать прямого обновления данных, вы можете либо расширить класс XYChart.Data' с помощью логики инверсии, либо ввести метод утилиты, который добавит инвертированные числа в диаграмму. –

0

Не простой вариант, чтобы включить inverse() операцию по осям. Без исправления классов JRE это довольно сложно.

Некоторые советы о том, как подойти к этому:

1) расширить ValueAxis или оси (NumberAxis является окончательным, к сожалению)

2) добавить логическое поле и inverse() метод к классу оси

public void inverse() { 
    inversed = !inversed; // boolean property 
    invalidateRange(); 
    requestAxisLayout(); 
} 

3) если вы увеличиваете ValueAxis - вам нужно будет компенсировать смещение, применяемое суперклассом (и перехватить код, где изменяется размер оси)

@Override 
public Long getValueForDisplay(double displayPosition) { 
    if (inversed) 
     return super.getValueForDisplay(offset - displayPosition); 
    else 
     return super.getValueForDisplay(displayPosition); 
} 

@Override 
public double getDisplayPosition(Long value) { 
    if (inversed) 
     return offset - super.getDisplayPosition(value); 
    else 
     return super.getDisplayPosition(value); 
} 

4) (самая уродливая часть), спрятанные этикетки, подавленные классом Axis - исходная реализация зависит от порядка тиков по умолчанию. Я не нашел другого способа, который мог бы разблокировать его через отражение. Так что это очень хрупкое.

@Override 
protected void layoutChildren() { 
    final Side side = getSide(); 
    boolean isHorisontal = null == side || side.isHorizontal(); 
    this.offset = isHorisontal ? getWidth() : getHeight(); 
    super.layoutChildren(); 
    if (inversed) { 
     double prevEnd = isHorisontal ? offset + getTickLabelGap() : 0; 
     for (TickMark m : getTickMarks()) { 
      double position = m.getPosition(); 
      try { 
       final Text textNode = (Text) textNodeField.get(m); 
       final Bounds bounds = textNode.getLayoutBounds(); 
       if (0 <= position && position <= offset) 
        if (isHorisontal) { 
         textNode.setVisible(position < prevEnd); 
         prevEnd = position - (bounds.getWidth() + getTickLabelGap()); 
        } else { 
         textNode.setVisible(position > prevEnd); 
         prevEnd = position + (bounds.getHeight() + getTickLabelGap()); 
        } 
      } catch (IllegalAccessException ignored) { 
      } 
     } 
    } 
} 

Ось Y инвертируется в этом примере this is how it looks like

0

использовать свойства LowerBound и UpperBound оси. Нижняя граница должна быть выше, чем верхняя. Вот как вы можете это сделать, используя fxml:

<?xml version="1.0" encoding="UTF-8"?> 

<?import javafx.scene.*?> 
<?import javafx.scene.control.*?> 
<?import javafx.scene.layout.*?> 

<HBox   
    prefHeight="600.0" 
    prefWidth="800.0" 
    xmlns:fx="http://javafx.com/fxml/1">  

    <javafx.scene.chart.LineChart 
     fx:id="chart" > 
     <xAxis > 
      <javafx.scene.chart.NumberAxis 
       label="X Axis" 
       lowerBound="0.01" 
       upperBound="100" 
       tickUnit="10" 
       autoRanging="false" /> 
     </xAxis> 
     <yAxis> 
      <javafx.scene.chart.NumberAxis 
        label="Y Axis" 
        lowerBound="100" 
        upperBound="0.001" 
        tickUnit="10" 
        autoRanging="false" 
       /> 
     </yAxis> 
    </javafx.scene.chart.LineChart>    
</Hbox> 
Смежные вопросы