JavaFX Area Chart:在XYChart区域设置鼠标透明度,但不设置它的子数据节点

时间:2014-11-04 19:56:33

标签: charts tooltip mouseevent nodes javafx-8

一直在摸不着头脑,研究这一段时间没有运气。

我有一个javaFX项目,其中我创建了一个包含4组系列的areachart,其中最后一组只有点可见(黑色X):

我还实现了通过突出显示区域深入查看图表的功能。这一切都是通过各种鼠标处理程序来实现的,但实质上它是一个半透明的黄色矩形(突出显示),在拖动鼠标时会重新调整大小:

    private void setMouseHandler() {
final Axis<Date> xAxis = gcChart.getXAxis();
final Axis<Number> yAxis = gcChart.getYAxis();        
final Node chartBackground = gcChart.lookup(".chart-plot-background");
for (Node n: chartBackground.getParent().getChildrenUnmodifiable()) {
    if (n != chartBackground && n != xAxis && n != yAxis && n != highlight) {
    n.setMouseTransparent(true);
    }
}   
chartBackground.setOnMouseEntered(new EventHandler<MouseEvent>() {

    @Override 
    public void handle(MouseEvent mouseEvent) {
    if (mouseEvent.isPrimaryButtonDown()){
        exitedChart = false;
    }
    }

});


//grab the initial values so if dragged we have them
chartBackground.setOnMousePressed(new EventHandler<MouseEvent>() {

    @Override 
    public void handle(MouseEvent mouseEvent) {     

    if (mouseEvent.isPrimaryButtonDown()){
            Bounds chartAreaBounds = yAxis.localToParent(yAxis.getBoundsInParent()); //chartBackground.localToScene(chartBackground.getBoundsInLocal());                                  
            xShift = chartAreaBounds.getMaxX() -10;  //account for Y Axis area on the chart and side tabs
            origX = mouseEvent.getX() + xShift;
            highlight.setVisible(true);
            highlight.setX(origX);
            highlight.setY(chartAreaBounds.getMinY()+xAxis.getHeight());
            highlight.setHeight(chartAreaBounds.getMaxY()-xAxis.getHeight());

            // Don't want to re-render the chart if we are already zoomed out.      
            firstSelDate = xAxis.getValueForDisplay(mouseEvent.getX());
    }
    else{
     // Are we zoomed in?
        if (seriesCache.size() >= 2){
            logger.info("Zooming out of chart");
            Platform.runLater(new Runnable() {

            @Override
            public void run() {
                removeChartFromScene();
                // return to last series in cache
                new Thread(new GenerateDataTask(null, null, true)).start();
            }

            });
            firstSelDate = null;
        }
    }

    }

});

//must enable FullDrag to detect a drag entering into nodes other than the chart ie. highlight
chartBackground.setOnDragDetected(new EventHandler<MouseEvent>() {

    @Override 
    public void handle(MouseEvent mouseEvent) {
    if (mouseEvent.isPrimaryButtonDown()){
        chartBackground.startFullDrag();
    }
    }

});

chartBackground.setOnMouseDragged(new EventHandler<MouseEvent>() {

    @Override 
    public void handle(MouseEvent mouseEvent) {
    if (mouseEvent.isPrimaryButtonDown()){
            //only set drag values if in the bounds of yAxis
            if (!exitedChart){
                double position = mouseEvent.getX() + xShift;
                highlight.setX(origX <= position? origX : position);                    
                highlight.setWidth(origX <= position? position-origX: origX-position);

                // this may be whats causing the slow drag..
                lastSelDate = xAxis.getValueForDisplay(mouseEvent.getX());   
            }
    }
    }

});     
chartBackground.setOnMouseReleased(new EventHandler<MouseEvent>() {

    public void handle(MouseEvent mouseEvent) {     
        //Check if drag was backwards and if so swap dates
        if (lastSelDate!=null && firstSelDate.compareTo(lastSelDate)>0){
            Date tempDate = firstSelDate;
            firstSelDate=lastSelDate;
            lastSelDate=tempDate;
        }
        //mouse has been released so cleanup the highlight
        highlight.setX(0);
        highlight.setWidth(0);
        highlight.setVisible(false);
        //Set both sets of series in the chart to the subset selected
        if (lastSelDate != null && firstSelDate.compareTo(lastSelDate) != 0) {
            logger.info("Zooming into chart");
            removeChartFromScene();
            // show the subset of data
            new Thread(new GenerateDataTask(firstSelDate, lastSelDate, false)).start();

        }
        lastSelDate = null;

    }

});
yAxis.setOnMouseDragEntered(new EventHandler<MouseDragEvent>() {

    @Override 
    public void handle(MouseDragEvent mouseEvent) {
    if (mouseEvent.isPrimaryButtonDown()){
            exitedChart = true;

            //Account for lag in listener when hitting the yAxis - pull highlight rigt to the edge
            highlight.setX(yAxis.getBoundsInParent().getMaxX());
            highlight.setWidth(origX-yAxis.getBoundsInParent().getMaxX());
    }
    }

});

//detect drag if pulled back into highlight area
highlight.setOnMouseDragEntered(new EventHandler<MouseEvent>() {

    @Override 
    public void handle(MouseEvent mouseEvent) {
    if (mouseEvent.isPrimaryButtonDown()){
        exitedChart = false;
    }
    }

});
}

为了让这个高亮显示功能正常运行而不会有太多麻烦,我将图表中的大多数节点设置为对鼠标透明:

    for (Node n: chartBackground.getParent().getChildrenUnmodifiable()) {
    if (n != chartBackground && n != xAxis && n != yAxis && n != highlight) {
    n.setMouseTransparent(true);
    }
}

我的问题是我现在正试图在顶级图表系列(黑色x点)上设置工具提示,但是我能够让它们工作的唯一方法是设置这些节点以及它们的父节点(组)和grandParent(XYChart)不透明。在这样做的过程中,我突破了亮点功能。

我已经尝试过setPickOnBounds,但据我所知,只能控制鼠标是否“看到”给定节点的不可见部分。如果我的理解是正确的,在这种情况下不起作用,因为拖动例程需要忽略系列的可见区域(落到图表背景中)但不忽略黑色Xs(XYChart.Data节点)。

无论如何(没有重写鼠标处理)使鼠标可以看到这组系列而不会让其他所有东西都可见?

1 个答案:

答案 0 :(得分:1)

mouseTranparent属性使“节点(及其所有子节点)对鼠标事件完全透明。”,因此您无法使用此属性来获取所需的行为。

相反,请在图表上尝试setting an event filter,它会根据事件目标有选择地忽略事件。 mouse events的事件过滤器可以查询事件的源和目标,并选择使用事件(忽略它),或者不使用事件(允许节点的默认鼠标处理程序生效) 。

如果您需要帮助查看正在发生的事件,以便您可以决定要使用或通过什么,那么您可以使用ScenicView的事件记录功能。