使用鼠标绘制平移图 - Jfreechart

问题描述 投票:0回答:4

我们可以在 JfreeChart 中将平移功能实现为鼠标拖动事件吗?现在,我按 CTRL 并拖动鼠标来平移图表。我想通过拖动鼠标来实现平移功能。这可能吗?

java jfreechart
4个回答
2
投票

使用当前的 JFreeChart API 显然不可能更改修饰键,如here所述(但它正在管道中)。

但是,可以通过编程方式平移图表,因此您可以尝试以下操作:

  • MouseMotionListener
    添加到您的
    ChartPanel
    以跟踪
    mouseDragged()
    事件。
  • 根据这些事件,计算图表所需的移动。
  • 直接调用
    XYPlot.panDomainAxes()
    XYPlot.panRangeAxis()
    (API这里)。

ChartPanel
源代码中获取灵感:

/** 
 * Temporary storage for the width and height of the chart 
 * drawing area during panning.
 */
private double panW, panH;

/** The last mouse position during panning. */
private Point panLast;

/**
 * The mask for mouse events to trigger panning.
 *
 * @since 1.0.13
 */
private int panMask = InputEvent.CTRL_MASK;

...

/**
 * Handles a 'mouse pressed' event.
 * <P>
 * This event is the popup trigger on Unix/Linux.  For Windows, the popup
 * trigger is the 'mouse released' event.
 *
 * @param e  The mouse event.
 */
@Override
public void mousePressed(MouseEvent e) {
    if (this.chart == null) {
        return;
    }
    Plot plot = this.chart.getPlot();
    int mods = e.getModifiers();
    if ((mods & this.panMask) == this.panMask) {
        // can we pan this plot?
        if (plot instanceof Pannable) {
            Pannable pannable = (Pannable) plot;
            if (pannable.isDomainPannable() || pannable.isRangePannable()) {
                Rectangle2D screenDataArea = getScreenDataArea(e.getX(),
                        e.getY());
                if (screenDataArea != null && screenDataArea.contains(
                        e.getPoint())) {
                    this.panW = screenDataArea.getWidth();
                    this.panH = screenDataArea.getHeight();
                    this.panLast = e.getPoint();
                    setCursor(Cursor.getPredefinedCursor(
                            Cursor.MOVE_CURSOR));
                }
            }
            // the actual panning occurs later in the mouseDragged() 
            // method
        }
    }
    else if (this.zoomRectangle == null) {
        ...
    }
}

...

/**
 * Handles a 'mouse dragged' event.
 *
 * @param e  the mouse event.
 */
@Override
public void mouseDragged(MouseEvent e) {

    // if the popup menu has already been triggered, then ignore dragging...
    if (this.popup != null && this.popup.isShowing()) {
        return;
    }

    // handle panning if we have a start point
    if (this.panLast != null) {
        double dx = e.getX() - this.panLast.getX();
        double dy = e.getY() - this.panLast.getY();
        if (dx == 0.0 && dy == 0.0) {
            return;
        }
        double wPercent = -dx / this.panW;
        double hPercent = dy / this.panH;
        boolean old = this.chart.getPlot().isNotify();
        this.chart.getPlot().setNotify(false);
        Pannable p = (Pannable) this.chart.getPlot();
        if (p.getOrientation() == PlotOrientation.VERTICAL) {
            p.panDomainAxes(wPercent, this.info.getPlotInfo(),
                    this.panLast);
            p.panRangeAxes(hPercent, this.info.getPlotInfo(),
                    this.panLast);
        }
        else {
            p.panDomainAxes(hPercent, this.info.getPlotInfo(),
                    this.panLast);
            p.panRangeAxes(wPercent, this.info.getPlotInfo(),
                    this.panLast);
        }
        this.panLast = e.getPoint();
        this.chart.getPlot().setNotify(old);
        return;
    }

    ...

}

...

/**
 * Handles a 'mouse released' event.  On Windows, we need to check if this
 * is a popup trigger, but only if we haven't already been tracking a zoom
 * rectangle.
 *
 * @param e  information about the event.
 */
@Override
public void mouseReleased(MouseEvent e) {

    // if we've been panning, we need to reset now that the mouse is 
    // released...
    if (this.panLast != null) {
        this.panLast = null;
        setCursor(Cursor.getDefaultCursor());
    }

    ...

}

编辑:注意到当前API的唯一问题是

panMask
是私有的,为什么不尝试用反射来破解该字段:

Field mask = ChartPanel.class.getDeclaredField("panMask");
mask.setAccessible(true);
mask.set(yourChartPanel, Integer.valueOf(0)); // The "0" mask is equivalent to no mask. You could also set a different modifier.

2
投票

新版本仍然没有提供解决方案,所以我把对我来说完美无缺的东西,当你滚动时它也会自动缩放范围轴:

    ChartPanel panel = new ChartPanel(chart);
    panel.setMouseZoomable(false);
    panel.setMouseWheelEnabled(true);
    panel.setDomainZoomable(true);
    panel.setRangeZoomable(false);
    panel.setPreferredSize(new Dimension(1680, 1100));
    panel.setZoomTriggerDistance(Integer.MAX_VALUE);
    panel.setFillZoomRectangle(false);
    panel.setZoomOutlinePaint(new Color(0f, 0f, 0f, 0f));
    panel.setZoomAroundAnchor(true);
    try {
        Field mask = ChartPanel.class.getDeclaredField("panMask");
        mask.setAccessible(true);
        mask.set(panel, 0);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    panel.addMouseWheelListener(arg0 -> panel.restoreAutoRangeBounds());

现在 JFreeChart 的行为就像任何其他专业图表软件一样。


0
投票

这是我的解决方案。

问候 TA

 ChartPanel cp = new ChartPanel(chart)
  {
     /**
      * A hack to change the zoom and panning function.
      * With this override we can pan around by dragging.
      * If SHIFT is pressed we get the zoom rectangle.
      * @param e
      */
     @Override
     public void mousePressed(MouseEvent e)
     {
        int mods = e.getModifiers();

        int panMask = MouseEvent.BUTTON1_MASK;

        if (mods == MouseEvent.BUTTON1_MASK+MouseEvent.SHIFT_MASK)
        {
           panMask = 255; //The pan test will match nothing and the zoom rectangle will be activated.
        }

        try
        {
           Field mask = ChartPanel.class.getDeclaredField("panMask");
           mask.setAccessible(true);
           mask.set(this, panMask);

        }
        catch (Exception ex)
        {
           ex.printStackTrace();
        }

        super.mousePressed(e);
     }
  };

0
投票

受之前答案的启发,我制作了以下重写方法,在输入原始方法之前替换鼠标事件值(Jfreechart 版本 1.5.4)

    ChartPanel panel = new ChartPanel(chart) {

        // for MacOSX we can't use the CTRL key for mouse drags, see:
        // http://developer.apple.com/qa/qa2004/qa1362.html
        int panMask1 = System.getProperty("os.name").toLowerCase().startsWith("mac os x") ? InputEvent.ALT_MASK : InputEvent.CTRL_MASK;

        @Override
        public void mousePressed(MouseEvent e) {
            int mods = e.getModifiers();

            if ((mods & panMask1) == panMask1)
                mods -= panMask1;
            else
                mods += panMask1;

            MouseEvent e2 = new MouseEvent((Component) e.getSource(), e.getID(), e.getWhen(), mods, e.getX(),
                    e.getY(), e.getClickCount(), e.isPopupTrigger());

            super.mousePressed(e2);
        }

    };
© www.soinside.com 2019 - 2024. All rights reserved.