All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.metsci.glimpse.plot.timeline.StackedTimePlot2D Maven / Gradle / Ivy

There is a newer version: 4.0.0
Show newest version
/*
 * Copyright (c) 2012, Metron, Inc.
 * All rights reserved.
 *
 * 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 Metron, Inc. 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 METRON, INC. 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.
 */
package com.metsci.glimpse.plot.timeline;

import static com.metsci.glimpse.plot.stacked.StackedPlot2D.Orientation.HORIZONTAL;
import static com.metsci.glimpse.plot.stacked.StackedPlot2D.Orientation.VERTICAL;
import static com.metsci.glimpse.support.font.FontUtils.getDefaultPlain;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.TimeZone;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;

import com.metsci.glimpse.axis.Axis1D;
import com.metsci.glimpse.axis.listener.mouse.AxisMouseListener;
import com.metsci.glimpse.axis.listener.mouse.AxisMouseListener1D;
import com.metsci.glimpse.axis.painter.NumericXYAxisPainter;
import com.metsci.glimpse.axis.painter.label.AxisLabelHandler;
import com.metsci.glimpse.axis.painter.label.GridAxisLabelHandler;
import com.metsci.glimpse.axis.painter.label.TimeAxisLabelHandler;
import com.metsci.glimpse.axis.tagged.Constraint;
import com.metsci.glimpse.axis.tagged.Tag;
import com.metsci.glimpse.axis.tagged.TaggedAxis1D;
import com.metsci.glimpse.context.GlimpseTargetStack;
import com.metsci.glimpse.event.mouse.GlimpseMouseAllListener;
import com.metsci.glimpse.event.mouse.GlimpseMouseEvent;
import com.metsci.glimpse.event.mouse.GlimpseMouseMotionListener;
import com.metsci.glimpse.layout.GlimpseAxisLayout1D;
import com.metsci.glimpse.layout.GlimpseAxisLayout2D;
import com.metsci.glimpse.layout.GlimpseAxisLayoutX;
import com.metsci.glimpse.layout.GlimpseAxisLayoutY;
import com.metsci.glimpse.layout.GlimpseLayout;
import com.metsci.glimpse.painter.decoration.BackgroundPainter;
import com.metsci.glimpse.painter.decoration.BorderPainter;
import com.metsci.glimpse.painter.decoration.GridPainter;
import com.metsci.glimpse.painter.group.DelegatePainter;
import com.metsci.glimpse.painter.info.SimpleTextPainter;
import com.metsci.glimpse.painter.info.SimpleTextPainter.HorizontalPosition;
import com.metsci.glimpse.painter.info.SimpleTextPainter.VerticalPosition;
import com.metsci.glimpse.painter.info.TooltipPainter;
import com.metsci.glimpse.plot.stacked.PlotInfo;
import com.metsci.glimpse.plot.stacked.StackedPlot2D;
import com.metsci.glimpse.plot.timeline.data.Epoch;
import com.metsci.glimpse.plot.timeline.event.EventPlotInfo;
import com.metsci.glimpse.plot.timeline.event.EventSelectionHandler;
import com.metsci.glimpse.plot.timeline.layout.TimePlotInfo;
import com.metsci.glimpse.plot.timeline.layout.TimePlotInfoImpl;
import com.metsci.glimpse.plot.timeline.layout.TimelineInfo;
import com.metsci.glimpse.plot.timeline.listener.DataAxisMouseListener1D;
import com.metsci.glimpse.plot.timeline.listener.PlotMouseListener;
import com.metsci.glimpse.plot.timeline.listener.TimeAxisMouseListener1D;
import com.metsci.glimpse.plot.timeline.painter.SelectedTimeRegionPainter;
import com.metsci.glimpse.support.atlas.TextureAtlas;
import com.metsci.glimpse.support.font.FontUtils;
import com.metsci.glimpse.util.units.time.Time;
import com.metsci.glimpse.util.units.time.TimeStamp;

/**
 * A {@link StackedPlot2D} which automatically creates a timeline axis at the
 * bottom of the stack and uses a
 * {@link com.metsci.glimpse.axis.tagged.TaggedAxis1D} to define a selected time
 * region.
 *
 * @author ulman
 */
public class StackedTimePlot2D extends StackedPlot2D
{
    public static final String MIN_TIME = "min_time";
    public static final String MAX_TIME = "max_time";
    public static final String CURRENT_TIME = "current_time";

    // tags representing the minimum and maximum bounds of the selected time window
    protected Tag minTag;
    protected Tag maxTag;
    // tag representing the currently selected time
    protected Tag currentTag;

    // epoch encapsulating the absolute time which maps to value 0 on the timeline
    protected Epoch epoch;

    // timeline painters and listeners
    protected AxisMouseListener1D timelineMouseListener;
    protected TooltipPainter tooltipPainter;

    protected PlotInfo selectedLayout;
    protected SelectedTimeRegionPainter selectedTimePainter;

    // default tick/label handler
    protected TimeAxisLabelHandler timeTickHandler;
    protected TimelineInfo defaultTimelineInfo;

    // default settings for TimelineMouseListeners of new plots
    protected boolean allowPanX = true;
    protected boolean allowPanY = true;
    protected boolean allowZoomX = true;
    protected boolean allowZoomY = true;
    protected boolean allowSelectionLock = true;
    protected boolean currentTimeLock;

    // the size of the label layout area in pixels
    protected int labelLayoutSize = 30;
    protected boolean showLabelLayout = false;
    protected boolean showTimeline = true;

    protected TextureAtlas defaultTextureAtlas;

    // the default selection handler for all EventPlotInfo
    // if client code would like individual EventPlotInfo to maintain
    // their own set of selected events, individual SelectionHandlers
    // can be set for each EventPlotInfo
    protected EventSelectionHandler commonSelectionHandler;

    protected List plotMouseListeners;

    public StackedTimePlot2D( )
    {
        this( Orientation.VERTICAL, Epoch.posixEpoch( ) );
    }

    /**
     * Creates a vertical StackedTimePlot2D. The provided epoch determines what
     * absolute timestamp corresponds to value 0.0 on the time Axis1D.
     */
    public StackedTimePlot2D( Epoch epoch )
    {
        this( Orientation.VERTICAL, epoch );
    }

    public StackedTimePlot2D( Orientation orientation )
    {
        this( orientation, Epoch.posixEpoch( ) );
    }

    public StackedTimePlot2D( Orientation orientation, Epoch epoch )
    {
        this( orientation, epoch, new TextureAtlas( ) );
    }

    public StackedTimePlot2D( Orientation orientation, Epoch epoch, TextureAtlas atlas )
    {
        this( orientation, epoch, atlas, null );
    }

    public StackedTimePlot2D( Orientation orientation, Epoch epoch, TaggedAxis1D commonAxis )
    {
        this( orientation, epoch, new TextureAtlas( ), commonAxis );
    }

    /**
     * Creates a StackedTimePlot2D with specified orientation. The provided
     * epoch determines what absolute timestamp corresponds to value 0.0 on the
     * time Axis1D.
     */
    public StackedTimePlot2D( Orientation orientation, Epoch epoch, TextureAtlas atlas, TaggedAxis1D commonAxis )
    {
        super( orientation, commonAxis );

        this.epoch = epoch;
        this.defaultTextureAtlas = atlas;

        this.commonSelectionHandler = new EventSelectionHandler( );

        this.plotMouseListeners = new CopyOnWriteArrayList( );

        this.setBorderSize( 0 );
        this.timeTickHandler = new TimeAxisLabelHandler( TimeZone.getTimeZone( "GMT-0:00" ), epoch );

        this.initializeTimeAxis( );
        this.defaultTimelineInfo = this.createTimeline( );
        this.initializeOverlayPainters( );
    }
    
    public void setTimeAxisLabelHandler( TimeAxisLabelHandler handler )
    {
        this.timeTickHandler = handler;
    }
    
    public TimeAxisLabelHandler getTimeAxisLabelHandler( )
    {
        return this.timeTickHandler;
    }
    
    public TimelineInfo getDefaultTimeline( )
    {
        return this.defaultTimelineInfo;
    }

    public void addPlotMouseListener( PlotMouseListener listener )
    {
        this.plotMouseListeners.add( listener );
    }

    public void removePlotMouseListener( PlotMouseListener listener )
    {
        this.plotMouseListeners.remove( listener );
    }

    /**
     * Returns the common EventSelectionHandler shared between all {@link EventPlotInfo}
     * sub-plots for this StackedTimePlot2D.
     */
    public EventSelectionHandler getEventSelectionHander( )
    {
        return this.commonSelectionHandler;
    }

    public void setShowTimeline( boolean showTimeline )
    {
        this.showTimeline = showTimeline;

        for ( PlotInfo plot : getAllPlots( ) )
        {
            if ( plot instanceof TimelineInfo ) plot.getLayout( ).setVisible( showTimeline );
        }

        if ( this.isAutoValidate( ) ) this.validate( );
    }

    public boolean isShowTimeline( )
    {
        return this.showTimeline;
    }

    @Override
    protected int getOverlayLayoutOffsetX( )
    {
        return orient == VERTICAL ? getLabelSize( ) : 0;
    }

    @Override
    protected int getOverlayLayoutOffsetY2( )
    {
        return orient == VERTICAL ? 0 : getLabelSize( );
    }

    @Override
    public void setPlotSpacing( int size )
    {
        this.plotSpacing = size;

        for ( PlotInfo info : stackedPlots.values( ) )
        {
            // don't automatically change the timeline info plot spacing
            if ( info instanceof TimelineInfo ) continue;

            info.setPlotSpacing( size );
        }

        if ( this.isAutoValidate( ) ) this.validate( );
    }

    /**
     * StackedTimePlot2D provides a GlimpseAxisLayout1D which stretches over
     * all the underlying plots and timeline. By default, it passes through mouse
     * events to the underlying GlimpseLayouts and is used to display the blue
     * time selection interval box.
     * 
     * However, it can be used to perform arbitrary drawing on the timeline which
     * must stretch across multiple plots.
     */
    public GlimpseAxisLayout1D getOverlayLayout( )
    {
        return this.overlayLayout;
    }

    public GlimpseLayout getFullOverlayLayout( )
    {
        return this.fullOverlayLayout;
    }

    public GlimpseAxisLayout1D getUnderlayLayout( )
    {
        return this.underlayLayout;
    }

    public TooltipPainter getTooltipPainter( )
    {
        return this.tooltipPainter;
    }

    /**
     * 

Returns only the TimePlotInfo handles for plotting areas created with * {@link #createTimePlot(String)}.

* * Note, this may not be all the plotting areas for this StackedPlot2D if some * vanilla plots were created using {@link #createPlot(String)}. */ public Collection getAllTimePlots( ) { this.lock.lock( ); try { List list = new LinkedList( ); for ( PlotInfo plot : getAllPlots( ) ) { if ( plot instanceof TimePlotInfo ) list.add( ( TimePlotInfo ) plot ); } return list; } finally { this.lock.unlock( ); } } /** * Returns the timeline handle for the timeline identified via its unique string identifier. * * @param id a timeline unique identifier * @return the TimelineInfo handle */ public TimelineInfo getTimeline( Object id ) { this.lock.lock( ); try { PlotInfo plot = getPlot( id ); if ( plot instanceof TimelineInfo ) { return ( TimelineInfo ) plot; } else { return null; } } finally { this.lock.unlock( ); } } /** * Returns the time plot handle for the plot identified via its unique string identifier. * * @param id a plot unique identifier * @return the TimePlotInfo handle */ public TimePlotInfo getTimePlot( Object id ) { this.lock.lock( ); try { PlotInfo plot = getPlot( id ); if ( plot instanceof TimePlotInfo ) { return ( TimePlotInfo ) plot; } else { return null; } } finally { this.lock.unlock( ); } } /** * Returns the event plot handle for the plot identified via its unique string identifier. * * @param id a plot unique identifier * @return the EventPlotInfo handle */ public EventPlotInfo getEventPlot( Object id ) { this.lock.lock( ); try { PlotInfo plot = getPlot( id ); if ( plot instanceof EventPlotInfo ) { return ( EventPlotInfo ) plot; } else { return null; } } finally { this.lock.unlock( ); } } public void setSelectedPlot( Object id ) { this.setSelectedPlot( getPlot( id ) ); } public void setSelectedPlot( PlotInfo layout ) { this.selectedLayout = layout; } public PlotInfo getSelectedPlot( ) { return this.selectedLayout; } public void setTimeAxisMouseListener( AxisMouseListener1D listener ) { this.lock.lock( ); try { if ( this.timelineMouseListener != null ) { this.underlayLayout.removeGlimpseMouseAllListener( this.timelineMouseListener ); } if ( listener != null ) { this.underlayLayout.addGlimpseMouseAllListener( listener ); } this.timelineMouseListener = listener; } finally { this.lock.unlock( ); } } public AxisMouseListener1D getTimeAxisMouseListener( ) { return this.timelineMouseListener; } /** * Sets whether or not locking of the selected region is allowed for all * timeline and plot axes. This setting will also affect newly created plots. * * @param lock whether to allow locking of the selected region * @see AxisMouseListener#setAllowSelectionLock(boolean) */ public void setAllowSelectionLock( boolean lock ) { this.lock.lock( ); try { this.allowSelectionLock = lock; this.timelineMouseListener.setAllowSelectionLock( lock ); for ( TimePlotInfo info : getAllTimePlots( ) ) { info.getDataAxisMouseListener( ).setAllowSelectionLock( lock ); } } finally { this.lock.unlock( ); } } /** * Sets whether or not zooming of the Y axis is allowed for all * timeline and plot axes. This setting will also affect newly created plots. * * @param lock whether to allow zooming of the Y axis * @see AxisMouseListener#setAllowZoomY(boolean) */ public void setAllowZoomY( boolean lock ) { this.lock.lock( ); try { this.allowZoomY = lock; if ( this.getOrientation( ) == Orientation.HORIZONTAL ) { this.timelineMouseListener.setAllowZoom( lock ); } else { for ( TimePlotInfo info : getAllTimePlots( ) ) { info.getDataAxisMouseListener( ).setAllowZoom( lock ); } } } finally { this.lock.unlock( ); } } /** * Sets whether or not zooming of the X axis is allowed for all * timeline and plot axes. This setting will also affect newly created plots. * * @param lock whether to allow zooming of the X axis * @see AxisMouseListener#setAllowZoomX(boolean) */ public void setAllowZoomX( boolean lock ) { this.lock.lock( ); try { this.allowZoomX = lock; if ( this.getOrientation( ) == Orientation.VERTICAL ) { this.timelineMouseListener.setAllowZoom( lock ); } else { for ( TimePlotInfo info : getAllTimePlots( ) ) { info.getDataAxisMouseListener( ).setAllowZoom( lock ); } } } finally { this.lock.unlock( ); } } /** * Sets whether or not panning of the Y axis is allowed for all * timeline and plot axes. This setting will also affect newly created plots. * * @param lock whether to allow panning of the Y axis * @see AxisMouseListener#setAllowPanY(boolean) */ public void setAllowPanY( boolean lock ) { this.lock.lock( ); try { this.allowPanY = lock; if ( this.getOrientation( ) == Orientation.HORIZONTAL ) { this.timelineMouseListener.setAllowPan( lock ); } else { for ( TimePlotInfo info : getAllTimePlots( ) ) { info.getDataAxisMouseListener( ).setAllowPan( lock ); } } } finally { this.lock.unlock( ); } } /** * Sets whether or not panning of the X axis is allowed for all * timeline and plot axes. This setting will also affect newly created plots. * * @param lock whether to allow panning of the X axis * @see AxisMouseListener#setAllowPanX(boolean) */ public void setAllowPanX( boolean lock ) { this.lock.lock( ); try { this.allowPanX = lock; if ( this.getOrientation( ) == Orientation.VERTICAL ) { this.timelineMouseListener.setAllowPan( lock ); } else { for ( TimePlotInfo info : getAllTimePlots( ) ) { info.getDataAxisMouseListener( ).setAllowPan( lock ); } } } finally { this.lock.unlock( ); } } /** * Get the TaggedAxis1D Tag which defines the currently selected time. * * @return the current time selection Tag */ public Tag getTimeSelectionTag( ) { return this.currentTag; } /** * Get the TaggedAxis1D Tag which defines the earliest endpoint of the * selected time region. * * @return the earliest time selection Tag */ public Tag getTimeSelectionMinTag( ) { return this.minTag; } /** * Get the TaggedAxis1D Tag which defines the latest endpoint of the * selected time region. * * @return the latest time selection Tag */ public Tag getTimeSelectionMaxTag( ) { return this.maxTag; } /** * Get the currently selected time (usually equal to getTimeSelectionMax()). */ public TimeStamp getTimeSelection( ) { return epoch.toTimeStamp( currentTag.getValue( ) ); } /** * Get the TimeStamp of earliest endpoint of the selected time region. */ public TimeStamp getTimeSelectionMin( ) { return epoch.toTimeStamp( minTag.getValue( ) ); } /** * Get the TimeStamp of latest endpoint of the selected time region. */ public TimeStamp getTimeSelectionMax( ) { return epoch.toTimeStamp( maxTag.getValue( ) ); } public Epoch getEpoch( ) { return this.epoch; } public void setEpoch( Epoch epoch ) { this.epoch = epoch; this.timeTickHandler.setEpoch( epoch ); for ( PlotInfo info : getAllPlots( ) ) { if ( info instanceof TimelineInfo ) { ( ( TimelineInfo ) info ).setEpoch( epoch ); } } } public TimeStamp toTimeStamp( double value ) { return epoch.toTimeStamp( value ); } public double fromTimeStamp( TimeStamp value ) { return epoch.fromTimeStamp( value ); } public TaggedAxis1D getTimeAxis( ) { return ( TaggedAxis1D ) this.commonAxis; } public SelectedTimeRegionPainter getSelectedTimePainter( ) { return this.selectedTimePainter; } public void setLabelSize( int size ) { this.labelLayoutSize = size; this.validateLayout( ); } public void showLabels( boolean show ) { this.showLabelLayout = show; this.validateLayout( ); } public int getLabelSize( ) { return showLabelLayout ? this.labelLayoutSize : 0; } public boolean isShowLabels( ) { return this.showLabelLayout; } public boolean isTimeAxisHorizontal( ) { return getOrientation( ) == Orientation.VERTICAL; } /** * Pushes the layout stack for the named plot onto the provided * GlimpseTargetStack. * * @param id unique identifier for the plot * @return a relative GlimpseTargetStack for the named plot */ public GlimpseTargetStack pushLayoutTargetStack( GlimpseTargetStack stack, Object id ) { stack = pushPlotTargetStack( stack ); PlotInfo plot = getPlot( id ); stack.push( plot.getLayout( ) ); return stack; } /** * Pushes the layout stack for the base layout of this StackedTimePlot2D * onto the provided GlimpseTargetStack. * * @return a relative GlimpseTargetStack for the timeline plot background * layout */ public GlimpseTargetStack pushPlotTargetStack( GlimpseTargetStack stack ) { stack.push( this ); return stack; } /** * @see #createPlot(Object ) */ public TimePlotInfo createTimePlot( ) { return createTimePlot( UUID.randomUUID( ) ); } /** * @see #createPlot(Object, Axis1D ) */ public TimePlotInfo createTimePlot( Object id ) { return createTimePlot( id, new Axis1D( ) ); } /** * Creates a plot similar to {@code createPlot( String, Axis1D )} but with * additional plot decorations, including: grid lines, axes labels for the * data axis, and a text label describing the plot. * * @see #createPlot(Object, Axis1D ) */ public TimePlotInfo createTimePlot( Object id, Axis1D axis ) { this.lock.lock( ); try { PlotInfo plotInfo = createPlot0( id, axis ); TimePlotInfo timePlotInfo = createTimePlot0( plotInfo ); stackedPlots.put( id, timePlotInfo ); addTimePlotInfoListeners( timePlotInfo ); if ( isAutoValidate( ) ) validate( ); return timePlotInfo; } finally { this.lock.unlock( ); } } /** * Creates a labeled timeline (with tick marks and date/time labels). This method may * be called multiple times with different time zones if multiple timezone labels are * desired. */ public TimelineInfo createTimeline( ) { return createTimeline( UUID.randomUUID( ), TimeZone.getTimeZone( "GMT-0:00" ) ); } public TimelineInfo createTimeline( Object id, TimeZone timeZone ) { this.lock.lock( ); try { PlotInfo info = createPlot( id ); TimelineInfo timelineInfo = new TimelineInfo( this, info ); timelineInfo.setTimeZone( timeZone ); this.stackedPlots.put( timelineInfo.getId( ), timelineInfo ); if ( isAutoValidate( ) ) this.validate( ); return timelineInfo; } finally { this.lock.unlock( ); } } public TextureAtlas getTextureAtlas( ) { return this.defaultTextureAtlas; } public EventPlotInfo createEventPlot( ) { return createEventPlot( UUID.randomUUID( ) ); } public EventPlotInfo createEventPlot( Object id ) { return createEventPlot( id, defaultTextureAtlas ); } public boolean isLocked( ) { return isSelectionLocked( ) || isCurrentTimeLocked( ); } public boolean isSelectionLocked( ) { return getTimeAxis( ).isSelectionLocked( ); } /** * Fixes the selected time region so that it will no longer follow the mouse * cursor. * * @param lock whether to lock or unlock the selected time region */ public void setSelectionLocked( boolean lock ) { getTimeAxis( ).setSelectionLock( lock ); getTimeAxis( ).validate( ); } public boolean isCurrentTimeLocked( ) { return currentTimeLock; } /** * Fixes the selected time region and the timeline bounds with the current * maximum of the selected time region at the far right of the timeline. * * @param lock */ public void setCurrentTimeLocked( boolean lock ) { currentTimeLock = lock; if ( lock ) { double maxValue = maxTag.getValue( ); TimeStamp maxTime = epoch.toTimeStamp( maxValue ); shiftTimeSelection( maxTime ); shiftTimeAxisBounds( maxTime ); getTimeAxis( ).lockMax( maxValue ); } else { getTimeAxis( ).unlockMax( ); } getTimeAxis( ).validate( ); } public void setTimeSelection( TimeStamp minTime, TimeStamp selectedTime, TimeStamp maxTime ) { minTag.setValue( epoch.fromTimeStamp( minTime ) ); maxTag.setValue( epoch.fromTimeStamp( maxTime ) ); currentTag.setValue( epoch.fromTimeStamp( selectedTime ) ); TaggedAxis1D axis = getTimeAxis( ); axis.validateTags( ); axis.validate( ); if ( isCurrentTimeLocked( ) ) { shiftTimeAxisBounds( maxTime ); } } public void setTimeAxisBounds( TimeStamp minTime, TimeStamp maxTime ) { TaggedAxis1D axis = getTimeAxis( ); axis.setMax( epoch.fromTimeStamp( maxTime ) ); axis.setMin( epoch.fromTimeStamp( minTime ) ); axis.validate( ); if ( isCurrentTimeLocked( ) ) { shiftTimeSelection( maxTime ); } } public void shiftTimeAxisBounds( TimeStamp maxTime ) { TaggedAxis1D axis = getTimeAxis( ); double diff = axis.getMax( ) - axis.getMin( ); double max = epoch.fromTimeStamp( maxTime ); axis.setMax( max ); axis.setMin( max - diff ); axis.validate( ); } public void setTimeSelection( TimeStamp minTime, TimeStamp maxTime ) { setTimeSelection( minTime, maxTime, maxTime ); } public void shiftTimeSelection( TimeStamp maxTime ) { double diff = Time.fromSeconds( maxTag.getValue( ) - minTag.getValue( ) ); TimeStamp minTime = maxTime.subtract( diff ); setTimeSelection( minTime, maxTime, maxTime ); } public TimeStamp getTime( GlimpseMouseEvent e ) { if ( isTimeAxisHorizontal( ) ) { return getEpoch( ).toTimeStamp( e.getAxisCoordinatesX( ) ); } else { return getEpoch( ).toTimeStamp( e.getAxisCoordinatesY( ) ); } } protected void initializeTimeAxis( ) { TaggedAxis1D timeAxis = getTimeAxis( ); this.addTimeTags( getTimeAxis( ) ); this.minTag = timeAxis.getTag( MIN_TIME ); this.maxTag = timeAxis.getTag( MAX_TIME ); this.currentTag = timeAxis.getTag( CURRENT_TIME ); } protected void initializeOverlayPainters( ) { this.selectedTimePainter = new SelectedTimeRegionPainter( this ); this.tooltipPainter = new TooltipPainter( this.defaultTextureAtlas ); this.overlayLayout.addGlimpseMouseMotionListener( new GlimpseMouseMotionListener( ) { @Override public void mouseMoved( GlimpseMouseEvent e ) { tooltipPainter.setLocation( e ); } } ); this.overlayLayout.addPainter( this.selectedTimePainter ); this.overlayLayout.addPainter( this.tooltipPainter ); this.timelineMouseListener = createTimeAxisListener( ); this.underlayLayout.addGlimpseMouseAllListener( this.timelineMouseListener ); } protected DataAxisMouseListener1D createDataAxisListener( PlotInfo plotInfo ) { return new DataAxisMouseListener1D( this, plotInfo ); } protected TimeAxisMouseListener1D createTimeAxisListener( ) { return new TimeAxisMouseListener1D( this ); } protected void addTimeTags( TaggedAxis1D axis ) { axis.addTag( MIN_TIME, 0 ); axis.addTag( MAX_TIME, 10 ); axis.addTag( CURRENT_TIME, 10 ); axis.addConstraint( new Constraint( ) { @Override public void applyConstraint( TaggedAxis1D axis ) { Tag minTag = axis.getTag( MIN_TIME ); Tag maxTag = axis.getTag( MAX_TIME ); Tag currentTag = axis.getTag( CURRENT_TIME ); double minValue = minTag.getValue( ); double maxValue = maxTag.getValue( ); double currentValue = currentTag.getValue( ); if ( minValue > maxValue ) { minTag.setValue( maxValue ); } if ( currentValue < minValue ) { currentTag.setValue( minValue ); } else if ( currentValue > maxValue ) { currentTag.setValue( maxValue ); } } @Override public String getName( ) { return "order"; } } ); } @Override protected TaggedAxis1D createCommonAxis( ) { return new TaggedAxis1D( ); } protected EventPlotInfo createEventPlot( Object id, TextureAtlas atlas ) { this.lock.lock( ); try { PlotInfo plotInfo = createPlot0( id, new Axis1D( ) ); EventPlotInfo eventPlotInfo = createEventPlot0( plotInfo, atlas ); stackedPlots.put( id, eventPlotInfo ); addTimePlotInfoListeners( eventPlotInfo ); if ( isAutoValidate( ) ) validate( ); return eventPlotInfo; } finally { this.lock.unlock( ); } } protected EventPlotInfo createEventPlot0( PlotInfo plotInfo, TextureAtlas atlas ) { TimePlotInfo timePlot = createTimePlot0( plotInfo ); // don't show axes timePlot.getAxisPainter( ).setVisible( false ); // don't show grid lines timePlot.getGridPainter( ).setVisible( false ); // center the labels because the plots are so small anyway if ( isTimeAxisHorizontal( ) ) { timePlot.getLabelPainter( ).setVerticalPosition( VerticalPosition.Center ); timePlot.getLabelPainter( ).setHorizontalPosition( HorizontalPosition.Left ); } else { timePlot.getLabelPainter( ).setVerticalPosition( VerticalPosition.Center ); timePlot.getLabelPainter( ).setHorizontalPosition( HorizontalPosition.Center ); } // the TimeAxisMouseListener1D for all plots is attached to the underlay layout // thus we need to let events fall through if they are not handled timePlot.getLayout( ).setEventConsumer( false ); EventPlotInfo eventPlotInfo = new EventPlotInfo( timePlot, atlas ); eventPlotInfo.setLookAndFeel( laf ); eventPlotInfo.setSelectionHandler( commonSelectionHandler ); return eventPlotInfo; } protected EventPlotInfo createEventPlot0( PlotInfo plotInfo ) { return createEventPlot0( plotInfo, defaultTextureAtlas ); } protected TimePlotInfo createTimePlot0( PlotInfo plotInfo ) { // create a tick handler to calculate Y axis tick marks GridAxisLabelHandler labelHandler = new GridAxisLabelHandler( ) { @Override protected String tickString( double number, int orderAxis ) { return tickNumberFormatter.format( number ); } @Override protected void updateFormatter( int orderAxis, int orderTick ) { tickNumberFormatter.setMaximumFractionDigits( Math.abs( orderTick ) ); } }; GlimpseAxisLayout2D layout2D = plotInfo.getLayout( ); layout2D.setEventConsumer( false ); GlimpseAxisLayout2D plotLayout = new GlimpseAxisLayout2D( layout2D, String.format( "%s-plot", plotInfo.getId( ) ), layout2D.getAxis( ) ); plotLayout.setEventConsumer( false ); BackgroundPainter backgroundPainter = new BackgroundPainter( false ); plotLayout.addPainter( backgroundPainter, Integer.MIN_VALUE ); // add a painter for user data DelegatePainter dataPainter = new DelegatePainter( ); plotLayout.addPainter( dataPainter ); AxisLabelHandler xHandler, yHandler; if ( orient == HORIZONTAL ) { xHandler = labelHandler; yHandler = timeTickHandler; } else { yHandler = labelHandler; xHandler = timeTickHandler; } // create a painter to display Y axis grid lines GridPainter gridPainter = new GridPainter( xHandler, yHandler ); gridPainter.setShowMinorGrid( false ); plotLayout.addPainter( gridPainter ); // create a painter to display Y axis tick marks along the left edge of the graph NumericXYAxisPainter axisPainter = new NumericXYAxisPainter( xHandler, yHandler ); axisPainter.setFont( getDefaultPlain( 9 ), false ); axisPainter.setShowLabelsNearOrigin( true ); axisPainter.setShowOriginLabel( true ); plotLayout.addPainter( axisPainter ); // add a border BorderPainter borderPainter = new BorderPainter( ); plotLayout.addPainter( borderPainter ); // create a custom mouse listener for the data (non-time) axis DataAxisMouseListener1D listener = createDataAxisListener( plotInfo ); GlimpseAxisLayout1D layout1D; if ( orient == HORIZONTAL ) { layout1D = new GlimpseAxisLayoutX( plotLayout ); } else { layout1D = new GlimpseAxisLayoutY( plotLayout ); } layout1D.setEventConsumer( false ); layout1D.addGlimpseMouseAllListener( listener ); // the TimeAxisMouseListener1D for all plots is attached to the underlay layout // thus we need to let events fall through if they are not handled plotLayout.setEventConsumer( false ); // create a GlimpseLayout which will appear to the side of the timeline and contain labels/controls GlimpseLayout labelLayout = new GlimpseLayout( layout2D, String.format( "%s-label", plotInfo.getId( ) ) ); // add a label to display the plot title SimpleTextPainter labelPainter = new SimpleTextPainter( ); labelPainter.setHorizontalPosition( HorizontalPosition.Center ); labelPainter.setVerticalPosition( VerticalPosition.Center ); labelPainter.setFont( FontUtils.getDefaultBold( 9 ), false ); labelPainter.setPadding( 2 ); // don't use the plot unique identifier as the label by default, this makes // it too easy to think that the String argument to createPlot() is supposed to be the label labelPainter.setText( "" ); labelPainter.setHorizontalLabels( false ); labelLayout.addPainter( labelPainter ); // add a border BorderPainter labelBorderPainter = new BorderPainter( ); labelBorderPainter.setVisible( false ); labelLayout.addPainter( labelBorderPainter ); //@formatter:off TimePlotInfo timePlotInfo = new TimePlotInfoImpl( StackedTimePlot2D.this, plotInfo, plotLayout, labelLayout, listener, gridPainter, axisPainter, labelPainter, borderPainter, labelBorderPainter, backgroundPainter, dataPainter ); //@formatter:on if ( orient == HORIZONTAL ) { gridPainter.setShowHorizontalLines( false ); labelHandler.setTickSpacing( 45 ); axisPainter.setShowVerticalTicks( false ); axisPainter.setShowHorizontalTicks( true ); axisPainter.setLockTop( true ); } else { gridPainter.setShowVerticalLines( false ); labelHandler.setTickSpacing( 16 ); axisPainter.setShowVerticalTicks( true ); axisPainter.setShowHorizontalTicks( false ); axisPainter.setLockLeft( true ); } timePlotInfo.setLookAndFeel( laf ); return timePlotInfo; } @Override public PlotInfo createPlot( Object id, Axis1D axis ) { PlotInfo info = super.createPlot( id, axis ); addPlotInfoListeners( info ); return info; } protected void addPlotInfoListeners( PlotInfo info ) { info.getLayout( ).addGlimpseMouseAllListener( createPlotMouseListener( info, PlotMouseListener.PlotLocation.Plot ) ); } protected void addTimePlotInfoListeners( TimePlotInfo info ) { info.getLabelLayout( ).addGlimpseMouseAllListener( createPlotMouseListener( info, PlotMouseListener.PlotLocation.Label ) ); info.getLayout( ).addGlimpseMouseAllListener( createPlotMouseListener( info, PlotMouseListener.PlotLocation.Plot ) ); } protected GlimpseMouseAllListener createPlotMouseListener( final PlotInfo info, final PlotMouseListener.PlotLocation location ) { return new GlimpseMouseAllListener( ) { @Override public void mouseWheelMoved( GlimpseMouseEvent e ) { for ( PlotMouseListener listener : plotMouseListeners ) { listener.mouseWheelMoved( e, info, location ); } } @Override public void mouseMoved( GlimpseMouseEvent e ) { for ( PlotMouseListener listener : plotMouseListeners ) { listener.mouseMoved( e, info, location ); } } @Override public void mouseReleased( GlimpseMouseEvent e ) { for ( PlotMouseListener listener : plotMouseListeners ) { listener.mouseReleased( e, info, location ); } } @Override public void mousePressed( GlimpseMouseEvent e ) { for ( PlotMouseListener listener : plotMouseListeners ) { listener.mousePressed( e, info, location ); } } @Override public void mouseExited( GlimpseMouseEvent e ) { for ( PlotMouseListener listener : plotMouseListeners ) { listener.mouseExited( e, info, location ); } } @Override public void mouseEntered( GlimpseMouseEvent e ) { for ( PlotMouseListener listener : plotMouseListeners ) { listener.mouseEntered( e, info, location ); } } }; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy