package com.revolsys.swing.map.layer.record.style.marker;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.Map;
import javax.measure.Measure;
import javax.measure.quantity.Length;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import com.revolsys.awt.CloseableAffineTransform;
import com.revolsys.collection.map.MapEx;
import com.revolsys.io.BaseCloseable;
import com.revolsys.swing.map.Viewport2D;
import com.revolsys.swing.map.layer.record.style.MarkerStyle;
public class TextMarker extends AbstractMarker {
private String text = "?";
private Font font;
private String textFaceName = "san-serif";
public TextMarker(final Map<String, Object> properties) {
setProperties(properties);
}
public TextMarker(final String textFaceName, final String text) {
this.textFaceName = textFaceName;
this.text = text;
}
@Override
public boolean equals(final Object object) {
if (object instanceof TextMarker) {
final TextMarker marker = (TextMarker)object;
if (getText().equals(marker.getText())) {
return getFont().equals(marker.getFont());
}
}
return false;
}
public Font getFont() {
return this.font;
}
public String getText() {
return this.text;
}
public String getTextFaceName() {
return this.textFaceName;
}
@Override
public int hashCode() {
return getText().hashCode();
}
@Override
public Icon newIcon(final MarkerStyle style) {
Icon icon;
final BufferedImage image = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
final Graphics2D graphics = image.createGraphics();
double orientation = style.getMarkerOrientation();
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
final String textFaceName = getTextFaceName();
final Font font = new Font(textFaceName, 0, 14);
graphics.setFont(font);
final FontMetrics fontMetrics = graphics.getFontMetrics();
int x = 0;
int y = 15;
final String text = getText();
final Rectangle2D bounds = fontMetrics.getStringBounds(text, graphics);
final double width = bounds.getWidth();
final double height = fontMetrics.getAscent();
final String horizontalAlignment = style.getMarkerHorizontalAlignment();
if ("right".equals(horizontalAlignment)) {
x = 15 - (int)width;
} else if ("center".equals(horizontalAlignment) || "auto".equals(horizontalAlignment)) {
x = 8 - (int)(width / 2);
}
final String verticalAlignment = style.getMarkerVerticalAlignment();
if ("top".equals(verticalAlignment)) {
y = (int)height;
} else if ("middle".equals(verticalAlignment) || "auto".equals(verticalAlignment)) {
y = 7 + (int)(height / 2);
}
if (orientation != 0) {
if (orientation > 270) {
orientation -= 360;
}
graphics.rotate(-Math.toRadians(orientation), 8, 8);
}
graphics.setColor(style.getMarkerFill());
graphics.drawString(text, x, y);
graphics.dispose();
icon = new ImageIcon(image);
return icon;
}
@Override
public void render(final Viewport2D viewport, final Graphics2D graphics, final MarkerStyle style,
final double modelX, final double modelY, double orientation) {
try (
BaseCloseable transformCloseable = new CloseableAffineTransform(graphics)) {
Viewport2D.setUseModelCoordinates(viewport, graphics, false);
final Measure<Length> markerHeight = style.getMarkerHeight();
final double mapHeight = Viewport2D.toDisplayValue(viewport, markerHeight);
final String orientationType = style.getMarkerOrientationType();
if ("none".equals(orientationType)) {
orientation = 0;
}
final int fontSize = (int)mapHeight;
if (this.font == null || this.font.getSize() != fontSize) {
this.font = new Font(this.textFaceName, 0, fontSize);
}
final FontRenderContext fontRenderContext = graphics.getFontRenderContext();
final GlyphVector glyphVector = this.font.createGlyphVector(fontRenderContext, this.text);
final Shape shape = glyphVector.getOutline();
final GeneralPath newShape = new GeneralPath(shape);
final Rectangle2D bounds = newShape.getBounds2D();
final double shapeWidth = bounds.getWidth();
final double shapeHeight = bounds.getHeight();
Viewport2D.translateModelToViewCoordinates(viewport, graphics, modelX, modelY);
final double markerOrientation = style.getMarkerOrientation();
orientation = -orientation + markerOrientation;
if (orientation != 0) {
graphics.rotate(Math.toRadians(orientation));
}
final Measure<Length> deltaX = style.getMarkerDx();
final Measure<Length> deltaY = style.getMarkerDy();
double dx = Viewport2D.toDisplayValue(viewport, deltaX);
double dy = Viewport2D.toDisplayValue(viewport, deltaY);
dy -= bounds.getY();
final String verticalAlignment = style.getMarkerVerticalAlignment();
if ("bottom".equals(verticalAlignment)) {
dy -= shapeHeight;
} else if ("auto".equals(verticalAlignment) || "middle".equals(verticalAlignment)) {
dy -= shapeHeight / 2.0;
}
final String horizontalAlignment = style.getMarkerHorizontalAlignment();
if ("right".equals(horizontalAlignment)) {
dx -= shapeWidth;
} else if ("auto".equals(horizontalAlignment) || "center".equals(horizontalAlignment)) {
dx -= shapeWidth / 2;
}
graphics.translate(dx, dy);
if (style.setMarkerFillStyle(viewport, graphics)) {
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
graphics.setFont(this.font);
graphics.drawString(this.text, 0, 0);
}
}
}
public void setText(final String text) {
final Object oldValue = this.text;
this.text = MarkerStyle.getWithDefault(text, "?");
this.font = null;
firePropertyChange("text", oldValue, this.text);
}
public void setTextFaceName(final String textFaceName) {
final Object oldValue = this.textFaceName;
this.textFaceName = textFaceName;
this.font = null;
firePropertyChange("textFaceName", oldValue, this.textFaceName);
}
@Override
public MapEx toMap() {
final MapEx map = super.toMap();
addTypeToMap(map, "markerText");
addToMap(map, "textFaceName", this.textFaceName);
addToMap(map, "text", this.text);
return map;
}
@Override
public String toString() {
return getText();
}
}