/**
* Copyright 2010-2014 Jingjing Li.
*
* This file is part of jplot2d.
*
* jplot2d is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or any later version.
*
* jplot2d is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with jplot2d. If not, see .
*/
package org.jplot2d.layout;
import java.awt.geom.Dimension2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.jplot2d.element.AxisPosition;
import org.jplot2d.element.HAlign;
import org.jplot2d.element.VAlign;
import org.jplot2d.element.impl.AxisEx;
import org.jplot2d.element.impl.LegendEx;
import org.jplot2d.element.impl.PlotEx;
import org.jplot2d.element.impl.PlotMarginEx;
import org.jplot2d.element.impl.TitleEx;
import org.jplot2d.util.DoubleDimension2D;
import org.jplot2d.util.Insets2D;
/**
* This LayoutDirector only layout layers, all subplot are not considered.
*
* @author Jingjing Li
*
*/
public class SimpleLayoutDirector implements LayoutDirector {
/**
* All Axes in a plot grouped by position.
*/
public static class AxesInPlot {
final ArrayList leftAxes = new ArrayList();
final ArrayList rightAxes = new ArrayList();
final ArrayList topAxes = new ArrayList();
final ArrayList bottomAxes = new ArrayList();
}
static double LEGEND_GAP = 8.0;
/** The layout constraints */
private Map constraints = new HashMap();
public Object getConstraint(PlotEx plot) {
return constraints.get(plot);
}
public void remove(PlotEx plot) {
constraints.remove(plot);
}
public void setConstraint(PlotEx plot, Object constraint) {
constraints.put(plot, constraint);
}
public void invalidateLayout(PlotEx plot) {
// nothing to do
}
public void layout(PlotEx plot) {
AxesInPlot ais = getAllAxes(plot);
Insets2D margin = calcMargin(plot, ais);
double contentWidth, contentHeight;
if (plot.getContentConstrant() != null) {
contentWidth = plot.getContentConstrant().getWidth();
contentHeight = plot.getContentConstrant().getHeight();
} else {
contentWidth = plot.getSize().getWidth() - margin.getLeft() - margin.getRight();
contentHeight = plot.getSize().getHeight() - margin.getTop() - margin.getBottom();
}
if (contentWidth < 0) {
contentWidth = 0;
}
if (contentHeight < 0) {
contentHeight = 0;
}
if (plot.getContentConstrant() != null) {
double width = contentWidth + margin.getLeft() + margin.getRight();
double height = contentHeight + margin.getTop() + margin.getBottom();
plot.setSize(width, height);
}
Dimension2D contentSize = new DoubleDimension2D(contentWidth, contentHeight);
plot.setContentSize(contentSize);
layoutLeftMargin(plot, contentSize, ais.leftAxes);
layoutRightMargin(plot, contentSize, ais.rightAxes);
layoutTopMargin(plot, contentSize, ais.topAxes);
layoutBottomMargin(plot, contentSize, ais.bottomAxes);
}
/**
* Return all visible axes on left, right, top, bottom margins.
*
* @param plot
* @return
*/
protected static AxesInPlot getAllAxes(PlotEx plot) {
AxesInPlot ais = new AxesInPlot();
for (AxisEx axis : plot.getXAxes()) {
if (axis.isVisible() && axis.canContribute()) {
if (axis.getPosition() == AxisPosition.POSITIVE_SIDE) {
ais.topAxes.add(axis);
} else {
ais.bottomAxes.add(axis);
}
}
}
for (AxisEx axis : plot.getYAxes()) {
if (axis.isVisible() && axis.canContribute()) {
if (axis.getPosition() == AxisPosition.POSITIVE_SIDE) {
ais.rightAxes.add(axis);
} else {
ais.leftAxes.add(axis);
}
}
}
return ais;
}
protected static double calcLeftMargin(PlotEx plot, ArrayList leftAxes) {
PlotMarginEx margin = plot.getMargin();
if (!margin.isAutoLeft()) {
return margin.getLeft() + margin.getExtraLeft();
}
double mLeft = 0;
if (leftAxes.size() > 0) {
for (AxisEx am : leftAxes) {
mLeft += am.getAsc() + am.getDesc();
}
mLeft -= leftAxes.get(0).getDesc();
}
LegendEx legend = plot.getLegend();
if (legend.isVisible() && legend.canContribute()) {
switch (legend.getPosition()) {
case LEFTTOP:
case LEFTMIDDLE:
case LEFTBOTTOM: {
mLeft += LEGEND_GAP + legend.getSize().getWidth();
break;
}
}
}
plot.getMargin().directLeft(mLeft);
return mLeft + margin.getExtraLeft();
}
protected static double calcRightMargin(PlotEx plot, ArrayList rightAxes) {
PlotMarginEx margin = plot.getMargin();
if (!margin.isAutoRight()) {
return margin.getRight() + margin.getExtraRight();
}
double mRight = 0;
if (rightAxes.size() > 0) {
for (AxisEx am : rightAxes) {
mRight += am.getAsc() + am.getDesc();
}
mRight -= rightAxes.get(0).getAsc();
}
LegendEx legend = plot.getLegend();
if (legend.isVisible() && legend.canContribute()) {
switch (legend.getPosition()) {
case RIGHTTOP:
case RIGHTMIDDLE:
case RIGHTBOTTOM: {
mRight += LEGEND_GAP + legend.getSize().getWidth();
break;
}
}
}
plot.getMargin().directRight(mRight);
return mRight + margin.getExtraRight();
}
protected static double calcTopMargin(PlotEx plot, ArrayList topAxes) {
PlotMarginEx margin = plot.getMargin();
if (!margin.isAutoTop()) {
return margin.getTop() + margin.getExtraTop();
}
double mTop = 0;
if (topAxes.size() > 0) {
for (AxisEx am : topAxes) {
mTop += am.getAsc() + am.getDesc();
}
mTop -= topAxes.get(0).getDesc();
}
LegendEx legend = plot.getLegend();
if (legend.isVisible() && legend.canContribute()) {
switch (legend.getPosition()) {
case TOPLEFT:
case TOPCENTER:
case TOPRIGHT: {
mTop += LEGEND_GAP + legend.getSize().getHeight();
break;
}
}
}
for (TitleEx title : plot.getTitles()) {
if (title.isVisible() && title.canContribute()) {
double titleHeight = title.getSize().getHeight();
switch (title.getPosition()) {
case TOPLEFT:
case TOPCENTER:
case TOPRIGHT: {
mTop += (1 + title.getGapFactor()) * titleHeight;
break;
}
}
}
}
plot.getMargin().directTop(mTop);
return mTop + margin.getExtraTop();
}
protected static double calcBottomMargin(PlotEx plot, ArrayList bottomAxes) {
PlotMarginEx margin = plot.getMargin();
if (!margin.isAutoBottom()) {
return margin.getBottom() + margin.getExtraBottom();
}
double mBottom = 0;
if (bottomAxes.size() > 0) {
for (AxisEx am : bottomAxes) {
mBottom += am.getAsc() + am.getDesc();
}
mBottom -= bottomAxes.get(0).getAsc();
}
LegendEx legend = plot.getLegend();
if (legend.isVisible() && legend.canContribute()) {
switch (legend.getPosition()) {
case BOTTOMLEFT:
case BOTTOMCENTER:
case BOTTOMRIGHT: {
mBottom += LEGEND_GAP + legend.getSize().getHeight();
break;
}
}
}
for (TitleEx title : plot.getTitles()) {
if (title.isVisible() && title.canContribute()) {
double titleHeight = title.getSize().getHeight();
switch (title.getPosition()) {
case BOTTOMLEFT:
case BOTTOMCENTER:
case BOTTOMRIGHT: {
mBottom += (1 + title.getGapFactor()) * titleHeight;
break;
}
}
}
}
plot.getMargin().directBottom(mBottom);
return mBottom + margin.getExtraBottom();
}
/**
* Calculate the margin of the given plot. The legend size can be calculated by pre-setting its length constraint.
*
* @param plot
* @param ais
* @return
*/
private static Insets2D calcMargin(PlotEx plot, AxesInPlot ais) {
double mLeft, mRight, mTop, mBottom;
mTop = calcTopMargin(plot, ais.topAxes);
mBottom = calcBottomMargin(plot, ais.bottomAxes);
mLeft = calcLeftMargin(plot, ais.leftAxes);
mRight = calcRightMargin(plot, ais.rightAxes);
return new Insets2D.Double(mTop, mLeft, mBottom, mRight);
}
private static void layoutLeftMargin(PlotEx sp, Dimension2D contentSize, ArrayList leftAxes) {
// viewport box
double iabLeft = 0;
double iabBottom = 0;
double xloc = iabLeft;
/* locate axes */
if (leftAxes.size() > 0) {
AxisEx am = leftAxes.get(0);
am.setLength(contentSize.getHeight());
am.setLocation(xloc, iabBottom);
xloc -= am.getAsc();
for (int i = 1; i < leftAxes.size(); i++) {
am = leftAxes.get(i);
am.setLength(contentSize.getHeight());
xloc -= am.getDesc();
am.setLocation(xloc, iabBottom);
xloc -= am.getAsc();
}
}
LegendEx legend = sp.getLegend();
/* locate legend */
if (legend.isVisible() && legend.canContribute()) {
switch (legend.getPosition()) {
case LEFTTOP:
xloc -= LEGEND_GAP;
legend.directLocation(xloc, contentSize.getHeight());
legend.setHAlign(HAlign.RIGHT);
legend.setVAlign(VAlign.TOP);
break;
case LEFTMIDDLE:
xloc -= LEGEND_GAP;
legend.directLocation(xloc, contentSize.getHeight() / 2);
legend.setHAlign(HAlign.RIGHT);
legend.setVAlign(VAlign.MIDDLE);
break;
case LEFTBOTTOM:
xloc -= LEGEND_GAP;
legend.directLocation(xloc, 0);
legend.setHAlign(HAlign.RIGHT);
legend.setVAlign(VAlign.BOTTOM);
break;
}
}
}
private static void layoutRightMargin(PlotEx sp, Dimension2D contentSize, ArrayList rightAxes) {
// viewport box
double iabRight = contentSize.getWidth();
double iabBottom = 0;
double xloc = iabRight;
/* locate axes */
if (rightAxes.size() > 0) {
AxisEx am = rightAxes.get(0);
am.setLength(contentSize.getHeight());
am.setLocation(xloc, iabBottom);
xloc += am.getDesc();
for (int i = 1; i < rightAxes.size(); i++) {
am = rightAxes.get(i);
am.setLength(contentSize.getHeight());
xloc += am.getAsc();
am.setLocation(xloc, iabBottom);
xloc += am.getDesc();
}
}
/* locate legend */
LegendEx legend = sp.getLegend();
if (legend.isVisible() && legend.canContribute()) {
switch (legend.getPosition()) {
case RIGHTTOP:
xloc += LEGEND_GAP;
legend.directLocation(xloc, contentSize.getHeight());
legend.setHAlign(HAlign.LEFT);
legend.setVAlign(VAlign.TOP);
break;
case RIGHTMIDDLE:
xloc += LEGEND_GAP;
legend.directLocation(xloc, contentSize.getHeight() / 2);
legend.setHAlign(HAlign.LEFT);
legend.setVAlign(VAlign.MIDDLE);
break;
case RIGHTBOTTOM:
xloc += LEGEND_GAP;
legend.directLocation(xloc, 0);
legend.setHAlign(HAlign.LEFT);
legend.setVAlign(VAlign.BOTTOM);
break;
}
}
}
private static void layoutTopMargin(PlotEx sp, Dimension2D contentSize, ArrayList topAxes) {
// viewport box
double iabLeft = 0;
double iabTop = contentSize.getHeight();
double yloc = iabTop;
// locate axes
if (topAxes.size() > 0) {
AxisEx am = topAxes.get(0);
am.setLength(contentSize.getWidth());
am.setLocation(iabLeft, yloc);
yloc += am.getAsc();
for (int i = 1; i < topAxes.size(); i++) {
am = topAxes.get(i);
am.setLength(contentSize.getWidth());
yloc += am.getDesc();
am.setLocation(iabLeft, yloc);
yloc += am.getAsc();
}
}
// locate legend
LegendEx legend = sp.getLegend();
if (legend.isVisible() && legend.canContribute()) {
switch (legend.getPosition()) {
case TOPLEFT:
yloc += LEGEND_GAP;
legend.directLocation(0, yloc);
legend.setHAlign(HAlign.LEFT);
legend.setVAlign(VAlign.BOTTOM);
yloc += legend.getSize().getHeight();
break;
case TOPCENTER:
yloc += LEGEND_GAP;
legend.directLocation(contentSize.getWidth() / 2, yloc);
legend.setHAlign(HAlign.CENTER);
legend.setVAlign(VAlign.BOTTOM);
yloc += legend.getSize().getHeight();
break;
case TOPRIGHT:
yloc += LEGEND_GAP;
legend.directLocation(contentSize.getWidth(), yloc);
legend.setHAlign(HAlign.RIGHT);
legend.setVAlign(VAlign.BOTTOM);
yloc += legend.getSize().getHeight();
break;
}
}
// locate titles
TitleEx[] titles = sp.getTitles();
for (int i = titles.length - 1; i >= 0; i--) {
TitleEx title = titles[i];
if (title.isVisible() && title.canContribute()) {
double titleHeight = title.getSize().getHeight();
switch (title.getPosition()) {
case TOPLEFT:
yloc += title.getGapFactor() * titleHeight;
title.setLocation(0, yloc);
title.setHAlign(HAlign.LEFT);
title.setVAlign(VAlign.BOTTOM);
yloc += titleHeight;
break;
case TOPCENTER:
yloc += title.getGapFactor() * titleHeight;
title.setLocation(contentSize.getWidth() / 2, yloc);
title.setHAlign(HAlign.CENTER);
title.setVAlign(VAlign.BOTTOM);
yloc += titleHeight;
break;
case TOPRIGHT: {
yloc += title.getGapFactor() * titleHeight;
title.setLocation(contentSize.getWidth(), yloc);
title.setHAlign(HAlign.RIGHT);
title.setVAlign(VAlign.BOTTOM);
yloc += titleHeight;
break;
}
}
}
}
}
private static void layoutBottomMargin(PlotEx sp, Dimension2D contentSize, ArrayList bottomAxes) {
// viewport box
double iabLeft = 0;
double iabBottom = 0;
double yloc = iabBottom;
// locate axes
if (bottomAxes.size() > 0) {
AxisEx am = bottomAxes.get(0);
am.setLength(contentSize.getWidth());
am.setLocation(iabLeft, yloc);
yloc -= am.getDesc();
for (int i = 1; i < bottomAxes.size(); i++) {
am = bottomAxes.get(i);
am.setLength(contentSize.getWidth());
yloc -= am.getAsc();
am.setLocation(iabLeft, yloc);
yloc -= am.getDesc();
}
}
// locate legend
LegendEx legend = sp.getLegend();
if (legend.isVisible() && legend.canContribute()) {
switch (legend.getPosition()) {
case BOTTOMLEFT:
yloc -= LEGEND_GAP;
legend.directLocation(0, yloc);
legend.setHAlign(HAlign.LEFT);
legend.setVAlign(VAlign.TOP);
yloc -= legend.getSize().getHeight();
break;
case BOTTOMCENTER:
yloc -= LEGEND_GAP;
legend.directLocation(contentSize.getWidth() / 2, yloc);
legend.setHAlign(HAlign.CENTER);
legend.setVAlign(VAlign.TOP);
yloc -= legend.getSize().getHeight();
break;
case BOTTOMRIGHT:
yloc -= LEGEND_GAP;
legend.directLocation(contentSize.getWidth(), yloc);
legend.setHAlign(HAlign.RIGHT);
legend.setVAlign(VAlign.TOP);
yloc -= legend.getSize().getHeight();
break;
}
}
// locate titles
for (TitleEx title : sp.getTitles()) {
if (title.isVisible() && title.canContribute()) {
double titleHeight = title.getSize().getHeight();
switch (title.getPosition()) {
case BOTTOMLEFT:
yloc -= title.getGapFactor() * titleHeight;
title.setLocation(0, yloc);
title.setHAlign(HAlign.LEFT);
title.setVAlign(VAlign.TOP);
yloc -= titleHeight;
break;
case BOTTOMCENTER:
yloc -= title.getGapFactor() * titleHeight;
title.setLocation(contentSize.getWidth() / 2, yloc);
title.setHAlign(HAlign.CENTER);
title.setVAlign(VAlign.TOP);
yloc -= titleHeight;
break;
case BOTTOMRIGHT: {
yloc -= title.getGapFactor() * titleHeight;
title.setLocation(contentSize.getWidth(), yloc);
title.setHAlign(HAlign.RIGHT);
title.setVAlign(VAlign.TOP);
yloc -= titleHeight;
break;
}
}
}
}
}
/**
* Calculate the preferred content size of the given plot. The default implementation returns the
* plot.getPreferredContentSize(), which can be override by subclass to consider nested subplots. The returned size
* may be null if there is no enough information to derive a value.
*
* @param plot
* @return the preferred content size
*/
public Dimension2D getPreferredContentSize(PlotEx plot) {
return plot.getPreferredContentSize();
}
public Dimension2D getPreferredSize(PlotEx plot) {
Dimension2D prefContSize = getPreferredContentSize(plot);
if (prefContSize == null) {
return null;
} else {
AxesInPlot ais = getAllAxes(plot);
Insets2D margin = calcMargin(plot, ais);
double w = prefContSize.getWidth() + margin.getLeft() + margin.getRight();
double h = prefContSize.getHeight() + margin.getTop() + margin.getBottom();
return new DoubleDimension2D(w, h);
}
}
public String toString() {
return this.getClass().getSimpleName();
}
}
Ads help maintain this website.