-2

CandleStick 图表是使用 JavaFx(使用 CSS 和扩展 XYChart 并使用区域和线创建蜡烛)和 JFree 图表库开发的。

但是 Jfree(400 Mb) 中的内存使用量远低于 javafx(2.5Gb)。(使用 JConsole 运行 2 小时后获取数据)

AdvCandleStickChartSample

/**
 * Copyright (c) 2008, 2012 Oracle and/or its affiliates.
 * All rights reserved. Use is subject to license terms.
 */
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.UUID;

import javafx.animation.Animation;
import javafx.animation.FadeTransition;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.chart.Axis;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.util.Duration;
import java.util.*;

/**
 * A custom candlestick chart.
 * 
 * @see javafx.scene.chart.Axis
 * @see javafx.scene.chart.Chart
 * @see javafx.scene.chart.NumberAxis
 * @see javafx.scene.chart.XYChart
 */
@SuppressWarnings("unused")
public class AdvCandleStickChartSample extends Application {

    // DAY, OPEN, CLOSE, HIGH, LOW, AVERAGE
    private static double[][] data = new double[][] {
        { 1, 25, 20, 32, 16, 20 }, { 2, 26, 30, 33, 22, 25 },
        { 3, 30, 38, 40, 20, 32 }, { 4, 24, 30, 34, 22, 30 },
        { 5, 26, 36, 40, 24, 32 }, { 6, 28, 38, 45, 25, 34 },
        { 7, 36, 30, 44, 28, 39 }, { 8, 30, 18, 36, 16, 31 },
        { 9, 40, 50, 52, 36, 41 }, { 10, 30, 34, 38, 28, 36 }
        };

    private static double[][] data1 = new double[][] {
            { 1, 25, 20, 32, 16, 20 }, { 2, 26, 30, 33, 22, 25 },
            { 3, 30, 38, 40, 20, 32 }, { 4, 24, 30, 34, 22, 30 },
            { 5, 26, 36, 40, 24, 32 }, { 6, 28, 38, 45, 25, 34 },
            { 7, 36, 30, 44, 28, 39 }, { 8, 30, 18, 36, 16, 31 },
            { 9, 40, 50, 52, 36, 41 }, { 10, 30, 34, 38, 28, 36 },
            {11, 24, 12, 30, 8, 32.4},
            {12, 28, 40, 46, 25, 31.6},
            {13, 28, 18, 36, 14, 32.6},
            {14, 38, 30, 40, 26, 30.6},
            {15, 28, 33, 40, 28, 30.6},
            {16, 25, 10, 32, 6, 30.1},
            {17, 26, 30, 42, 18, 27.3},
            {18, 20, 18, 30, 10, 21.9},
            {19, 20, 10, 30, 5, 21.9},
            {20, 26, 16, 32, 10, 17.9},
            {21, 38, 40, 44, 32, 18.9},
            {22, 26, 40, 41, 12, 18.9},
            {23, 30, 18, 34, 10, 18.9},
            {24, 12, 23, 26, 12, 18.2},
            {25, 30, 40, 45, 16, 18.9},
            {26, 25, 35, 38, 20, 21.4},
            {27, 24, 12, 30, 8, 19.6},
            {28, 23, 44, 46, 15, 22.2},
            {29, 28, 18, 30, 12, 23},
            {30, 28, 18, 30, 12, 23.2},
            {31, 28, 18, 30, 12, 22}
            };

    private Timeline animation;
    XYChart.Series<String, Number> series1 = new XYChart.Series<String, Number>();
    int iii=11;
    private void init(Stage primaryStage) {
        Group root = new Group();
        primaryStage.setScene(new Scene(root,500,500,Color.GRAY));
        primaryStage
                .getScene()
                .getStylesheets()
                .add(AdvCandleStickChartSample.class.getResource(
                        "ensemble2.css").toExternalForm());
        final CandleStickChart cd=createChart();
         //Button adddata = new Button("Add Data");
          //  adddata.setOnAction(new EventHandler<ActionEvent>() {
             // @Override
             // public void handle(ActionEvent event) {
                  Timeline oneSecondsWonder = new Timeline(new KeyFrame(Duration.millis(100), new EventHandler<ActionEvent>() {

                        @Override
                        public void handle(ActionEvent event) {
                            getdatatoload(cd);
                            //System.out.println("this is called every 5 seconds on UI thread");
                        }
                    }));
                    oneSecondsWonder.setCycleCount(Timeline.INDEFINITE);
                    oneSecondsWonder.play();
             // }
            //});
        root.getChildren().addAll(cd);
    }

    public void getdatatoload(CandleStickChart cd) {
        Random rn=new Random();
        int ran_ind=rn.nextInt(31);

        double[] day=data1[ran_ind];
        SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
        Date date = new Date();
        //for (int i = 0; i <= 10; i += 1) {
            date.setTime(date.getTime() );
            //System.out.println(dateFormat.format(date));
            series1.getData().add(new XYChart.Data<String,Number>(dateFormat.format(date), day[1],new CandleStickExtraValues(day[2],day[3],day[4],day[5])));
    //  }

        //System.out.println("here");
        //series1.getData().add(new XYChart.Data<String, Number>("iii++",day[1],new CandleStickExtraValues(day[2],day[3],day[4],day[5])));
        /*int j=series1.getData().size();
        System.out.println(j);
        Data item = series1.getData().get(j-1);
        cd.dataItemAdded(series1, j, item);
        //cd.getData().add(series1);*/

    }

    @SuppressWarnings("unchecked")
    protected CandleStickChart createChart() {
        final CategoryAxis xAxis = new CategoryAxis();
        //xAxis.setMinorTickCount(0);
        final NumberAxis yAxis = new NumberAxis();
        final CandleStickChart bc = new CandleStickChart(xAxis, yAxis);
        // setup chart
        bc.setTitle("Custom Candle Stick Chart");
        xAxis.setLabel("Day");
        yAxis.setLabel("Price");
        // add starting data
    //XYChart.Series<Number, Number> series = new XYChart.Series<Number, Number>();
        /*
         * Random ran=new Random(); data=new double[100][6]; for(int
         * i=0;i<100;i++) { data[i][0]= i; data[i][1]= ran.nextInt(40) + 1;
         * data[i][2]= ran.nextInt(40) + 1; data[i][3]= ran.nextInt(40) + 20;
         * data[i][4]= ran.nextInt(20) + 10; data[i][5]= (data[i][3] +
         * data[i][4])/2; } for (int i=0; i< 100; i++) { double[] day; day=new
         * double[6]; day[0]=ran.nextInt(40)+1; day[1]=ran.nextInt(40)+1;
         * day[2]=ran.nextInt(40)+1; day[3]=ran.nextInt(40)+1;
         * day[4]=ran.nextInt(40)+1; day[5]=ran.nextInt(40)+1;
         * series.getData().add( new
         * XYChart.Data<Number,Number>(day[0],day[1],new
         * CandleStickExtraValues(day[2],day[3],day[4],day[5])) ); }
         */
        for (int i = 0; i < data.length; i++) {
            double[] day = data[i];
            /*series1.getData().add(
                    new XYChart.Data<String, Number>("day[0]", day[1],
                            new CandleStickExtraValues(day[2], day[3], day[4],
                                    day[5])));*/
        }
        ObservableList<XYChart.Series<String, Number>> data = bc.getData();
        if (data == null) {
            data = FXCollections.observableArrayList(series1);
            bc.setData(data);
        } else {
            bc.getData().add(series1);
        }
        return bc;
    }

    /**
     * A candlestick chart is a style of bar-chart used primarily to describe
     * price movements of a security, derivative, or currency over time.
     * 
     * The Data Y value is used for the opening price and then the close, high
     * and low values are stored in the Data's extra value property using a
     * CandleStickExtraValues object.
     */
    private class CandleStickChart extends XYChart<String, Number> {

        // -------------- CONSTRUCTORS
        // ----------------------------------------------
        /**
         * Construct a new CandleStickChart with the givextraValuePropertyen
         * axis.
         * 
         * @param xAxis
         *            The x axis to use
         * @param yAxis
         *            The y axis to use
         */
        public CandleStickChart(Axis<String> xAxis, Axis<Number> yAxis) {
            super(xAxis, yAxis);
            setAnimated(false);
            xAxis.setAnimated(false);
            yAxis.setAnimated(false);
        }

        /**
         * Construct a new CandleStickChart with the given axis and data.
         * 
         * @param xAxis
         *            The x axis to use
         * @param yAxis
         *            The y axis to use
         * @param data
         *            The data to use, this is the actual list used so any
         *            changes to it will be reflected in the chart
         */

        public CandleStickChart(Axis<String> xAxis, Axis<Number> yAxis,
                ObservableList<Series<String, Number>> data) {
            this(xAxis, yAxis);
            setUserData(data);
        }

        // -------------- METHODS
        // ------------------------------------------------------------------------------------------
        /** Called to update and layout the content for the plot */
        @Override
        protected void layoutPlotChildren() {
            // we have nothing to layout if no data is present
            if (getData() == null) {
                return;
            }
            // update candle positions
            for (int seriesIndex = 0; seriesIndex < getData().size(); seriesIndex++) {
                Series<String, Number> series = getData().get(seriesIndex);
                Iterator<Data<String, Number>> iter = getDisplayedDataIterator(series);
                Path seriesPath = null;
                if (series.getNode() instanceof Path) {
                    seriesPath = (Path) series.getNode();
                    seriesPath.getElements().clear();
                }
                while (iter.hasNext()) {
                    Data<String, Number> item = iter.next();
                    double x = getXAxis().getDisplayPosition(
                            getCurrentDisplayedXValue(item));
                    double y = getYAxis().getDisplayPosition(
                            getCurrentDisplayedYValue(item));
                    Node itemNode = item.getNode();
                    CandleStickExtraValues extra = (CandleStickExtraValues) item
                            .getExtraValue();
                    if (itemNode instanceof Candle && extra != null) {
                        Candle candle = (Candle) itemNode;

                        double close = getYAxis().getDisplayPosition(
                                extra.getClose());
                        double high = getYAxis().getDisplayPosition(
                                extra.getHigh());
                        double low = getYAxis().getDisplayPosition(
                                extra.getLow());
                        // calculate candle width
                        double candleWidth = -1;
                        if (getXAxis() instanceof CategoryAxis) {
                            CategoryAxis xa = (CategoryAxis) getXAxis();
                        //****//candleWidth = xa.getDisplayPosition(xa.getTickLength()) * 0.90; // use 90% width
                                                            // between ticks
                        }
                        // update candle
                        // System.out.format("x = %f y=%f%n",x,y);
                        candle.update(close - y, high - y, low - y, candleWidth);
                        candle.updateTooltip(item.getYValue().doubleValue(),
                                extra.getClose(), extra.getHigh(),
                                extra.getLow());

                        // position the candle
                        candle.setLayoutX(x);
                        candle.setLayoutY(y);
                    }
                    if (seriesPath != null) {
                        if (seriesPath.getElements().isEmpty()) {
                            seriesPath.getElements().add(
                                    new MoveTo(x, getYAxis()
                                            .getDisplayPosition(
                                                    extra.getAverage())));
                        } else {
                            seriesPath.getElements().add(
                                    new LineTo(x, getYAxis()
                                            .getDisplayPosition(
                                                    extra.getAverage())));
                        }
                    }
                }
            }
        }

        @Override
        protected void dataItemChanged(Data<String, Number> item) {
        }

        @Override
        protected void dataItemAdded(Series<String, Number> series,
                int itemIndex, Data<String, Number> item) {
            //System.out.println("DatItemAdded");
            Node candle = createCandle(getData().indexOf(series), item,
                    itemIndex);
            if (shouldAnimate()) {
                candle.setOpacity(0);
                getPlotChildren().add(candle);
                // fade in new candle
                FadeTransition ft = new FadeTransition(Duration.millis(500),
                        candle);
                ft.setToValue(1);
                ft.play();
            } else {
                getPlotChildren().add(candle);
            }
            // always draw average line on top
            /*if (series.getNode() != null) {
                series.getNode().toFront();
            }*/
        }

        @Override
        protected void dataItemRemoved(Data<String, Number> item,
                Series<String, Number> series) {

            final Node candle = item.getNode();
            if (shouldAnimate()) {
                // fade out old candle
                FadeTransition ft = new FadeTransition(Duration.millis(500),
                        candle);
                ft.setToValue(0);
                ft.setOnFinished(new EventHandler<ActionEvent>() {

                    @Override
                    public void handle(ActionEvent actionEvent) {
                        getPlotChildren().remove(candle);
                    }
                });
                ft.play();
            } else {
                getPlotChildren().remove(candle);
            }
        }

        @SuppressWarnings("rawtypes")
        @Override
        protected void seriesAdded(Series<String, Number> series,
                int seriesIndex) {
//          System.out.println("seriesAdded");
            //System.out.println(seriesIndex);
            // called once from setData() function (internal to XYchart) from
            // createChart
            // handle any data already in series

            for (int j = 0; j < series.getData().size(); j++) {
                Data item = series.getData().get(j);
                Node candle = createCandle(seriesIndex, item, j);
                if (shouldAnimate()) {
                    candle.setOpacity(0);
                    getPlotChildren().add(candle);
                    // fade in new candle
                    FadeTransition ft = new FadeTransition(
                            Duration.millis(500), candle);
                    ft.setToValue(1);
                    ft.play();
                } else {
                    getPlotChildren().add(candle);
                }
            }
            // create series path
            Path seriesPath = new Path();
            seriesPath.getStyleClass().setAll("candlestick-average-line",
                    "series" + seriesIndex);
            series.setNode(seriesPath);
            getPlotChildren().add(seriesPath);
        }

        @Override
        protected void seriesRemoved(Series<String, Number> series) {
            // remove all candle nodes
            for (XYChart.Data<String, Number> d : series.getData()) {
                final Node candle = d.getNode();
                if (shouldAnimate()) {
                    // fade out old candle
                    FadeTransition ft = new FadeTransition(
                            Duration.millis(500), candle);
                    ft.setToValue(0);
                    ft.setOnFinished(new EventHandler<ActionEvent>() {

                        @Override
                        public void handle(ActionEvent actionEvent) {
                            getPlotChildren().remove(candle);
                        }
                    });
                    ft.play();
                } else {
                    getPlotChildren().remove(candle);
                }
            }
        }

        /**
         * Create a new Candle node to represent a single data item
         * 
         * @param seriesIndex
         *            The index of the series the data item is in
         * @param item
         *            The data item to create node for
         * @param itemIndex
         *            The index of the data item in the series
         * @return New candle node to represent the give data item
         */
        @SuppressWarnings("rawtypes")
        private Node createCandle(int seriesIndex, final Data item,
                int itemIndex) {
            Node candle = item.getNode();
            // check if candle has already been created
            if (candle instanceof Candle) {
                ((Candle) candle).setSeriesAndDataStyleClasses("series"
                        + seriesIndex, "data" + itemIndex);
            } else {
                candle = new Candle("series" + seriesIndex, "data" + itemIndex);
                item.setNode(candle);
            }
            return candle;
        }

        /**
         * This is called when the range has been invalidated and we need to
         * update it. If the axis are auto ranging then we compile a list of all
         * data that the given axis has to plot and call invalidateRange() on
         * the axis passing it that data.
         */
        @Override
        protected void updateAxisRange() {
            // called once :)
            // For candle stick chart we need to override this method as we need
            // to let the axis know that they need to be able
            // to cover the whole area occupied by the high to low range not
            // just its center data value
            final Axis<String> xa = getXAxis();
            final Axis<Number> ya = getYAxis();
            List<String> xData = null;
            List<Number> yData = null;
            if (xa.isAutoRanging()) {
                xData = new ArrayList<String>();
            }
            if (ya.isAutoRanging()) {
                yData = new ArrayList<Number>();
            }
            if (xData != null || yData != null) {
                for (Series<String, Number> series : getData()) {
                    for (Data<String, Number> data : series.getData()) {
                        if (xData != null) {
                        xData.add(data.getXValue());
                        }
                        if (yData != null) {
                            CandleStickExtraValues extras = (CandleStickExtraValues) data
                                    .getExtraValue();
                            if (extras != null) {
                                yData.add(extras.getHigh());
                                yData.add(extras.getLow());
                            } else {
                                yData.add(data.getYValue());
                            }
                        }
                    }
                }
                if (xData != null) {
                    xa.invalidateRange(xData);
                }
                if (yData != null) {
                    ya.invalidateRange(yData);
                }
            }
        }
/*
        @Override
        protected void dataItemAdded(
                javafx.scene.chart.XYChart.Series<String, Number> series,
                int itemIndex,
                javafx.scene.chart.XYChart.Data<String, Number> item) {
            // TODO Auto-generated method stub

        }

        @Override
        protected void dataItemChanged(
                javafx.scene.chart.XYChart.Data<String, Number> item) {
            // TODO Auto-generated method stub

        }

        @Override
        protected void dataItemRemoved(
                javafx.scene.chart.XYChart.Data<String, Number> item,
                javafx.scene.chart.XYChart.Series<String, Number> series) {
            // TODO Auto-generated method stub

        }

        @Override
        protected void seriesAdded(
                javafx.scene.chart.XYChart.Series<String, Number> series,
                int seriesIndex) {
            // TODO Auto-generated method stub

        }

        @Override
        protected void seriesRemoved(
                javafx.scene.chart.XYChart.Series<String, Number> series) {
            // TODO Auto-generated method stub

        }*/
    }

    /** Data extra values for storing close, high and low. */
    private class CandleStickExtraValues {
        private double close;
        private double high;
        private double low;
        private double average;

        public CandleStickExtraValues(double close, double high, double low,
                double average) {
            this.close = close;
            this.high = high;
            this.low = low;
            this.average = average;
        }

        public double getClose() {
            return close;
        }

        public double getHigh() {
            return high;
        }

        public double getLow() {
            return low;
        }

        public double getAverage() {
            return average;
        }
    }

    /** Candle node used for drawing a candle */
    private class Candle extends Group {
        private Line highLowLine = new Line();
        private Region bar = new Region();
        private String seriesStyleClass;
        private String dataStyleClass;
        private boolean openAboveClose = true;
        private Tooltip tooltip = new Tooltip();

        private Candle(String seriesStyleClass, String dataStyleClass) {
            setAutoSizeChildren(false);
            getChildren().addAll(highLowLine, bar);
            this.seriesStyleClass = seriesStyleClass;
            this.dataStyleClass = dataStyleClass;
            updateStyleClasses();
            tooltip.setGraphic(new TooltipContent());
            Tooltip.install(bar, tooltip);
        }

        public void setSeriesAndDataStyleClasses(String seriesStyleClass,
                String dataStyleClass) {
            this.seriesStyleClass = seriesStyleClass;
            this.dataStyleClass = dataStyleClass;
            updateStyleClasses();
        }

        public void update(double closeOffset, double highOffset,
                double lowOffset, double candleWidth) {
            openAboveClose = closeOffset > 0;
            updateStyleClasses();
            highLowLine.setStartY(highOffset);
            highLowLine.setEndY(lowOffset);
            if (candleWidth == -1) {
                candleWidth = bar.prefWidth(-1);
            }
            if (openAboveClose) {
                bar.resizeRelocate(-candleWidth / 2, 0, candleWidth,
                        closeOffset);
            } else {
                bar.resizeRelocate(-candleWidth / 2, closeOffset, candleWidth,
                        closeOffset * -1);
            }
            // System.out.println(bar.localToScene(bar.getBoundsInLocal()));
        }

        public void updateTooltip(double open, double close, double high,
                double low) {
            TooltipContent tooltipContent = (TooltipContent) tooltip
                    .getGraphic();
            tooltipContent.update(open, close, high, low);
            // tooltip.setText("Open: "+open+"\nClose: "+close+"\nHigh: "+high+"\nLow: "+low);
        }

        private void updateStyleClasses() {
            getStyleClass().setAll("candlestick-candle", seriesStyleClass,
                    dataStyleClass);
            highLowLine.getStyleClass().setAll("candlestick-line",
                    seriesStyleClass, dataStyleClass,
                    openAboveClose ? "open-above-close" : "close-above-open");
            bar.getStyleClass().setAll("candlestick-bar", seriesStyleClass,
                    dataStyleClass,
                    openAboveClose ? "open-above-close" : "close-above-open");
        }
    }

    private class TooltipContent extends GridPane {
        private Label openValue = new Label();
        private Label closeValue = new Label();
        private Label highValue = new Label();
        private Label lowValue = new Label();

        private TooltipContent() {
            Label open = new Label("OPEN:");
            Label close = new Label("CLOSE:");
            Label high = new Label("HIGH:");
            Label low = new Label("LOW:");
            open.getStyleClass().add("candlestick-tooltip-label");
            close.getStyleClass().add("candlestick-tooltip-label");
            high.getStyleClass().add("candlestick-tooltip-label");
            low.getStyleClass().add("candlestick-tooltip-label");
            setConstraints(open, 0, 0);
            setConstraints(openValue, 1, 0);
            setConstraints(close, 0, 1);
            setConstraints(closeValue, 1, 1);
            setConstraints(high, 0, 2);
            setConstraints(highValue, 1, 2);
            setConstraints(low, 0, 3);
            setConstraints(lowValue, 1, 3);
            getChildren().addAll(open, openValue, close, closeValue, high,
                    highValue, low, lowValue);
        }

        public void update(double open, double close, double high, double low) {
            openValue.setText(Double.toString(open));
            closeValue.setText(Double.toString(close));
            highValue.setText(Double.toString(high));
            lowValue.setText(Double.toString(low));
        }
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        init(primaryStage);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

ensemble2.css

/*
 * Copyright (c) 2008, 2012 Oracle and/or its affiliates.
 * All rights reserved. Use is subject to license terms.
 *
 * This file is available and licensed under the following license:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  - Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the distribution.
 *  - Neither the name of Oracle Corporation nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 /*
/* ====== CANDLE STICK CHART =========================================================== */

.candlestick-tooltip-label {
    -fx-font-size: 0.75em;
    -fx-font-weight: bold;
    -fx-text-fill: #666666;
    -fx-padding: 2 5 2 0;
}
.candlestick-average-line {
    -fx-stroke: #106ece;
    -fx-stroke-width: 2px;
}
.candlestick-candle {
    -fx-effect: dropshadow( two-pass-box , rgba(0,0,0,0.4) , 10, 0.0 , 2 , 4 );
}
.candlestick-line {
    -fx-stroke: #666666;
    -fx-stroke-width: 3px;
}
.candlestick-bar {
    -fx-padding: 5;
    -demo-bar-fill: red;
    -fx-background-color: linear-gradient(derive(-demo-bar-fill,-30%), derive(-demo-bar-fill,-40%)),
                          linear-gradient(derive(-demo-bar-fill,100%), derive(-demo-bar-fill, 10%)),
                          linear-gradient(derive(-demo-bar-fill,30%), derive(-demo-bar-fill,-10%));
    -fx-background-insets: 0,1,2;
}
.candlestick-bar.close-above-open {
    -demo-bar-fill: #95ce1b;
}
.candlestick-bar.open-above-close {
    -demo-bar-fill: #ce2700;
}
4

1 回答 1

1

1) JavaFX 图表总是比 JFreeChart 消耗更多的内存,因为图表上的节点是场景图的活动部分。也就是说,散点图中的每个点都是一个节点,可以对输入事件做出反应、进行自定义渲染、执行动画甚至播放视频文件。另一方面,JFreeChart 静态呈现图表。一种或另一种是否对您的应用程序有益取决于用例,但 JavaFX 方法肯定会使用更多内存。

2) 看来,JavaFX 中当前对 CSS 的处理仍然可以使用一些优化。我这个陈述完全基于经验,但至少对于我所有的测试来说,开销都是一致的。

3) 话虽如此,2.5GB 与 400MB 似乎太多了。你能用你的外汇图表代码发布一个小测试示例吗?可能还有其他与 JavaFX 无关的东西。

于 2013-07-07T08:45:12.867 回答