]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
New trend axis mode SingleAxisShowLegends 16/4716/1 release/1.43.0-CVM2
authorMiro Eklund <miro.eklund@semantum.fi>
Wed, 14 Apr 2021 06:52:57 +0000 (09:52 +0300)
committerMiro Eklund <miro.eklund@semantum.fi>
Wed, 14 Apr 2021 06:52:57 +0000 (09:52 +0300)
Allows displaying the names of all plotted lines as part of a single
axis.

related to #693

Change-Id: Iab5be5582a03ae4aaabe2ba1ece0280f23a57c95

bundles/org.simantics.trend/example/org/simantics/trend/DemoTrendSingleAxisShowLegends.java [new file with mode: 0644]
bundles/org.simantics.trend/src/org/simantics/trend/configuration/TrendSpec.java
bundles/org.simantics.trend/src/org/simantics/trend/configuration/YAxisMode.java
bundles/org.simantics.trend/src/org/simantics/trend/impl/TrendNode.java
bundles/org.simantics.trend/src/org/simantics/trend/impl/VertRuler.java

diff --git a/bundles/org.simantics.trend/example/org/simantics/trend/DemoTrendSingleAxisShowLegends.java b/bundles/org.simantics.trend/example/org/simantics/trend/DemoTrendSingleAxisShowLegends.java
new file mode 100644 (file)
index 0000000..bdb22a3
--- /dev/null
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.trend;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+
+import javax.swing.JFrame;
+
+import org.simantics.g2d.canvas.impl.CanvasContext;
+import org.simantics.g2d.chassis.AWTChassis;
+import org.simantics.g2d.image.DefaultImages;
+import org.simantics.history.impl.FileHistory;
+import org.simantics.trend.configuration.Scale;
+import org.simantics.trend.configuration.TrendItem;
+import org.simantics.trend.configuration.TrendSpec;
+import org.simantics.trend.configuration.YAxisMode;
+import org.simantics.trend.impl.Milestone;
+import org.simantics.trend.impl.MilestoneSpec;
+import org.simantics.trend.impl.TrendNode;
+import org.simantics.trend.impl.TrendParticipant;
+import org.simantics.utils.FileUtils;
+import org.simantics.utils.datastructures.hints.IHintContext;
+import org.simantics.utils.threads.AWTThread;
+import org.simantics.utils.threads.IThreadWorkQueue;
+
+public class DemoTrendSingleAxisShowLegends {
+
+       public static void main(String[] args) throws Exception {
+               System.out.println(DefaultImages.HAND);
+
+               // Initialize file history
+               final File workarea = FileUtils.createTmpDir();
+               final TestData data = new TestData(workarea);
+               FileHistory fh = ((FileHistory) data.historyManager);
+               fh.asyncUsage = false;
+               // Memory history
+               // final TestData data = new TestData();
+
+               final TrendSpec trendSpec = new TrendSpec();
+               trendSpec.init();
+               trendSpec.viewProfile.showMilestones = true;
+               trendSpec.name = "SingleAxisShowLegends Y-Axis DemoTrend";
+               trendSpec.axisMode = YAxisMode.SingleAxisShowLegends;
+               trendSpec.singleAxisShowLegendsMaxLegends = 10;
+               
+               trendSpec.items.add(new TrendItem(1, "Sine", data.subscriptionId, "Sine", new Scale.Manual(-100, 100),
+                               TrendItem.Renderer.Analog));
+               trendSpec.items.add(new TrendItem(2, "Random", data.subscriptionId, "Random", new Scale.Auto(), TrendItem.Renderer.Analog));
+               
+               trendSpec.viewProfile.profileName = "Profile";
+//        trendSpec.viewProfile.timeWindow.timeWindowLength = 180.0;
+//        trendSpec.viewProfile.timeWindow.timeWindowStart = 0.0;
+               trendSpec.viewProfile.timeWindow.timeWindowIncrement = 75.0;
+
+               // Alternative spec - Switch with Spacebarman button
+//        TrendSpec altSpec = new TrendSpec();
+//        altSpec.init();
+//        altSpec.viewProfile.showMilestones = true;
+//        altSpec.name = "Single Axis";
+//        altSpec.axisMode = YAxisMode.SingleAxis;
+//        altSpec.items.add( new TrendItem( 1, "Sine", data.subscriptionId,"Sine", new Scale.Auto(), TrendItem.Renderer.Analog, 0, 1 ) );
+//        altSpec.items.add( new TrendItem( 2, "Ramp", data.subscriptionId,"Ramp", new Scale.Auto(), TrendItem.Renderer.Binary ) );
+//        //altSpec.items.add( new TrendItem( "Random", data.subscriptionId,"Random", new Scale.FitAll(), TrendItem.Renderer.Analog, 0, 1, DrawMode.Deviation ) );             
+//        altSpec.viewProfile.profileName = "Profile";
+//        //altSpec.viewProfile.timeWindow.timeWindowLength = 30.0;
+//        //altSpec.viewProfile.timeWindow.timeWindowStart = 0.0;
+//        altSpec.viewProfile.timeWindow.timeWindowIncrement = 25.0;
+
+               // JFrame has double buffering enabled by default
+               JFrame frame = new JFrame("Demo Trend");
+               // Add a window listener for close button
+               frame.addWindowListener(new WindowAdapter() {
+                       @Override
+                       public void windowClosing(WindowEvent e) {
+                               data.dispose();
+                               System.exit(0);
+                       }
+               });
+
+               data.solver.start();
+
+               // This is an empty content area in the frame
+               final AWTChassis chassis = new AWTChassis();
+
+               chassis.setPreferredSize(new Dimension(480, 320));
+
+               frame.getContentPane().add(chassis, BorderLayout.CENTER);
+               frame.pack();
+
+               frame.setVisible(true);
+               chassis.requestFocus();
+
+               IThreadWorkQueue thread = AWTThread.getThreadAccess();
+
+               final CanvasContext ctx = TrendInitializer.createDefaultCanvas(thread, data.historyManager, data.collector,
+                               data.solver, trendSpec);
+               TrendNode node = TrendInitializer.getTrendNode(ctx);
+
+               ctx.getAtMostOneItemOfClass(TrendParticipant.class).setHintAsync(TrendParticipant.KEY_TREND_DRAW_INTERVAL,
+                               1000L);
+
+               MilestoneSpec milestones = new MilestoneSpec();
+               milestones.init();
+               Milestone m1 = new Milestone("1", "1", "Event 1", 50);
+               Milestone m2 = new Milestone("2", "2", "Event 2", 60);
+               Milestone m3 = new Milestone("3", "3", "Event 3", 80);
+               Milestone m4 = new Milestone("4", "4", "Event 4", 90);
+               milestones.milestones.add(m1);
+               milestones.milestones.add(m2);
+               milestones.milestones.add(m3);
+               milestones.milestones.add(m4);
+               milestones.baseline = 2;
+               node.setMilestones(milestones);
+
+               @SuppressWarnings("unused")
+               IHintContext hintCtx = ctx.getDefaultHintContext();
+
+               thread.asyncExec(new Runnable() {
+                       @Override
+                       public void run() {
+                               chassis.setCanvasContext(ctx);
+                       }
+               });
+       }
+
+}
index 9970544d032cf2968c9e7dd56a8040bb43663438..46b4a8023866bc361783664d0066105dc4480fc5 100644 (file)
@@ -27,6 +27,8 @@ public class TrendSpec extends Bean {
 
        public YAxisMode axisMode;
        
+       public int singleAxisShowLegendsMaxLegends = 10;
+       
        public ViewProfile viewProfile;
 
        /**
index c3d7e26b2b854456d2e465700613792395271726..aad7468b1842d274474c4580ec1bd65d07f5f006 100644 (file)
@@ -16,7 +16,11 @@ public enum YAxisMode {
        SingleAxis,
        
        // Each variable has its own axis
-       MultiAxis
+       MultiAxis,
+       
+       // Each variable has the same axis, but legends is shown for each, just like with MultiAxis
+       // Works only for analog values
+       SingleAxisShowLegends
        
 }
 
index ddbd4934e0763dd6dd82468a0031563b2ea56f5d..80ffa97679a748d6afd218cd5876ebb0a73050e2 100644 (file)
@@ -87,6 +87,7 @@ public class TrendNode extends G2DParentNode implements TrendLayout {
        public TrendQualitySpec quality = TrendQualitySpec.DEFAULT;
        public boolean printing = false;
        boolean singleAxis;
+       boolean singleAxisShowLegends;
        
        // Data nodes
        List<ItemNode> analogItems = new ArrayList<ItemNode>();
@@ -322,7 +323,27 @@ public class TrendNode extends G2DParentNode implements TrendLayout {
 
                // Setup vertical ruler nodes
                singleAxis = spec.axisMode == YAxisMode.SingleAxis;
-               if (singleAxis) {
+               singleAxisShowLegends = spec.axisMode == YAxisMode.SingleAxisShowLegends;
+               if(singleAxisShowLegends) {
+                       if (yaxisModeChanged || vertRulers.size() != 1 || vertRuler == null) {
+                               for (VertRuler vr : vertRulers) removeNode(vr);
+                               vertRulers.clear();
+
+                               vertRuler = addNode("VertRuler", VertRuler.class);
+                               vertRulers.add( vertRuler );
+                       }
+
+                       vertRuler.manualscale = true;
+                       vertRuler.singleAxisShowLegendsMaxLegends = spec.singleAxisShowLegendsMaxLegends;
+                       for (int i=0; i<analogItems.size(); i++) {
+                               ItemNode item = analogItems.get(i);
+                               vertRuler.addExtraLabel(item.item.label, item.color);
+                               item.ruler = vertRuler;
+                               item.trendNode = this;
+                               if (item.item.scale instanceof Scale.Manual == false) vertRuler.manualscale = false;
+                       }
+               }
+               else if (singleAxis) {
                        if (yaxisModeChanged || vertRulers.size() != 1 || vertRuler == null) {
                                for (VertRuler vr : vertRulers) removeNode(vr);
                                vertRulers.clear();
@@ -370,8 +391,8 @@ public class TrendNode extends G2DParentNode implements TrendLayout {
                                ItemNode item = analogItems.get(i);
                                VertRuler vr = vertRulers.get(i);
                                vr.setZIndex(1000 + i);
-                               vr.color = item.color;
                                vr.label = item.item.label;
+                               vr.color = item.color;
                                vr.manualscale = item.item.scale instanceof Scale.Manual;
                                item.ruler = vr;
                                item.trendNode = this;
index a6a234c805c126e5a7af20665627bf3d422f1370..d9560b0c3620192b4011d42cef23d6b06d1cef70 100644 (file)
@@ -18,6 +18,8 @@ import java.awt.Graphics2D;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Path2D;
 import java.text.Format;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.simantics.g2d.utils.GridSpacing;
 import org.simantics.g2d.utils.GridUtil;
@@ -37,7 +39,11 @@ public class VertRuler extends TrendGraphicalNode {
        boolean autoscroll = true;  // Autoscroll on/off
        boolean manualscale = false; // Autoscale / manual scale
        double labelWidth = 7;
-
+       List<String> extra_labels = new ArrayList<>();
+       List<Color> extra_label_colors = new ArrayList<>();
+       double extra_width = 0.0;
+       int singleAxisShowLegendsMaxLegends = 10;
+       
        static final double TRIANGLE_SIZE = 7;
     static final Path2D TRIANGLE;
                        
@@ -47,7 +53,9 @@ public class VertRuler extends TrendGraphicalNode {
                ValueFormat vf = trend.valueFormat;
                spacing = GridSpacing.makeGridSpacing(max-min, getHeight(), 15);
                labelWidth = Math.max(7, GridUtil.calcLabelWidth(min, max, vf.format, spacing));
+               
                double w = 30 + labelWidth;
+               
                // Snap w -> next 20 pixels
                double quantization = 10; 
                int x = (int) Math.ceil( w / quantization );
@@ -57,13 +65,35 @@ public class VertRuler extends TrendGraphicalNode {
                bounds.setFrame(0, 0, w, getHeight());          
                trend.shapedirty = true;
        }
-
+       
+       public void addExtraLabel(String label, Color color) {
+               extra_labels.add(label);
+               extra_label_colors.add(color);
+       }
+       
        public void setHeight(double height) {
                if (height==bounds.getHeight()) return;
                bounds.setFrame(0, 0, bounds.getWidth(), height);               
                getTrend().shapedirty = true;
        }
        
+       @Override
+       public double getWidth() { 
+               if(extra_labels.size() == 0) {
+                       return super.getWidth();
+               } else {
+                       if(extra_width == 0.0) {
+                               extra_width = 15.0 * extra_labels.size();
+                               double w = bounds.getWidth();
+                               return w + extra_width;
+                       } else {
+                               double w = bounds.getWidth();
+                               return w + extra_width;
+                       }
+               }
+               
+       }
+       
        public boolean setMinMax(double min, double max) {
                if (min==this.min && max==this.max) return false;
                spacing = GridSpacing.makeGridSpacing(max-min, getHeight(), 15);
@@ -77,6 +107,9 @@ public class VertRuler extends TrendGraphicalNode {
        protected void doRender(Graphics2D g) {
                TrendNode trend = (TrendNode) getParent();
                
+               VertRuler master = trend.vertRuler;
+               VertRuler slave = this;
+
                // Draw little "Frozen"
                if ( !trend.printing )
                {
@@ -88,20 +121,19 @@ public class VertRuler extends TrendGraphicalNode {
                        // Draw at top
                        g.drawString(txt, 5.f, -9.f );
                }
-               
+
                g.setPaint( color );
                g.setStroke( GridUtil.RULER_LINE_STROKE );              
-                               
+
                ValueFormat vf = trend.valueFormat;
-               VertRuler master = trend.vertRuler;
-               VertRuler slave = this;
+
                if ( master != slave )
                {       
                        // Paint "slave" ruler - a ruler with ticks from master and labels from this
                        int tickCount = GridUtil.getTickCount(master.spacing, master.min, master.getHeight());
                        int noOfDecimals = calcNoOfDecimals(tickCount, slave.max-slave.min);
                        Format format = vf.toFormat(noOfDecimals);
-                       
+
                        GridUtil.paintVerticalSlaveRuler(
                                        master.spacing,
                                        spacing, 
@@ -112,16 +144,16 @@ public class VertRuler extends TrendGraphicalNode {
                                        format);
                } else {
                        Format format = vf.format;
-                       
+
                        // Paint normal ruler
                        GridUtil.paintVerticalRuler(
-                               spacing, 
-                               g,
-                               min,
-                               getHeight(),
-                               format);
+                                       spacing, 
+                                       g,
+                                       min,
+                                       getHeight(),
+                                       format);
                }
-               
+
                // Draw label
                {
 //                     Shape oldClip = g2d.getClip();
@@ -133,25 +165,54 @@ public class VertRuler extends TrendGraphicalNode {
                        Font font = selected ? RULER_FONT_BOLD : RULER_FONT;
                        FontMetrics fm = g.getFontMetrics( font );
                        //LineMetrics lm = fm.getLineMetrics(label, g);
-                       double wid = fm.stringWidth(label);
                        
-                       AffineTransform at = g.getTransform();
-                       g.translate( getWidth()-15, (getHeight()-wid)/2);
-//                     g2d.translate( 18+labelWidth, (getHeight()-wid)/2);
-                       g.transform( AffineTransform.getQuadrantRotateInstance(1) );
-                       g.setColor( color );
-                       g.setFont( font );
-                       g.drawString( label, (float) 0, (float) 0);
-                       g.setTransform( at );                   
-//                     g2d.setClip(oldClip);
-                       
-                       // Triangle
-                       if (selected) {
-                               at = g.getTransform();
-                               g.translate( getWidth() - TRIANGLE_SIZE - 5, 0 );
+                       if(extra_labels.size() == 0) {
+                               double wid = fm.stringWidth(label);
+                               
+                               AffineTransform at = g.getTransform();
+                               g.translate( getWidth()-15, (getHeight()-wid)/2);                       
+       //                      g2d.translate( 18+labelWidth, (getHeight()-wid)/2);
+                               g.transform( AffineTransform.getQuadrantRotateInstance(1) );
                                g.setColor( color );
-                               g.fill( TRIANGLE );                             
+                               g.setFont( font );
+                               g.drawString( label, (float) 0, (float) 0);
                                g.setTransform( at );                   
+       //                      g2d.setClip(oldClip);
+                               
+                               // Triangle
+                               if (selected) {
+                                       at = g.getTransform();
+                                       g.translate( getWidth() - TRIANGLE_SIZE - 5, 0 );
+                                       g.setColor( color );
+                                       g.fill( TRIANGLE );                             
+                                       g.setTransform( at );                   
+                               }
+                       } else {
+                               extra_width = 0.0;
+                               double bounds_width = bounds.getWidth();
+                               
+                               for(int label_index = 0; label_index < extra_labels.size(); label_index++) {
+                                       if(label_index >= singleAxisShowLegendsMaxLegends) {
+                                               break; // Maximum amount of labels that we should display has been reached
+                                       }
+                                       
+                                       String label = extra_labels.get(label_index);
+                                       Color color = extra_label_colors.get(label_index);
+                                       
+                                       double wid = fm.stringWidth(label);
+                                       double font_height = fm.getHeight();
+                                       extra_width += font_height;
+                                       //Letters are displayed in 90 degree angle, so font height is the width of the label as seen in X-direction
+                                       
+                                       AffineTransform at = g.getTransform();
+                                       g.translate( bounds_width + label_index*font_height, (getHeight()-wid)/2);                      
+               //                      g2d.translate( 18+labelWidth, (getHeight()-wid)/2);
+                                       g.transform( AffineTransform.getQuadrantRotateInstance(1) );
+                                       g.setColor( color );
+                                       g.setFont( font );
+                                       g.drawString( label, (float) 0, (float) 0);
+                                       g.setTransform( at );   
+                               }
                        }
                }
        }