/*
* Apache License
* Version 2.0, January 2004
* http://www.apache.org/licenses/
*
* Copyright 2013 Aurelian Tutuianu
* Copyright 2014 Aurelian Tutuianu
* Copyright 2015 Aurelian Tutuianu
* Copyright 2016 Aurelian Tutuianu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package rapaio.graphics.base;
import rapaio.graphics.opt.ColorPalette;
import java.awt.*;
import java.util.ArrayList;
/**
* @author <a href="mailto:padreati@yahoo.com>Aurelian Tutuianu</a>
*/
public abstract class HostFigure extends BaseFigure {
private static final long serialVersionUID = 8198529442678989416L;
protected static final Font TITLE_FONT = new Font("Verdana", Font.BOLD, 18);
protected static final Font MARKERS_FONT = new Font("Verdana", Font.PLAIN, 13);
protected static final Font LABELS_FONT = new Font("Verdana", Font.BOLD, 16);
protected static final double DEFAULT_THICKER_MIN_SPACE = 110.;
protected static final int THICKER_PAD = 7;
protected static final int MARKER_PAD = 15;
protected static final int LABEL_PAD = 30;
protected static final int TITLE_PAD = 40;
protected static final int MINIMUM_PAD = 20;
//
protected Rectangle viewport;
//
protected String title;
protected String yLabel;
protected String xLabel;
protected double thickerMinSpace = DEFAULT_THICKER_MIN_SPACE;
//
protected boolean leftThicker;
protected boolean bottomThicker;
protected boolean leftMarkers;
protected boolean bottomMarkers;
protected final ArrayList<String> bottomMarkersMsg = new ArrayList<>();
protected final ArrayList<Double> bottomMarkersPos = new ArrayList<>();
protected final ArrayList<String> leftMarkersMsg = new ArrayList<>();
protected final ArrayList<Double> leftMarkersPos = new ArrayList<>();
//
protected double x1 = Double.NaN;
protected double x2 = Double.NaN;
protected double y1 = Double.NaN;
protected double y2 = Double.NaN;
public HostFigure xLim(double start, double end) {
this.x1 = start;
this.x2 = end;
return this;
}
public HostFigure yLim(double start, double end) {
this.y1 = start;
this.y2 = end;
return this;
}
protected double getXRangeStart() {
return x1;
}
protected double getXRangeEnd() {
return x2;
}
protected double getYRangeStart() {
return y1;
}
protected double getYRangeEnd() {
return y2;
}
protected int sizeLeftThicker;
protected int sizeBottomThicker;
protected int sizeLeftMarkers;
protected int sizeBottomMarkers;
protected int sizeTitle;
protected int sizeYLabel;
protected int sizeXLabel;
protected void buildViewport(Rectangle rectangle) {
viewport = new Rectangle(rectangle);
viewport.x += MINIMUM_PAD;
viewport.width -= 2 * MINIMUM_PAD;
viewport.y += MINIMUM_PAD;
viewport.height -= 2 * MINIMUM_PAD;
if (leftThicker) {
sizeLeftThicker = 2 * THICKER_PAD;
}
if (leftMarkers) {
sizeLeftMarkers = MARKER_PAD;
}
if (yLabel != null) {
sizeYLabel = LABEL_PAD;
}
if (title != null) {
sizeTitle = TITLE_PAD;
}
if (bottomThicker) {
sizeBottomThicker = 2 * THICKER_PAD;
}
if (bottomMarkers) {
sizeBottomMarkers = MARKER_PAD;
}
if (xLabel != null) {
sizeXLabel = LABEL_PAD;
}
viewport.x += sizeLeftThicker;
viewport.width -= sizeLeftThicker;
viewport.x += sizeLeftMarkers;
viewport.width -= sizeLeftMarkers;
viewport.x += sizeYLabel;
viewport.width -= sizeYLabel;
viewport.y += sizeTitle;
viewport.height -= sizeTitle;
viewport.height -= sizeBottomThicker;
viewport.height -= sizeBottomMarkers;
viewport.height -= sizeXLabel;
}
public double xScale(double x) {
return viewport.x + viewport.width * (x - getRange().x1()) / (getRange().x2() - getRange().x1());
}
public double yScale(double y) {
return viewport.y + viewport.height * (1. - (y - getRange().y1()) / (getRange().y2() - getRange().y1()));
}
protected Rectangle getViewport() {
return viewport;
}
public HostFigure leftThick(boolean leftThicker) {
this.leftThicker = leftThicker;
return this;
}
public HostFigure bottomThick(boolean bottomThicker) {
this.bottomThicker = bottomThicker;
return this;
}
public HostFigure leftMarkers(boolean leftMarkers) {
this.leftMarkers = leftMarkers;
return this;
}
public HostFigure bottomMarkers(boolean bottomMarkers) {
this.bottomMarkers = bottomMarkers;
return this;
}
public HostFigure thickMinSpace(double minSpace) {
thickerMinSpace = minSpace;
return this;
}
public HostFigure title(String title) {
this.title = title;
return this;
}
public HostFigure yLab(String yLabel) {
this.yLabel = yLabel;
return this;
}
public HostFigure xLab(String xLabel) {
this.xLabel = xLabel;
return this;
}
@Override
public void paint(Graphics2D g2d, Rectangle rect) {
buildViewport(rect);
setRange(buildRange());
g2d.setColor(ColorPalette.STANDARD.getColor(255));
g2d.fill(rect);
g2d.setBackground(ColorPalette.STANDARD.getColor(255));
g2d.setColor(ColorPalette.STANDARD.getColor(0));
if (title != null) {
g2d.setFont(TITLE_FONT);
double titleWidth = g2d.getFontMetrics().getStringBounds(title, g2d).getWidth();
g2d.drawString(title, (int) (rect.x + (rect.width - titleWidth) / 2), rect.y + TITLE_PAD);
}
// left part
buildLeftMarkers();
g2d.setFont(MARKERS_FONT);
g2d.drawLine(viewport.x - THICKER_PAD,
viewport.y,
viewport.x - THICKER_PAD,
viewport.y + viewport.height);
for (int i = 0; i < leftMarkersPos.size(); i++) {
if (leftThicker) {
g2d.drawLine(
viewport.x - 2 * THICKER_PAD,
(int) (viewport.y + leftMarkersPos.get(i)),
viewport.x - THICKER_PAD,
(int) (viewport.y + leftMarkersPos.get(i)));
}
if (leftMarkers) {
int xx = viewport.x - 3 * THICKER_PAD;
int yy = (int) (viewport.y + viewport.height - leftMarkersPos.get(i)
+ g2d.getFontMetrics().getStringBounds(leftMarkersMsg.get(i), g2d).getWidth() / 2);
g2d.translate(xx, yy);
g2d.rotate(-Math.PI / 2);
g2d.drawString(leftMarkersMsg.get(i), 0, 0);
g2d.rotate(Math.PI / 2);
g2d.translate(-xx, -yy);
}
}
if (yLabel != null) {
g2d.setFont(LABELS_FONT);
double ywidth = g2d.getFontMetrics().getStringBounds(yLabel, g2d).getWidth();
int xx = viewport.x - 5 * THICKER_PAD - MARKER_PAD;
int yy = (int) (viewport.y + ywidth + (viewport.height - ywidth) / 2);
g2d.translate(xx, yy);
g2d.rotate(-Math.PI / 2);
g2d.drawString(yLabel, 0, 0);
g2d.rotate(Math.PI / 2);
g2d.translate(-xx, -yy);
}
// bottom part
buildBottomMarkers();
g2d.setFont(MARKERS_FONT);
g2d.drawLine(viewport.x,
viewport.y + viewport.height + THICKER_PAD,
viewport.x + viewport.width,
viewport.y + viewport.height + THICKER_PAD);
for (int i = 0; i < bottomMarkersPos.size(); i++) {
if (bottomThicker) {
g2d.drawLine(
(int) (viewport.x + bottomMarkersPos.get(i)),
viewport.y + viewport.height + THICKER_PAD,
(int) (viewport.x + bottomMarkersPos.get(i)),
viewport.y + viewport.height + 2 * THICKER_PAD);
}
if (bottomMarkers) {
g2d.drawString(
bottomMarkersMsg.get(i),
(int) (viewport.x + bottomMarkersPos.get(i)
- g2d.getFontMetrics().getStringBounds(bottomMarkersMsg.get(i), g2d).getWidth() / 2),
viewport.y + viewport.height + 2 * THICKER_PAD + MARKER_PAD
);
}
}
if (xLabel != null) {
g2d.setFont(LABELS_FONT);
double xwidth = g2d.getFontMetrics().getStringBounds(xLabel, g2d).getWidth();
g2d.drawString(xLabel,
(int) (viewport.x + (viewport.width - xwidth) / 2),
viewport.y + viewport.height + 2 * THICKER_PAD + MARKER_PAD + LABEL_PAD);
}
}
protected void buildNumericBottomMarkers() {
bottomMarkersPos.clear();
bottomMarkersMsg.clear();
int xspots = (int) Math.floor(viewport.width / thickerMinSpace);
if (xspots < 1) {
xspots = 1;
}
double xspotwidth = viewport.width / xspots;
for (int i = 0; i <= xspots; i++) {
bottomMarkersPos.add(i * xspotwidth);
bottomMarkersMsg.add(String.format("%." + getRange().getProperDecimalsX() + "f", getRange().x1() + getRange().width() * i / xspots));
}
}
protected void buildNumericLeftMarkers() {
leftMarkersPos.clear();
leftMarkersMsg.clear();
int yspots = (int) Math.floor(viewport.height / thickerMinSpace);
if (yspots < 1) {
yspots = 1;
}
double yspotwidth = viewport.height / yspots;
for (int i = 0; i <= yspots; i++) {
leftMarkersPos.add(i * yspotwidth);
leftMarkersMsg.add(String.format("%." + getRange().getProperDecimalsY() + "f", getRange().y1() + getRange().height() * i / yspots));
}
}
protected void buildLeftMarkers() {
}
protected void buildBottomMarkers() {
}
}