/*******************************************************************************
* 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;
}
}
}