/**
* 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.HashMap;
import java.util.Map;
import org.jplot2d.element.impl.PlotEx;
import org.jplot2d.util.DoubleDimension2D;
import org.jplot2d.util.SparseDoubleArray;
/**
* Subplots are placed side-bye-side. The plot space are distributed to subplots according to ratio of their
* preferedContentSize.
*
* @author Jingjing Li
*
*/
public class GridLayoutDirector extends SimpleLayoutDirector {
private final double hgap;
private final double vgap;
private Map plotsPreferredContentsGeomMap = new HashMap();
private Map plotsMarginGeomMap = new HashMap();
protected static Map getSubplotAxisMap(PlotEx[] subplots) {
Map glaMap = new HashMap();
/*
* Gather metrics for every axis. Iterate over grid to ensure the axes' z-order.
*/
for (PlotEx subplot : subplots) {
AxesInPlot ais = getAllAxes(subplot);
glaMap.put(subplot, ais);
}
return glaMap;
}
/**
* Create a GridLayoutDirector with 0 horizontal gap and 0 vertical gap.
*/
public GridLayoutDirector() {
this(0, 0);
}
/**
* Create a GridLayoutDirector with the given horizontal gap and vertical gap.
*
* @param hgap
* the horizontal gap
* @param vgap
* the vertical gap
*/
public GridLayoutDirector(double hgap, double vgap) {
this.hgap = hgap;
this.vgap = vgap;
}
public double getHGap() {
return hgap;
}
public double getVGap() {
return vgap;
}
public void invalidateLayout(PlotEx plot) {
plotsPreferredContentsGeomMap.remove(plot);
plotsMarginGeomMap.remove(plot);
}
public void layout(PlotEx plot) {
super.layout(plot);
GridCellGeom contGeom = getSubplotsPreferredContentsGeom(plot);
GridCellInsets marginGeom = getSubplotsMarginGeom(plot);
// calculate contents size factor of subplots.
Dimension2D scsFactor = calcSubplotContentFactor(plot, marginGeom);
SparseDoubleArray cellWidthMap = new SparseDoubleArray();
SparseDoubleArray cellHeightMap = new SparseDoubleArray();
for (PlotEx sp : plot.getSubplots()) {
GridConstraint grid = (GridConstraint) getConstraint(sp);
int col = (grid == null) ? 0 : grid.getGridX();
int row = (grid == null) ? 0 : grid.getGridY();
double contWidth = scsFactor.getWidth() * contGeom.getWidth(col);
double contHeight = scsFactor.getHeight() * contGeom.getHeight(row);
/*
* impose viewport constraint on its children.
*/
sp.setContentConstrant(new DoubleDimension2D(contWidth, contHeight));
double cw = marginGeom.getLeft(col) + contWidth + marginGeom.getRight(col);
double ch = marginGeom.getTop(row) + contHeight + marginGeom.getBottom(row);
if (cellWidthMap.get(col, -1) < cw) {
cellWidthMap.put(col, cw);
}
if (cellHeightMap.get(row, -1) < ch) {
cellHeightMap.put(row, ch);
}
}
GridCellGeom cellGeom = new GridCellGeom(cellWidthMap, cellHeightMap);
for (PlotEx sp : plot.getSubplots()) {
GridConstraint grid = (GridConstraint) getConstraint(sp);
int col = (grid == null) ? 0 : grid.getGridX();
int row = (grid == null) ? 0 : grid.getGridY();
// the paper bottom-left of a grid in chart(root layer)
double cws = cellGeom.getSumWidthLeft(col);
double chs = cellGeom.getSumHeightBelow(row);
double pX = cws + marginGeom.getLeft(col) + cellWidthMap.indexOfKey(col) * hgap;
double pY = chs + marginGeom.getBottom(row) + cellHeightMap.indexOfKey(row) * vgap;
sp.setLocation(pX, pY);
}
}
/**
* calculate cell size by contents size, grid size and gap.
*
* @param ctsSize
* @param gridSize
* @param padding
* @param hgap
* @param vgap
* @return contents size factor
*/
private Dimension2D calcSubplotContentFactor(PlotEx subplot, GridCellInsets padding) {
double ctsWidth = subplot.getContentSize().getWidth();
double ctsHeight = subplot.getContentSize().getHeight();
GridCellGeom contGeom = getSubplotsPreferredContentsGeom(subplot);
double sumWeightX = contGeom.getSumWidth();
double sumWeightY = contGeom.getSumHeight();
double xn = contGeom.getColNum();
double yn = contGeom.getRowNum();
double sumXpad = padding.getSumWidth();
double sumYpad = padding.getSumHeight();
double xfactor, yfactor;
if (xn == 0 || yn == 0) {
xfactor = ctsWidth;
yfactor = ctsHeight;
} else {
xfactor = (ctsWidth - sumXpad - hgap * (xn - 1)) / sumWeightX;
yfactor = (ctsHeight - sumYpad - vgap * (yn - 1)) / sumWeightY;
}
return new DoubleDimension2D(xfactor, yfactor);
}
public Dimension2D getPreferredContentSize(PlotEx plot) {
GridCellGeom contentGeom = getSubplotsPreferredContentsGeom(plot);
GridCellInsets marginGeom = getSubplotsMarginGeom(plot);
SparseDoubleArray colWidthMap = new SparseDoubleArray();
SparseDoubleArray rowHeightMap = new SparseDoubleArray();
for (PlotEx sp : plot.getSubplots()) {
GridConstraint grid = (GridConstraint) getConstraint(sp);
int col = (grid == null) ? 0 : grid.getGridX();
int row = (grid == null) ? 0 : grid.getGridY();
double width = contentGeom.getWidth(col) + marginGeom.getLeft(col) + marginGeom.getRight(col);
double Height = contentGeom.getHeight(row) + marginGeom.getTop(row) + marginGeom.getBottom(row);
if (colWidthMap.get(col, -1) < width) {
colWidthMap.put(col, width);
}
if (rowHeightMap.get(row, -1) < Height) {
rowHeightMap.put(row, Height);
}
}
GridCellGeom geom = new GridCellGeom(colWidthMap, rowHeightMap);
double width = geom.getSumWidth() + hgap * (colWidthMap.size() - 1);
double height = geom.getSumHeight() + vgap * (rowHeightMap.size() - 1);
Dimension2D spcs = plot.getPreferredContentSize();
if (spcs != null && width < spcs.getWidth()) {
width = spcs.getWidth();
}
if (spcs != null && height < spcs.getHeight()) {
height = spcs.getHeight();
}
return new DoubleDimension2D(width, height);
}
/**
* Returns row width and column height of the subplots of the given plot.
*
* @param plot
* @return
*/
private GridCellGeom getSubplotsPreferredContentsGeom(PlotEx plot) {
if (plotsPreferredContentsGeomMap.containsKey(plot)) {
return plotsPreferredContentsGeomMap.get(plot);
}
SparseDoubleArray colWidthMap = new SparseDoubleArray();
SparseDoubleArray rowHeightMap = new SparseDoubleArray();
for (PlotEx sp : plot.getSubplots()) {
GridConstraint grid = (GridConstraint) getConstraint(sp);
int col = (grid == null) ? 0 : grid.getGridX();
int row = (grid == null) ? 0 : grid.getGridY();
double width = 0;
double Height = 0;
Dimension2D contentSize = sp.getLayoutDirector().getPreferredContentSize(sp);
if (contentSize != null) {
width = contentSize.getWidth();
Height = contentSize.getHeight();
}
if (colWidthMap.get(col, -1) < width) {
colWidthMap.put(col, width);
}
if (rowHeightMap.get(row, -1) < Height) {
rowHeightMap.put(row, Height);
}
}
GridCellGeom geom = new GridCellGeom(colWidthMap, rowHeightMap);
plotsPreferredContentsGeomMap.put(plot, geom);
return geom;
}
/**
* calculate the margin (from grid bounds to data area bounds) for every row and columns of subplots in the given
* plot.
*
* @return the margin
*/
private GridCellInsets getSubplotsMarginGeom(PlotEx plot) {
if (plotsMarginGeomMap.containsKey(plot)) {
return plotsMarginGeomMap.get(plot);
}
Map saMap = getSubplotAxisMap(plot.getSubplots());
SparseDoubleArray topMargin = new SparseDoubleArray();
SparseDoubleArray leftMargin = new SparseDoubleArray();
SparseDoubleArray bottomMargin = new SparseDoubleArray();
SparseDoubleArray rightMargin = new SparseDoubleArray();
for (Map.Entry me : saMap.entrySet()) {
PlotEx sp = me.getKey();
AxesInPlot ais = me.getValue();
GridConstraint grid = (GridConstraint) getConstraint(sp);
int col = (grid == null) ? 0 : grid.getGridX();
int row = (grid == null) ? 0 : grid.getGridY();
double mLeft = calcLeftMargin(sp, ais.leftAxes);
double mRight = calcRightMargin(sp, ais.rightAxes);
double mTop = calcTopMargin(sp, ais.topAxes);
double mBottom = calcBottomMargin(sp, ais.bottomAxes);
if (leftMargin.get(col, -1) < mLeft) {
leftMargin.put(col, mLeft);
}
if (rightMargin.get(col, -1) < mRight) {
rightMargin.put(col, mRight);
}
if (topMargin.get(row, -1) < mTop) {
topMargin.put(row, mTop);
}
if (bottomMargin.get(row, -1) < mBottom) {
bottomMargin.put(row, mBottom);
}
}
GridCellInsets insets = new GridCellInsets(topMargin, leftMargin, bottomMargin, rightMargin);
plotsMarginGeomMap.put(plot, insets);
return insets;
}
}
Ads help maintain this website.