/******************************************************************************* * Copyright (c) 2010, 2017 Oak Ridge National Laboratory. * 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 ******************************************************************************/ package org.eclipse.nebula.visualization.xygraph.linearscale; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.eclipse.draw2d.Figure; import org.eclipse.draw2d.FigureUtilities; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.nebula.visualization.xygraph.linearscale.AbstractScale.LabelSide; import org.eclipse.nebula.visualization.xygraph.util.XYGraphMediaFactory; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.RGB; /** * A linear scale related marker, whose orientation, range, mark position etc. * are determined by the scale. It must have the same length and bounds.x(for * horizontal) or bounds.y(for vertical) with the scale. * * @author Xihui Chen */ public class LinearScaledMarker extends Figure { private Map<String, MarkerProperties> markersMap = new LinkedHashMap<String, MarkerProperties>(); private static final RGB DEFAULT_MARKER_COLOR = XYGraphMediaFactory.COLOR_RED; private String[] labels; private double[] markerValues; private Dimension[] markerLabelDimensions; private List<Color> markerColorsList = new ArrayList<Color>(); private LinearScale scale; private LabelSide makerLabelsPosition = LabelSide.Secondary; private boolean markerLineVisible = false; private boolean markerLabelVisible = true; private int tickLabelMaxLength; private boolean dirty = true; private int[] markerPositions; private final static int TICK_LENGTH = 10; private final static int TICK_LINE_WIDTH = 2; private final static int GAP_BTW_MARK_LABEL = 3; /** * Constructor * * @param scale */ public LinearScaledMarker(LinearScale scale) { this.scale = scale; setFont(XYGraphMediaFactory.getInstance().getFont(XYGraphMediaFactory.FONT_TAHOMA)); } /** * @param dirty * the dirty to set */ public void setDirty(boolean dirty) { this.dirty = dirty; } /** * If the marker exists, set its value. * * @param label * the label of the marker element, it must be unique. * @param value * the value to be set */ public void setMarkerElementValue(String label, double value) { if (markersMap.containsKey(label)) { markersMap.get(label).value = value; dirty = true; } } /** * If the marker exists, set its color. * * @param label * the label of the marker element, it must be unique. * @param color * the color to be set */ public void setMarkerElementColor(String label, RGB color) { if (markersMap.containsKey(label)) { markersMap.get(label).color = color; dirty = true; } } /** * Add (if the marker does not exist) or change a marker element. * * @param label * the label of the marker element, it must be unique. * @param value * the value of the marker element * @param color * the color of the marker element */ public void addMarkerElement(String label, double value, RGB color) { if (markersMap.containsKey(label)) { markersMap.get(label).value = value; markersMap.get(label).color = color; } else markersMap.put(label, new MarkerProperties(value, color)); dirty = true; } /** * Add (if the marker does not exist) or change a marker element. * * @param label * the label of the marker element, it must be unique. * @param value * the value of the marker element */ public void addMarkerElement(String label, double value) { if (markersMap.containsKey(label)) markersMap.get(label).value = value; else markersMap.put(label, new MarkerProperties(value, DEFAULT_MARKER_COLOR)); dirty = true; } /** * Removes the marker element with the given label * * @param label */ public void removeMarkerElement(String label) { markersMap.remove(label); dirty = true; } @Override protected void paintClientArea(Graphics graphics) { // use relative coordinate graphics.translate(bounds.x, bounds.y); updateTick(); drawMarkerTick(graphics); super.paintClientArea(graphics); } private void drawMarkerTick(Graphics graphics) { graphics.setLineWidth(TICK_LINE_WIDTH); if (scale.isHorizontal()) { if (makerLabelsPosition == LabelSide.Primary) { int i = 0; for (int markerPos : markerPositions) { graphics.setForegroundColor(markerColorsList.get(i)); graphics.drawLine(markerPos, 0, markerPos, TICK_LENGTH); // draw labels if (isMarkerLabelVisible()) { graphics.drawText(labels[i], markerPos - markerLabelDimensions[i].width / 2, TICK_LENGTH + GAP_BTW_MARK_LABEL); } i++; } } else { int i = 0; for (int markerPos : markerPositions) { graphics.setForegroundColor(markerColorsList.get(i)); graphics.drawLine(markerPos, bounds.height, markerPos, bounds.height - TICK_LENGTH); // draw labels if (isMarkerLabelVisible()) { graphics.drawText(labels[i], markerPos - markerLabelDimensions[i].width / 2, bounds.height - TICK_LENGTH - GAP_BTW_MARK_LABEL - markerLabelDimensions[i].height); } i++; } } } else { if (makerLabelsPosition == LabelSide.Primary) { for (int i = 0; i < markerPositions.length; i++) { graphics.setForegroundColor(markerColorsList.get(i)); graphics.drawLine(bounds.width, markerPositions[i], bounds.width - TICK_LENGTH, markerPositions[i]); // draw labels if (isMarkerLabelVisible()) { graphics.drawText(labels[i], bounds.width - TICK_LENGTH - GAP_BTW_MARK_LABEL - markerLabelDimensions[i].width, markerPositions[i] - markerLabelDimensions[i].height / 2); } } } else { int i = 0; for (int markerPos : markerPositions) { graphics.setForegroundColor(markerColorsList.get(i)); graphics.drawLine(0, markerPos, TICK_LENGTH, markerPos); // draw labels if (isMarkerLabelVisible()) { graphics.drawText(labels[i], TICK_LENGTH + GAP_BTW_MARK_LABEL, markerPos - markerLabelDimensions[i].height / 2); } i++; } } } } @Override public void setBounds(Rectangle rect) { if (!bounds.equals(rect)) dirty = true; super.setBounds(rect); } /** * Updates the tick, recalculate all inner parameters */ public void updateTick() { if (dirty == true) { updateMarkerElements(); updateTickLabelMaxLength(); } dirty = false; } /** * Gets max length of tick label. */ private void updateTickLabelMaxLength() { int maxLength = 0; for (int i = 0; i < labels.length; i++) { Dimension p = FigureUtilities.getTextExtents(labels[i], scale.getFont()); if (p.width > maxLength) { maxLength = p.width; } } tickLabelMaxLength = maxLength; } /** * @return the labels */ public String[] getLabels() { String[] labels = new String[markersMap.size()]; int i = 0; for (String label : markersMap.keySet()) { labels[i] = label; i++; } return labels; } /** * Use correctly spelled {@link #updateMarkerElements()} instead. */ @Deprecated public void updateMarkerElments() { updateMarkerElements(); } /** * updates marker elements of ticks */ public void updateMarkerElements() { labels = new String[markersMap.size()]; markerColorsList.clear(); markerValues = new double[markersMap.size()]; markerLabelDimensions = new Dimension[markersMap.size()]; markerPositions = new int[markerValues.length]; int i = 0; for (String label : markersMap.keySet()) { labels[i] = label; markerValues[i] = markersMap.get(label).value; markerPositions[i] = scale.getValuePosition(markerValues[i], true); markerLabelDimensions[i] = FigureUtilities.getTextExtents(label, getFont()); markerColorsList.add(XYGraphMediaFactory.getInstance().getColor(markersMap.get(label).color)); i++; } } /** * @param scale * the scale to set */ public void setScale(LinearScale scale) { this.scale = scale; dirty = true; } /** * @return the scale */ public LinearScale getScale() { return scale; } /** * @param labelSide * the makerLabelsPosition to set */ public void setLabelSide(LabelSide labelSide) { this.makerLabelsPosition = labelSide; dirty = true; } /** * @return the makerLabelsPosition */ public LabelSide getMakerLabelsPosition() { return makerLabelsPosition; } /** * @deprecated use correctly spelled {@link #getMakerLabelsPosition()} */ @Deprecated public LabelSide getMakerLablesPosition() { return getMakerLabelsPosition(); } /** * @param markerLineVisible * the markerLineVisible to set */ public void setMarkerLineVisible(boolean markerLineVisible) { this.markerLineVisible = markerLineVisible; dirty = true; } /** * @return the markerLineVisible */ public boolean isMarkerLineVisible() { return markerLineVisible; } /** * @param markerLabelVisible * the markerLabelVisible to set */ public void setMarkerLabelVisible(boolean markerLabelVisible) { this.markerLabelVisible = markerLabelVisible; dirty = true; } /** * @deprecated use correctly spelled {@link #setMarkerLabelVisible(boolean)} */ @Deprecated public void setMarkerLableVisible(boolean markerLabelVisible) { setMarkerLabelVisible(markerLabelVisible); } /** * @return the markerLabelVisible */ public boolean isMarkerLabelVisible() { return markerLabelVisible; } /** * @deprecated use correctly spelled {@link #isMarkerLabelVisible() */ @Deprecated public boolean isMarkerLableVisible() { return isMarkerLabelVisible(); } @Override public Dimension getPreferredSize(int wHint, int hHint) { updateTick(); Dimension size = new Dimension(wHint, hHint); if (scale.isHorizontal()) { size.width = scale.getSize().width; size.height = FigureUtilities.getTextExtents("dummy", getFont()).height + GAP_BTW_MARK_LABEL + TICK_LENGTH; } else { updateTickLabelMaxLength(); size.width = (int) tickLabelMaxLength + GAP_BTW_MARK_LABEL + TICK_LENGTH; size.height = scale.getSize().height; } return size; } private static class MarkerProperties { private double value; private RGB color; /** * @param value * @param color */ public MarkerProperties(double value, RGB color) { this.value = value; this.color = color; } } }