--- /dev/null
+/*******************************************************************************
+ * 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);
+ }
+ });
+ }
+
+}
public YAxisMode axisMode;
+ public int singleAxisShowLegendsMaxLegends = 10;
+
public ViewProfile viewProfile;
/**
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
}
public TrendQualitySpec quality = TrendQualitySpec.DEFAULT;
public boolean printing = false;
boolean singleAxis;
+ boolean singleAxisShowLegends;
// Data nodes
List<ItemNode> analogItems = new ArrayList<ItemNode>();
// 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();
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;
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;
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;
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 );
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);
protected void doRender(Graphics2D g) {
TrendNode trend = (TrendNode) getParent();
+ VertRuler master = trend.vertRuler;
+ VertRuler slave = this;
+
// Draw little "Frozen"
if ( !trend.printing )
{
// 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,
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();
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 );
+ }
}
}
}